From 31f329c8d5792895b8aea993f75b203824f212d9 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 1 May 2026 11:16:04 +1000 Subject: [PATCH] lots of fixes to get this working in wasm --- .ignore | 2 - Test_Runner | Bin 2095192 -> 0 bytes alloc.d | 104 +- build.sh | 145 +- dlibincludes.c | 16 +- external.d | 101 + external/arsd-webassembly/core/arsd/aa.d | 1 - .../core/arsd/memory_allocation.d | 4 +- .../arsd-webassembly/core/arsd/objectutils.d | 4 +- .../arsd-webassembly/core/arsd/utf_decoding.d | 24 +- external/arsd-webassembly/core/demangle.d | 2376 +++++++++++++++++ .../arsd-webassembly/core/internal/cast_.d | 206 ++ .../arsd-webassembly/core/internal/lifetime.d | 31 + .../arsd-webassembly/core/internal/string.d | 53 + external/arsd-webassembly/core/lifetime.d | 73 + external/arsd-webassembly/core/stdc/string.d | 61 + external/arsd-webassembly/math/package.d | 10 + external/arsd-webassembly/object.d | 2021 +++++++++++--- external/arsd-webassembly/std/math/rounding.d | 8 + external/cglm/aabb2d.h | 270 -- external/cglm/affine-mat.h | 189 -- external/cglm/affine-post.h | 247 -- external/cglm/affine-pre.h | 304 --- external/cglm/affine.h | 238 -- external/cglm/affine2d-post.h | 132 - external/cglm/affine2d.h | 268 -- external/cglm/applesimd.h | 136 - external/cglm/bezier.h | 154 -- external/cglm/box.h | 281 -- external/cglm/call.h | 51 - external/cglm/call/aabb2d.h | 89 - external/cglm/call/affine.h | 167 -- external/cglm/call/affine2d.h | 67 - external/cglm/call/bezier.h | 31 - external/cglm/call/box.h | 78 - external/cglm/call/cam.h | 133 - external/cglm/call/clipspace/ortho_lh_no.h | 46 - external/cglm/call/clipspace/ortho_lh_zo.h | 46 - external/cglm/call/clipspace/ortho_rh_no.h | 46 - external/cglm/call/clipspace/ortho_rh_zo.h | 46 - external/cglm/call/clipspace/persp_lh_no.h | 87 - external/cglm/call/clipspace/persp_lh_zo.h | 87 - external/cglm/call/clipspace/persp_rh_no.h | 87 - external/cglm/call/clipspace/persp_rh_zo.h | 87 - external/cglm/call/clipspace/project_no.h | 31 - external/cglm/call/clipspace/project_zo.h | 31 - external/cglm/call/clipspace/view_lh_no.h | 31 - external/cglm/call/clipspace/view_lh_zo.h | 31 - external/cglm/call/clipspace/view_rh_no.h | 31 - external/cglm/call/clipspace/view_rh_zo.h | 31 - external/cglm/call/curve.h | 23 - external/cglm/call/ease.h | 143 - external/cglm/call/euler.h | 80 - external/cglm/call/frustum.h | 41 - external/cglm/call/io.h | 45 - external/cglm/call/ivec2.h | 179 -- external/cglm/call/ivec3.h | 183 -- external/cglm/call/ivec4.h | 147 - external/cglm/call/mat2.h | 83 - external/cglm/call/mat2x3.h | 47 - external/cglm/call/mat2x4.h | 47 - external/cglm/call/mat3.h | 94 - external/cglm/call/mat3x2.h | 47 - external/cglm/call/mat3x4.h | 47 - external/cglm/call/mat4.h | 135 - external/cglm/call/mat4x2.h | 47 - external/cglm/call/mat4x3.h | 47 - external/cglm/call/noise.h | 31 - external/cglm/call/plane.h | 23 - external/cglm/call/project.h | 39 - external/cglm/call/quat.h | 175 -- external/cglm/call/ray.h | 39 - external/cglm/call/sphere.h | 39 - external/cglm/call/vec2.h | 251 -- external/cglm/call/vec3.h | 369 --- external/cglm/call/vec4.h | 342 --- external/cglm/cam.h | 582 ---- external/cglm/cglm.c | 3 - external/cglm/cglm.h | 48 - external/cglm/clipspace/ortho_lh_no.h | 183 -- external/cglm/clipspace/ortho_lh_zo.h | 177 -- external/cglm/clipspace/ortho_rh_no.h | 183 -- external/cglm/clipspace/ortho_rh_zo.h | 181 -- external/cglm/clipspace/persp.h | 48 - external/cglm/clipspace/persp_lh_no.h | 395 --- external/cglm/clipspace/persp_lh_zo.h | 387 --- external/cglm/clipspace/persp_rh_no.h | 395 --- external/cglm/clipspace/persp_rh_zo.h | 389 --- external/cglm/clipspace/project_no.h | 109 - external/cglm/clipspace/project_zo.h | 111 - external/cglm/clipspace/view_lh.h | 99 - external/cglm/clipspace/view_lh_no.h | 74 - external/cglm/clipspace/view_lh_zo.h | 74 - external/cglm/clipspace/view_rh.h | 99 - external/cglm/clipspace/view_rh_no.h | 74 - external/cglm/clipspace/view_rh_zo.h | 74 - external/cglm/color.h | 26 - external/cglm/common.h | 130 - external/cglm/curve.h | 40 - external/cglm/ease.h | 317 --- external/cglm/euler.h | 601 ----- external/cglm/frustum.h | 255 -- external/cglm/handed/euler_to_quat_lh.h | 167 -- external/cglm/handed/euler_to_quat_rh.h | 170 -- external/cglm/io.h | 440 --- external/cglm/ivec2.h | 659 ----- external/cglm/ivec3.h | 713 ----- external/cglm/ivec4.h | 608 ----- external/cglm/mat2.h | 363 --- external/cglm/mat2x3.h | 154 -- external/cglm/mat2x4.h | 168 -- external/cglm/mat3.h | 480 ---- external/cglm/mat3x2.h | 148 - external/cglm/mat3x4.h | 177 -- external/cglm/mat4.h | 831 ------ external/cglm/mat4x2.h | 153 -- external/cglm/mat4x3.h | 168 -- external/cglm/noise.h | 734 ----- external/cglm/plane.h | 44 - external/cglm/project.h | 172 -- external/cglm/quat.h | 949 ------- external/cglm/ray.h | 174 -- external/cglm/simd/arm.h | 206 -- external/cglm/simd/avx/affine.h | 66 - external/cglm/simd/avx/mat4.h | 115 - external/cglm/simd/intrin.h | 153 -- external/cglm/simd/neon/affine.h | 121 - external/cglm/simd/neon/mat2.h | 44 - external/cglm/simd/neon/mat4.h | 468 ---- external/cglm/simd/neon/quat.h | 57 - external/cglm/simd/sse2/affine.h | 115 - external/cglm/simd/sse2/mat2.h | 48 - external/cglm/simd/sse2/mat3.h | 76 - external/cglm/simd/sse2/mat4.h | 573 ---- external/cglm/simd/sse2/quat.h | 54 - external/cglm/simd/wasm.h | 198 -- external/cglm/simd/wasm/affine.h | 127 - external/cglm/simd/wasm/mat2.h | 50 - external/cglm/simd/wasm/mat3.h | 85 - external/cglm/simd/wasm/mat4.h | 454 ---- external/cglm/simd/wasm/quat.h | 55 - external/cglm/simd/x86.h | 365 --- external/cglm/sphere.h | 99 - external/cglm/struct.h | 50 - external/cglm/struct/aabb2d.h | 253 -- external/cglm/struct/affine-mat.h | 90 - external/cglm/struct/affine-post.h | 184 -- external/cglm/struct/affine-pre.h | 184 -- external/cglm/struct/affine.h | 201 -- external/cglm/struct/affine2d.h | 177 -- external/cglm/struct/box.h | 259 -- external/cglm/struct/cam.h | 646 ----- external/cglm/struct/clipspace/ortho_lh_no.h | 154 -- external/cglm/struct/clipspace/ortho_lh_zo.h | 154 -- external/cglm/struct/clipspace/ortho_rh_no.h | 154 -- external/cglm/struct/clipspace/ortho_rh_zo.h | 154 -- external/cglm/struct/clipspace/persp_lh_no.h | 312 --- external/cglm/struct/clipspace/persp_lh_zo.h | 312 --- external/cglm/struct/clipspace/persp_rh_no.h | 312 --- external/cglm/struct/clipspace/persp_rh_zo.h | 312 --- external/cglm/struct/clipspace/project_no.h | 98 - external/cglm/struct/clipspace/project_zo.h | 98 - external/cglm/struct/clipspace/view_lh_no.h | 89 - external/cglm/struct/clipspace/view_lh_zo.h | 89 - external/cglm/struct/clipspace/view_rh_no.h | 89 - external/cglm/struct/clipspace/view_rh_zo.h | 89 - external/cglm/struct/color.h | 27 - external/cglm/struct/curve.h | 40 - external/cglm/struct/euler.h | 249 -- external/cglm/struct/frustum.h | 155 -- .../cglm/struct/handed/euler_to_quat_lh.h | 115 - .../cglm/struct/handed/euler_to_quat_rh.h | 115 - external/cglm/struct/io.h | 107 - external/cglm/struct/ivec2.h | 708 ----- external/cglm/struct/ivec3.h | 725 ----- external/cglm/struct/ivec4.h | 588 ---- external/cglm/struct/mat2.h | 274 -- external/cglm/struct/mat2x3.h | 125 - external/cglm/struct/mat2x4.h | 125 - external/cglm/struct/mat3.h | 322 --- external/cglm/struct/mat3x2.h | 125 - external/cglm/struct/mat3x4.h | 125 - external/cglm/struct/mat4.h | 496 ---- external/cglm/struct/mat4x2.h | 126 - external/cglm/struct/mat4x3.h | 125 - external/cglm/struct/noise.h | 57 - external/cglm/struct/plane.h | 40 - external/cglm/struct/project.h | 162 -- external/cglm/struct/quat.h | 601 ----- external/cglm/struct/ray.h | 86 - external/cglm/struct/sphere.h | 93 - external/cglm/struct/vec2-ext.h | 337 --- external/cglm/struct/vec2.h | 747 ------ external/cglm/struct/vec3-ext.h | 325 --- external/cglm/struct/vec3.h | 1132 -------- external/cglm/struct/vec4-ext.h | 325 --- external/cglm/struct/vec4.h | 961 ------- external/cglm/types-struct.h | 303 --- external/cglm/types.h | 144 - external/cglm/util.h | 375 --- external/cglm/vec2-ext.h | 337 --- external/cglm/vec2.h | 798 ------ external/cglm/vec3-ext.h | 345 --- external/cglm/vec3.h | 1264 --------- external/cglm/vec4-ext.h | 400 --- external/cglm/vec4.h | 1348 ---------- external/cglm/version.h | 15 - external/tinyalloc/tinyalloc.c | 529 ++-- external/tinyalloc/tinyalloc.h | 15 +- fonts.d | 38 +- main.wasm | Bin 30020 -> 0 bytes math.d | 281 +- package.d | 23 +- platform.d | 2 +- test.sh | 29 +- tinyalloc.o | Bin 0 -> 4761 bytes util.d | 221 +- wasm.d | 0 218 files changed, 5501 insertions(+), 42555 deletions(-) delete mode 100755 Test_Runner create mode 100644 external.d create mode 100644 external/arsd-webassembly/core/demangle.d create mode 100644 external/arsd-webassembly/core/internal/cast_.d create mode 100644 external/arsd-webassembly/core/internal/lifetime.d create mode 100644 external/arsd-webassembly/core/internal/string.d create mode 100644 external/arsd-webassembly/core/lifetime.d create mode 100644 external/arsd-webassembly/core/stdc/string.d create mode 100644 external/arsd-webassembly/math/package.d create mode 100644 external/arsd-webassembly/std/math/rounding.d delete mode 100644 external/cglm/aabb2d.h delete mode 100644 external/cglm/affine-mat.h delete mode 100644 external/cglm/affine-post.h delete mode 100644 external/cglm/affine-pre.h delete mode 100644 external/cglm/affine.h delete mode 100644 external/cglm/affine2d-post.h delete mode 100644 external/cglm/affine2d.h delete mode 100644 external/cglm/applesimd.h delete mode 100644 external/cglm/bezier.h delete mode 100644 external/cglm/box.h delete mode 100644 external/cglm/call.h delete mode 100644 external/cglm/call/aabb2d.h delete mode 100644 external/cglm/call/affine.h delete mode 100644 external/cglm/call/affine2d.h delete mode 100644 external/cglm/call/bezier.h delete mode 100644 external/cglm/call/box.h delete mode 100644 external/cglm/call/cam.h delete mode 100644 external/cglm/call/clipspace/ortho_lh_no.h delete mode 100644 external/cglm/call/clipspace/ortho_lh_zo.h delete mode 100644 external/cglm/call/clipspace/ortho_rh_no.h delete mode 100644 external/cglm/call/clipspace/ortho_rh_zo.h delete mode 100644 external/cglm/call/clipspace/persp_lh_no.h delete mode 100644 external/cglm/call/clipspace/persp_lh_zo.h delete mode 100644 external/cglm/call/clipspace/persp_rh_no.h delete mode 100644 external/cglm/call/clipspace/persp_rh_zo.h delete mode 100644 external/cglm/call/clipspace/project_no.h delete mode 100644 external/cglm/call/clipspace/project_zo.h delete mode 100644 external/cglm/call/clipspace/view_lh_no.h delete mode 100644 external/cglm/call/clipspace/view_lh_zo.h delete mode 100644 external/cglm/call/clipspace/view_rh_no.h delete mode 100644 external/cglm/call/clipspace/view_rh_zo.h delete mode 100644 external/cglm/call/curve.h delete mode 100644 external/cglm/call/ease.h delete mode 100644 external/cglm/call/euler.h delete mode 100644 external/cglm/call/frustum.h delete mode 100644 external/cglm/call/io.h delete mode 100644 external/cglm/call/ivec2.h delete mode 100644 external/cglm/call/ivec3.h delete mode 100644 external/cglm/call/ivec4.h delete mode 100644 external/cglm/call/mat2.h delete mode 100644 external/cglm/call/mat2x3.h delete mode 100644 external/cglm/call/mat2x4.h delete mode 100644 external/cglm/call/mat3.h delete mode 100644 external/cglm/call/mat3x2.h delete mode 100644 external/cglm/call/mat3x4.h delete mode 100644 external/cglm/call/mat4.h delete mode 100644 external/cglm/call/mat4x2.h delete mode 100644 external/cglm/call/mat4x3.h delete mode 100644 external/cglm/call/noise.h delete mode 100644 external/cglm/call/plane.h delete mode 100644 external/cglm/call/project.h delete mode 100644 external/cglm/call/quat.h delete mode 100644 external/cglm/call/ray.h delete mode 100644 external/cglm/call/sphere.h delete mode 100644 external/cglm/call/vec2.h delete mode 100644 external/cglm/call/vec3.h delete mode 100644 external/cglm/call/vec4.h delete mode 100644 external/cglm/cam.h delete mode 100644 external/cglm/cglm.c delete mode 100644 external/cglm/cglm.h delete mode 100644 external/cglm/clipspace/ortho_lh_no.h delete mode 100644 external/cglm/clipspace/ortho_lh_zo.h delete mode 100644 external/cglm/clipspace/ortho_rh_no.h delete mode 100644 external/cglm/clipspace/ortho_rh_zo.h delete mode 100644 external/cglm/clipspace/persp.h delete mode 100644 external/cglm/clipspace/persp_lh_no.h delete mode 100644 external/cglm/clipspace/persp_lh_zo.h delete mode 100644 external/cglm/clipspace/persp_rh_no.h delete mode 100644 external/cglm/clipspace/persp_rh_zo.h delete mode 100644 external/cglm/clipspace/project_no.h delete mode 100644 external/cglm/clipspace/project_zo.h delete mode 100644 external/cglm/clipspace/view_lh.h delete mode 100644 external/cglm/clipspace/view_lh_no.h delete mode 100644 external/cglm/clipspace/view_lh_zo.h delete mode 100644 external/cglm/clipspace/view_rh.h delete mode 100644 external/cglm/clipspace/view_rh_no.h delete mode 100644 external/cglm/clipspace/view_rh_zo.h delete mode 100644 external/cglm/color.h delete mode 100644 external/cglm/common.h delete mode 100644 external/cglm/curve.h delete mode 100644 external/cglm/ease.h delete mode 100644 external/cglm/euler.h delete mode 100644 external/cglm/frustum.h delete mode 100644 external/cglm/handed/euler_to_quat_lh.h delete mode 100644 external/cglm/handed/euler_to_quat_rh.h delete mode 100644 external/cglm/io.h delete mode 100644 external/cglm/ivec2.h delete mode 100644 external/cglm/ivec3.h delete mode 100644 external/cglm/ivec4.h delete mode 100644 external/cglm/mat2.h delete mode 100644 external/cglm/mat2x3.h delete mode 100644 external/cglm/mat2x4.h delete mode 100644 external/cglm/mat3.h delete mode 100644 external/cglm/mat3x2.h delete mode 100644 external/cglm/mat3x4.h delete mode 100644 external/cglm/mat4.h delete mode 100644 external/cglm/mat4x2.h delete mode 100644 external/cglm/mat4x3.h delete mode 100644 external/cglm/noise.h delete mode 100644 external/cglm/plane.h delete mode 100644 external/cglm/project.h delete mode 100644 external/cglm/quat.h delete mode 100644 external/cglm/ray.h delete mode 100644 external/cglm/simd/arm.h delete mode 100644 external/cglm/simd/avx/affine.h delete mode 100644 external/cglm/simd/avx/mat4.h delete mode 100644 external/cglm/simd/intrin.h delete mode 100644 external/cglm/simd/neon/affine.h delete mode 100644 external/cglm/simd/neon/mat2.h delete mode 100644 external/cglm/simd/neon/mat4.h delete mode 100644 external/cglm/simd/neon/quat.h delete mode 100644 external/cglm/simd/sse2/affine.h delete mode 100644 external/cglm/simd/sse2/mat2.h delete mode 100644 external/cglm/simd/sse2/mat3.h delete mode 100644 external/cglm/simd/sse2/mat4.h delete mode 100644 external/cglm/simd/sse2/quat.h delete mode 100644 external/cglm/simd/wasm.h delete mode 100644 external/cglm/simd/wasm/affine.h delete mode 100644 external/cglm/simd/wasm/mat2.h delete mode 100644 external/cglm/simd/wasm/mat3.h delete mode 100644 external/cglm/simd/wasm/mat4.h delete mode 100644 external/cglm/simd/wasm/quat.h delete mode 100644 external/cglm/simd/x86.h delete mode 100644 external/cglm/sphere.h delete mode 100644 external/cglm/struct.h delete mode 100644 external/cglm/struct/aabb2d.h delete mode 100644 external/cglm/struct/affine-mat.h delete mode 100644 external/cglm/struct/affine-post.h delete mode 100644 external/cglm/struct/affine-pre.h delete mode 100644 external/cglm/struct/affine.h delete mode 100644 external/cglm/struct/affine2d.h delete mode 100644 external/cglm/struct/box.h delete mode 100644 external/cglm/struct/cam.h delete mode 100644 external/cglm/struct/clipspace/ortho_lh_no.h delete mode 100644 external/cglm/struct/clipspace/ortho_lh_zo.h delete mode 100644 external/cglm/struct/clipspace/ortho_rh_no.h delete mode 100644 external/cglm/struct/clipspace/ortho_rh_zo.h delete mode 100644 external/cglm/struct/clipspace/persp_lh_no.h delete mode 100644 external/cglm/struct/clipspace/persp_lh_zo.h delete mode 100644 external/cglm/struct/clipspace/persp_rh_no.h delete mode 100644 external/cglm/struct/clipspace/persp_rh_zo.h delete mode 100644 external/cglm/struct/clipspace/project_no.h delete mode 100644 external/cglm/struct/clipspace/project_zo.h delete mode 100644 external/cglm/struct/clipspace/view_lh_no.h delete mode 100644 external/cglm/struct/clipspace/view_lh_zo.h delete mode 100644 external/cglm/struct/clipspace/view_rh_no.h delete mode 100644 external/cglm/struct/clipspace/view_rh_zo.h delete mode 100644 external/cglm/struct/color.h delete mode 100644 external/cglm/struct/curve.h delete mode 100644 external/cglm/struct/euler.h delete mode 100644 external/cglm/struct/frustum.h delete mode 100644 external/cglm/struct/handed/euler_to_quat_lh.h delete mode 100644 external/cglm/struct/handed/euler_to_quat_rh.h delete mode 100644 external/cglm/struct/io.h delete mode 100644 external/cglm/struct/ivec2.h delete mode 100644 external/cglm/struct/ivec3.h delete mode 100644 external/cglm/struct/ivec4.h delete mode 100644 external/cglm/struct/mat2.h delete mode 100644 external/cglm/struct/mat2x3.h delete mode 100644 external/cglm/struct/mat2x4.h delete mode 100644 external/cglm/struct/mat3.h delete mode 100644 external/cglm/struct/mat3x2.h delete mode 100644 external/cglm/struct/mat3x4.h delete mode 100644 external/cglm/struct/mat4.h delete mode 100644 external/cglm/struct/mat4x2.h delete mode 100644 external/cglm/struct/mat4x3.h delete mode 100644 external/cglm/struct/noise.h delete mode 100644 external/cglm/struct/plane.h delete mode 100644 external/cglm/struct/project.h delete mode 100644 external/cglm/struct/quat.h delete mode 100644 external/cglm/struct/ray.h delete mode 100644 external/cglm/struct/sphere.h delete mode 100644 external/cglm/struct/vec2-ext.h delete mode 100644 external/cglm/struct/vec2.h delete mode 100644 external/cglm/struct/vec3-ext.h delete mode 100644 external/cglm/struct/vec3.h delete mode 100644 external/cglm/struct/vec4-ext.h delete mode 100644 external/cglm/struct/vec4.h delete mode 100644 external/cglm/types-struct.h delete mode 100644 external/cglm/types.h delete mode 100644 external/cglm/util.h delete mode 100644 external/cglm/vec2-ext.h delete mode 100644 external/cglm/vec2.h delete mode 100644 external/cglm/vec3-ext.h delete mode 100644 external/cglm/vec3.h delete mode 100644 external/cglm/vec4-ext.h delete mode 100644 external/cglm/vec4.h delete mode 100644 external/cglm/version.h delete mode 100755 main.wasm create mode 100644 tinyalloc.o create mode 100644 wasm.d diff --git a/.ignore b/.ignore index 79fd401..09313b6 100644 --- a/.ignore +++ b/.ignore @@ -1,5 +1,3 @@ .git build test -external/cglm -external/xxhash diff --git a/Test_Runner b/Test_Runner deleted file mode 100755 index 12893f9dd0da9fd1c573d264898a0f0a20dc5285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2095192 zcmbT<3AiL#UFZFvSvpw_M!-~2LS#vmC1?;69W@4MI+4Wy8c3J%Ms?M#&XVe?pz1cA z&FC|sBW>bFAfh>n5{{^e%S_!UY z=kq?#T%Oxe@yT;fob&&kICrUA!N0!wr7ybS0T1x>_CW9Ryxm#+x*JX@vKPjG@dW#m z=SAMo`fR%JmB-No-3vPQtlf@xANND{I**UHb~k9+X$kBNJo$8%42Bh&G|A9s4a{9&#m9Lu2_jgI&IxLs|c_dV+L<9OV> z&CO`|9X2x?=WcYnj|;!@V@^Mg$H0cKqw2XE#qND(_2ltMr@eWej=Q$Ix7~5~p03Q+J&qv-mCuT&s5r(^2DmMfY(w6xZPY=f4`~EA4uk50BLkyN-0U^iON@nC_)re7C&( z)!s+n{ODi*>f?*w`t~=>Up9H+gFpB!zxJ>%FBv?@H=F!h66V@SgZJ zkDh(C_u{m?_3NtJyPNpYz2sZooMjJ>p7fyVP2LSp32(?;UyH7rcX#hU(7pd)_ijV? z{zLcYvU~rL?)^u*_aE=xf1-O|cJDvgz5mDVefRd$-TQy;-hZZh|GDn{7rOV|+kflc z-`ln%{irYajpecmBrt2Mw;j{nLJMwEn3lp1lA0pZY5g`o6Dizx6AA{-YoBo=^J0 zzkK?Kzx{h(^p~IUj`zmD_~!5b%K!8IkG|{m?|b_D?|J#NKK0$7_c8zKzuo%2XME-R zo)}+zYw?p;U;VdldG*t8_>SJ!_a63_@h^wVuYTl@|IZJ6@TmIoS$^kNKk`fN`NrS+ zZtwdpf7hSKPyNF$c>jmq_s*aG;2*#DdC?PI@!=c4>RsRSKi_xxJ%91|>z5w) zw3oj96;DrJ^Pyk+^(U84xaX;#`lhdb)Q#`?iw}MJ&p-4zuPC}HAAGyHTb%#weqMcM zw}9`@2i-!uKmVrghP*$2W4Bq}pFiM0|F1sK{?dVQ{^@~!lFlD}KlAE!``-PH=YJd+ ze|4b!FLgKA{q^(Y1O5{S`v3I<_58I1^ZH0Pr~A9^cOIzEl>_5{<$?ZRa-g5zKhXZG z5BL`!nC~YZ=>NH$Kk-h)zzj~nkcO7W| z&I9fL=0J}B@qmB$z;YKXhPye(Qnyyy!sx&pI%#*BKd{}1dwf!<%8pK@TFAL+((fBV%R9O(be2kHy8ez|EdFZzWYG?mv`;&@4mk0z;&-4$oGQ>*3VlH?6<#v zU_AeDV4r!wp?Mwf@Ie2caG?F|2gd)I2l~17K<>Nm1@3QOeffcY{^`JYe&Im-e{=9{9ZcrUP~R?+4byFCFloJ8<29dthE&b1&%L`L_FB z_5RlRyAQ0x?>=zdTMpFc&kyu}(}DIcI57Unf$@CWfqdU{p#P^GSU>-8p#M+m#vgR= zeEaSL{K$dz@EhHa`~I2tNH2as_krEp*Pi~j`?-gC zcxU&4-P<3Vf8@aUZ?X36&%5>?*VSwH_66M!X?FdGU*r7m9eaOzy3V`n{;l)f&q;P~ ze_$ScjvLRwvG-B)VC&jHyjxGZx0jgvyDx;gw~6^DY5d>o{AK2!eju;gZJfp5x%O9V z{9k3BeV_BcJH3kM9ou!idz^QdJAHeuT{rdI_+MlGPpX6UKQVuswfC)`Tg^l3KVP{1 zcl+t??U${e{8yYer`r8&$=U~2XZKS;&--GH|JPjm-Ot{3Z|{(QzwfSC}`?p(r&+_^@^RKn*hQIFC!^)v@pG>I&9)wV^K>_`?yWZeSgTJ{IDeU~=igQ?R=3^HGk0&l zVdDwxzSDeP+r74%Z(O^6EK40aUd)Mu{{?E96-qP(O zySI-&a6kUAwa@<4_5UK*-1{-RZei>Bd(7|Zj=OQDzv}w$*?3-U?Q6Rqr)qERTm7GG ze$DC`zRUIVkLEvb;|Xj(RDJ%Bd1L$M#M-}0x!8U2QOoyTcHPkG+%-FW`&{$fa(|+^ zcl6?0Uv_li_}cO9m#&{2U%T~XFSva5%JHq|Zo7Q!9Ua|%$JHxG*H6w}J2^UXP4Bni zi*7x7@s&#_M=!c|e0=NO>9Kd|%Eim)PR@=uU%4Q9leMFS6{j7(v=HGFFd|{d~$sA^!#ypa_Q=oGk?|b$t|xuJG9tE&PA;DLxs#J?yN~HwpMTx;OK;rOy8By+^GE0JymsyQ%E{67OSfM;x#Q9mZ`bJR z`PW@dcSSosIXZXY!ZokEbb5Sz?aH}sRu`|P$5)>FoUY*=N0+*Ko?WBs;*N9IU*}y+ z?>sqwbmx`JT{p)Uyz6&gKY#VgMeqFX{HW{c(6--T{Gr(-)h zKY88J#dDV~dl$QGcmFwe!8<>>aOs+NJnb%a`TFtk>$&KTb?mpn$`P1ZgQ@(cf?1kg&C)cjt?d_&MId@vH>&MsLaNFJK)h^6C?!0oxxzxLO zeC=Ad?k--ueCPFvH#xa_<+69j@f~+ueZ#SLN7ta6)@gCQT>#yXk2JLNmygd~xidXV zcOTc4@!aKI4UevQ*N)G>;o`NccX$_1jxS%nx=ZEc+U4UbXCv$?e_=nRFTdJ_+)ZwB z_4>(ecb}%)P5MH&kWO!tt0$K(-n|R`=&p0!RJxQo-|ptMx!O`ZE&kETwYzr#-`n-+ zV$lpvv)NlM_eQqIrvu*2?!sN??z6T|xf|z|bN7aRzFQmJ(%;pf`_H)x-CwS~uABdb zt9RbJCf(Rh2i7&|N_6iXblT-@*RGzsaQ@u&ZeewUzt|P*i9omtDGkJw12+*t68wX=^ut&C>d4fjfSAKrE8LbphF zcf|4e6YsWe7dg4sP4DRX-FMt}_44(ji`^Zpu+Nt3)zrIixodH{SDfbg|M@_-$#i$? zxzkO??zr7PvztIy%+qCbbaZ}t?&#vBF8ycYe3;dl#?YedYXVQMwPh=<>RFa_!D5=ewM{CDN5^ zce5PbyxWj=+hE$=OWtmN>7{P7x_afxu0}^km%8yk?|DbpuXj83y<73Fy4tEv7aIoT zqW4a&-kGM|wxgnUgFpSKE9vRT(!0Ig>bP>cmz}?>TQYZD>sDen_HKXNZ3M5szT0{9 z(PtM`tf%d|F?JQaa`mX2{JGOz@7!&>k8(?Kcg2fc%`ctYeOBvk&$(}x-6nyX^xhkN z_i5m+`+OcaIy!lyg{jZ!N9Rs1UcL6ZZWt%s66&t!KHFS4KK*3=f~(ym?a%SG-6xIn zSGyH>eEs_Kuin}1N;6t&Xm=UAt@NpMBF&_jn>fn-FsvAnehePrMmjQ=<>PSuj>QcAa=v-E^u^m`X$ThrA|NMHOJSk@4jSs zrX;(Mx z_q8kfy<>X8)o$6n`g-@pz`a$mOIV*SQ9HSJ(k{q1>cd`rr5jcEMar>;vYTx8^_&ez ziFX&ap6)a1`we0@GYq`jvuu#3>knP4<6H0S2BFu^#`m&w-D1|V>^9fic3;Enz8u;8 zuE%qCaL3u7Za;ti==$#LSvx;(et*9ra?49!{QMUj-SmuSd-~H&&-hI5mKVI>=-JN* zPmj-e#!b6FsogW4bN1)YI{VYJ?)~GvFLxoHebjxl`@Iy;yP^A?mIrnJy`lU4tKEO^ z{hvF3NGCVmM;~~fKkwT1&OYv;_R53L+V6f>%Jp*JzVF+EUVX6luI{de~#_dlM?|8I^DJ?nMvw*_rS3bxp7*(DuixN3#6CXkK0bcR-QC%Z-iytW zdvCS#Yp4A`(0hlSyYb&}HvV|+em}1JcJ%Zuy6nDj9mA`Kx)uq%_(JCsc=T_ar}Q7_ zrrW(u;gxv?_ilFIG0))fS2)k%t^I!I99~%a1-yN;`@Vk(_ut`sb->pLd;`zl?)upt z@ZN9j*I(`X2YhhAhX*`@XCLYoLiaX-2M=~X;mF{-wYhtn!82=L(5?Lf?mfiyQ^7Z} z8_x>fzT9~YAHCN38osrD8u-J%(6!&d`{phDfp(*A;UA|P__z1-dXjk$u5tSC>Kj}g z0{Yjw--{iG!)9IXrul^Eo^>FX;EU_6vCMea=gGXugE!<`ulK zajxLryIub^Jp3J3cO6};?&rl;hoQYLR~;g_>M(+<4l&*8FovrR30!rUz*UD7t~yNN zszU~E?OaFAxA;1@9=2$&I(Wakziw5B9$a1-TI)rf5VF*_pB6wlv zI;sxY*Sk6_&|Y;Y;i|(Dt~yk7tHTPeI@EC0VGUOu8o27PfvXNJJbu5+RY%pK_y$*p zvAr%=9TK?eFoCNMDc$NYg{ux3Ty>biRfim|I?Um!Ljm`{$#RElz9n4qUBWfrimu$@ znr{u)eAjTzw}ETE8@T4%!ZrWV@9p2$g`MlD+~c=cebD}_KJc^pz|ZPKSAF1T^?{$& z2Yyx`_*s46XZ3-{zi;=29aRS}xBCLFIwWw_VFFhjQo8O7xayF>Rfic|b;#kW!yK+U z6!gZ`!Ly_4P+A>&aMi(ws}6m*>JZSa4gQmCKK1;ajQ^8fA6nJV8pjOY*tw3%F?_ol=LYSSR}0rTw{VTq`-A;Dby&ky zhXx+~q031})uFOFjO=x}>JYX5-zhZ$UT$l>v%Tb zZ*%Kmi}tF6_rLbnx$4k^s}4Th>d=R)4gp+s7{FDB5Ux55;i^LfFYH`L)ghR>IxNs$ zbtvJg!xFAKRCKGu3a&cTaMfWAR~;I->ac;U4lO+VBbTd=szYsc7~1Rd)b{fTt~!k1 zszXe-I*j4Lezvb`ICNE#O+W z3%J&832*ION7bRRI&9Hi`Fek{Ur*Jc2Ui_@y49f%4?n@>7{F`u0leA$gTn4Dgcpx@ zK7>b~gl_Ylz>}xA{!@5rK80uI89e`F*Ut=|Ji&Pm z4{Tm@cxYb0Bl873HZS3-Zw=4h;p)7G>;7uss`Cb}I=6JI^A@iA%iHX)Tisthxb80> zuKTMG*Zmd1HUA7Aey6L$46gN-!&QelTy-em#Zz7G3%aeJ5?-1w;gxv>*LqvQwccuY zYyGU@fsM0)`{o{j&t^X~&G57v-KX>I3z(YIN@oYb|yb83h>|95+&%ev%yFz>A zTf>#_8m@dBx~=mKJhb_?@JRK6$Ewet?bk>7_Tb9bhigCS!?m9TaP21pxbh9*iJj}H zI!Etxb)K-j?Mo?Kb)Ldi=ZtQ3p1~VipEb!uf&Lv!RUcy!93a&b@ z;Hq;C_idbOcwpYZ)Bo+(jgHEtwOpq5x;*_fSBDI)TxM|PlG81hIo!AY3wU6@fQRNK zJhk~Q;mW0gE0+~qxzupwvW6>{1|HcsH}pSu^^feRIv0hzFGg^Eo{izE{}`_NCv>a- z1g_7sDO{gtr*M6q&EWbxJA>=piX2k_*%Zag78GateW^9Wv=kKoy7x&C8#VLpae<_SD~p6h1<4?f#@3XjaE@WecW zm;c=LGlNH;>pX`SH#wifBg?yl*LJR>_UF>}jWyb9-)P|4H#TtX8!g@TjV)aJhWD5I z>rnef53YT~hil*H!?kY&aP1odxb}?@u6<(&*S-C}~*S@iZYv1r%tbf}ddT{Lh(;MyNzxb}xJT>C=;*ZwepYkx@Lk-n~gYk$b#+8<_c z?GHIz`$GY5-{tm!1zg|HmT>I@OStxdif;SB3a;;GYq-9jUBmVLYy;Q#vm3a+pKalq z|L8;e>$$LV9koyT-)Hqf`?LDM&*}p|s}EiEfuGd}epVm&S$*JV^?{$&2Oj^GtBa1R zLu+*y+v{@GA%Uw76S(S-(yb0txayF>Rfic|b;#kW!yK+UEa3I`yWC57_}8vJI;sxg z!nGgT>vAt~U(ZKy)n^1(ePX)RXAD<;61eI!fvY|#T=kj4Ri6yr?j8Wyz2$K4-L4LE zxYkJlR~;5`)uE(Y9hPv_p@ORpE4b=V!&QehTy<#Rnt%K^`};|0=Q?UVv{s)b+N(Yl zT=iMORiBz}^;yGJp9Ze_Y~ZR-3s-%%aMj2A@O~X~JJ(TlD1N}!3EHRncN}olVF6bi zO1jnw-2YoQJ{>il_y^s1`u4h9;|bsz&j7CRgmfFvkZ$KWJp3W64_xb{fNMMpxW-e` zRUf$4Nd?zBS;4hVYPi)bdqcw*15n!!`^8Xmsa zJ;%uZ$o_pT58#=d>!|rAKj!K%Lwl{~9IiUd;i^MHw>m7~TF)h1>v;*+damGF&nvjr za}5vw-qlM-)xrO9SBIg!E>|5Qxau&1s}3>U>M(|@4hdX!n7~zs6s|f<;i^LhZ|q!0 z&9|~TY|vhHXyK~E7OpyY|FFM4&wkGtt~&T|)u9hp9Rj%OFo3HLA-uBl60ZA5ud6=k zPq=lmLVMMxhO0hnxa!l;ZJli3s!t17eYSAb$NR_q`l~)Yxa#A>Q#;pDbqJQO4pX+b ze|MR|Rfic|b;#*fhdEqzDB!BY0M*d^6t3}SbQ}K+UZn2xbq+7h=kVb5u6+Ry%@^?4T=PDg zueDpEeQE70cxAqVhu7SAYItP6h9~9?Jhb|^aE;sR{vWb-ZyJC8pLDL{>C2w-^3h&- z_2J4Zpj%!8c>NkTf)L)A@BW{>?mN!3Q0GlC~?aP4DwFm~<7aPKbHK7qH^ zeggNceG1RN$n`&ktL`;C`YAWhHC**?;Hv)yuKKrhtN#}6-{!{YJz&4i{(0v;cw+9u zHJ^fR=OsM6!CkM0x2gmDtPb$AI>68BKvx~$mEA|4jmxUyr&qo$ILi#y{iM z!v^h@dka_YTex!f9=N}r_4Tk1k1E%$57%`AxUM^Z>$)M`*4q#syv@})f`{fKcw`>K zv$wi_#_-%cffwczcxj%(EAuH_bzH)|2f2FcsC=XU;ykt2<>AjdpTbrD46gdm;HrO4 zxBAcFs(%5mtj-H~ZC=6~^CdicyUV45m*y*YYhJ@+>wgVb9fJqE`l+75&$;sfT=fj$ zs^<`{dPa1s=LoKP#&E6YF+8$)C2;@ST-_${z&wSA=2LiNp21`D8C-Q-!TpE0dg`b; z*H-7gy)IXs1GwrufUC|SUHb-Hb&lYw^9Zgw$MD?hFoqZA3A{9)z-#jq-kN9d?B`uQ zXK>XmhpTRLxawBWt!@jr>Q=&4wwe$BRmb?o z{rkPNa~-t~+h1_)mT0fX6Z`4l}swki%7nIb3xp;Htv{t~!+P%FcCE9peAy z>M(fde%&HF*HP`gm1{Rb`{29Wx{cwg+Ze98C3LIX1Ri{+>pz8ucHJpFGSA?#`3#<$ z=kVHm4i9$!$BErr0k7WSd_lMK3SL@0S8%Uz{nT*Pa}8HL8@knV0}pNdE!?;3ZsCEs z_ptqS5}Nnmsksj?&HM1yJbl3beHgv5| zcx&Tt;h|l33(w5Ghwrb?+`I>`&3$^Mb#ECwG@rp!^Bi88&*8!Mx&8~d>baoXc?C~@$<`-4 zvHokg>bZuio()~=6CPUsEj%^f!fSKy5&P@2G4H{H?|1d_;i-8aUYiGS)pG!k>|95! z&)}DBeWJa;aN~*Ls^=K4dM0$OPk3YFPvL=GcM6ZpGk9t~gO}zx+<&*5*BqXj7jV^c zLAUb?UjMSKPk3ql*KpNy4OcxIy4EK=v;JFnWxjl5CX_uofZmTc2p}{gACsxav8EtDXs6>l0qv_*1xV*PX&c^9&xD&)}JP z4sXrp@a%`(d<*#5`h+Ksa&^;D^^AVQd1hB-ns{ahG`sZ}3 z{~YcwZNBjK$DA+Vjd=-=e!{h1!ZY&NI%>YfZ#rMw>vGkhfvXN1xa!c-tqxmw zVRi5x?XIuust!H4>fpmwhdx|&2;km7bJx>R*DcmI4trg$I{0wap$}Ib0=m^<055;q z-EzA2ANuRvl?r%vyYmG+o;WYz)dlBEc=%XbCw6qLy8qu+o9_^=`9^TfcLdjb zW4hJ}ys~p0HJ*r?PPe*N66 z2iMQde0XN(I;x-G_gud-v{xN+xau&6s}2R->ac*T4kcW5Si)6@3a&b=;HpCl*YD$b zAGcr6#Ljh8eX_>2o1newlfqS>DO~l*=vJQ@T=mJ}s?Qv*`V?^0X8~7zN_gIP^VLyx z2tVL_Zm-K#hXSrTEa0j`Nw+#I;i^LgR~=Sx)uD!~4r{pT(7@}Dck|Uz^KGmSYkOU; zIy7+AVFOnkTDsL?3s)VyPjKVXbybHRTy^l_szV>HIt1{{&UMsv^FMIon4!Juki%7n zIb3xp=-M~nszV7^9hPv_p@ORpE4b=V!=q1h^VLyxi2l&|$X=JXk8yvB;i|(Jt~w-i ztHT7YI;3#bVG36rGPvq6gR2fXytQ*3&*p1&*rI*d?Sd zhYehHXyNfEx%uj-I>dkEd~C1FwLc_q)nNix9a6g0VG36rGPvq6gR2fXTy>bkRfmH9 z$!@-$9W`I?kDd46s)G+#9r|$9A)s3w25{9OgsToixattWRfiE=b%^1mo$IJNlval& z+N%x~Ty2trPzdyZ;Bn?%y3B zXkWk^J1^nkr?~p-b@gBVsq+omr}lHd7Oq^jaOL6!`?>4)FnjRyQ!RJ6_ax_ixNjc7 z1M>kqG!NmC`4AqPNASda1W(OlcxFC^m*xq)HJ`wPC%ZbN@WgxyPt7xUZa#w-<~h7H zpTjHj0^XP};NDZ*_)B&8!X_u&xjgHLlUB6w&%f=A{tJT@Q06Y~U~ znor=Fc?!?Xr|`-=gL|Lu<~4(d<~ckypTjfr0$!Le;H7y9ugsV5+Ps3d<}0}W8E#%R zJTza!Bl8Acm~Y^vc?)mNxA6FBw!&hnNKeE^5;j1kdxV{bYkd}Q)n@@$eM-93X9;iqr5iy7 z_rA>e3Lco(@W^}(Ps|&5X0Cdu4*sXxIzju=+I#l8+Slg#IC=69uAczyb-fT?+PRKr z{rr{dr$zhpGo0(F_UT_cpW5qZ{wDXQ46Yn!aOIfOEyp=r|Bkhw+rL*`!1eD~OL+D) zH+~&8{_Jm@&+K)%)@KgayykGttDxJw7Igdj=n}5Kk6yy{_t6zxe;>Vq2TynN(oyqj zKJ0v8ugkSxg>cPx2-kcgy3Kb4*M1elwO@_l+OHD0_Nxh8`&A0B?OaFAH~(8#hc()( z4h>v&*uYhXmTq;}!c_^sjZkfrsWTJU8FM1MA;=)_(4Zc@LhM`|!fN53kJwcr|n5AHbtG zI}hQF^)rOG<`LZc4%g2Jo>~7fJU1W13-bhCnor%LgPbzhWp8&3rf9_rTN3Z8to8(9taZC$P5T89lhw|+M8O6wNhYQKV4|IR9P z)Bd`x&3o|1+=sX3eYp2MuKxfYm=EB-c?eH!oebexhY?)sa0Cyn{}>*bkKvWpEj;pE zz7u%$4Q{?ET=`Dn$~S|z*3S&Cd~f^(eZy&CF19)lu4B*N) zgh#d>hVa-tf+yx9cxoQQbMrC0Fi+r_`2=2?r*P#vg)83-u6$?k!tTc$UYgJ0x_=9J zY3Dk+R6Vb<&lgLy_iSIS;L3dkSMD`D*FFzd?hV|x&+i*}VBW$*^DVqI_nx!A&h_;} z4<1=PeRyo%hbQI%T)7Y6nY9n$%6$kgtbGJm?jv|*?PGZHQ8)iFyteiUT=`Dm$~T2K z*3T5Kd^33Vb#CR&;JJAYFU;rg(!79I<_majUcv+0mzMCx+E?(_dpCw%RR`BxeZu~2FVP3nDOM-w|B-#_+`Y8N-!t0&lJT1nzyC zn{NvD&8P6dJcEbkGk9d4!xQs4JT@=j%69=*z9n4wF5#*5U%@l;6S80IqyPcxwF&;mS9n>*tg3#yo~6?{GPe;f;9$SH2Ut@=f8b^)rQg z-|4QK!Ikd}u6%R2@}0vAyH5*vX}*A0<|RD8(dD~@`!@axUYW1p%D09$)_x6Fz70J1 zE?2h=JTY(KmH8GPywmmLJ#T;gE8iYm`TFqK`tQR->py@i-vK+ctJbAdwcL=X6-w3XJ zM{wmE!Bup-`~jKjh*XwHs43O^}j)T)uDx}4qLeD;C=4?{hnJLdT`ajhpP^KxattV zRfhpwbqL|Ho$IJN1dp<>)6ibOw~)Y9hY4JDNae!1NW`{23}eJEnNH07Owrr z`#h{qyKWC2*mZq)Y3=*)(Ao#|$GUt6@W|SSaOFFME8hsNd`EEQ8^dF}?ij9o6S(r7 zz?E+bSH4rY^3CANcLqI<{P;8*Y4}67VevG;mX(h7yIi!u=YK; z^7Y}$w+~mo0bKbG;GtbNge%`6JhJu?y!=F$?+6}S`xvf#$8hDFz?JU=u6$Ft@}0t! zZw60noHMxc&Ed*-4p+VfT=_2G%D03o-z8l6R&eFJf-Bz|u6);U<=eo6PjdNg;HlNE zg)84JT={y>-(UaAw+C0gK3w_s;mS9F>;4_Um2U`FzC*b3jo_KpVFXvcF+ z$~S^5-w|B-#&G33hAZC$9@;o3aOIoAmG2a;d^5WBKZ7gZ9IkxlaOGRTbIW%DSH2}& z`7Ytgw}Pji;__X=W1CkESH5ew@@?SCcLP_xEnN9-;mX&0;r{whY@9u~^7Y}$w+~mo z0p0o^z?E+ZSH45I@{QoicLZ0yF&ge+`NDn<_mafUcxK$C0zMd@Y>q1;L5j#E8jI-`8IInyMZ@$-4?EVxA4~5dpGZ| z|M*ER-yYoiuDUc1+T3C8m@fT@Y>op@M7Td-M|}b-@=ve7Os4~TlUw#^6kNuuMcnSx_!96b?YsF zhvox#VjjX%^C4XMM)1tqkKl=Y-5bM|?-;Ip6S(r7(CxY@T=`Dng|*M%{-?WqXYkV6 z=Wyjahb!L#u6!48WjN!_64A=ggz~iU6d?)b6`cL7?cM4a&8C?0!;L10L`+w&?&(7h2c>#~j7x2Qo zgqP+^xbm&wm9<~NYx5eeeAjU0+rX9Y2HsfzExff{wsdRneZl_vub%Gm?ZLf|*!RD1 z<=clV-vF+B2XN&Z!UMbR5FVOG@WgxsFU@0kWj=;0-vr)R`w6@?PvOdU3Rk`vT=~x6 z-ru|W=WySyJEvRw0v`W ze{gl%!j-T0lKu4`S^FM5vHjVHE8jj``37+1JAlV_-4GtyyoT_^+DGsrboq|pskM*c z%6AM`z6m_DekO3`o5BlgKZTd(8N4x{!F_vvLJkkj=k$McxfgIf7ia<3bAd{@@?FA} zZv|JrE4ZEuRKxXLpfz021!~~_O)lRJJhJ(=aOJy&D_`%W`|Dr%_Tb9bhb!McT=@p@ z*v2`4E8h^Ve24JD`ibDmcLZ0yF@cMbPH>h9kLu6#Fe<=euQ?-s6ny_fB; zf92bQD_9l@1v3|GEmxbjWljrM=I@=f8& zcS^VUW^m;@gDc-0u6*Zkgp(-N2P^3s=5dxbpSBaDV+r&vW_q;Em1KhwJ|B!^sJ zT=|A@-+SokzfT{+L-Popn2+GfH-;X61ei6z?E+bSH4rY^3CANcLrC!Ib8Y9 z;mWswm!IwOUBD}wZwXhvOStl_;L3LeSH3k|`L5y0w}IC-&JA4ows7UUg$ECC>&lDw z*T3@Z!IiHMSH69?@(tk1cK}zuAzb+m;mS9H2mjpVJA#Kc-x#iZ$8hDFz?JU=u6$Ft z@}0t!ZwA->JA*6V9Ikxl@W|#{z?JU;u6#?l@?FA}Zv|JrE4cEl;mUUnSH2BA|6G^v z1|HjdTe$Mw!j-T0iv9JUSU)|u^7Y}FweQ0V^8j9(58%o-ge%`6+`qxyzY$#dj^N5S zhAZDOT=^z&DeSaQUv_tvc@M69 zeYo=N!%OQYfGghtT=|A@hZWuaK4Jw|zBOF=uHnkJfh*q)T=}+e z<-3I|U+>oa^2eAw046LwIT)!E^HwT=~Xu8^d+~j^WBTfqM^e_r(ORd{cN}?Wge2JcGyPGr022;mUUoudJT} zu6!48tT=@>++Mgr1@*TmIZwyzyW4Q87;L3LbSH3A+`A*@=H-p!f z?+o5pzByd^&f&_pfNOtVz?E+a*Z#bOYk#ib+Mic&2upyMlW+y3d<6 zT=}ly%C~|0*3Sm6d|P;E?YHpA+#Bz&|HQlpSH3=6`S#(h^%KCA?*OiRL%8xC!j*3X zSH2^-@{QrjcMMm)3A}o#%Xb3zdM@7-u6(C(<(t8M>t_a6zBxR!_H%e-UceLc1zh=- zaOJy%`ww;Vt>DUc1y{Z`T=}ly%C~_l-wj;(ws7UUg)3k0i}u%l_;QzT4<6WjeYo=N z!r=3wUYm7x2W|mvH5~ge%_)u6$SU!uqe_ zrTH3O+c+C|Yv($;-!k*O^f4~?E!s!+yg2Vm_Sd;`@4=P34_EGexN;BRv0Zln*K-R) zxSm@$gzLG55!|!>M{wmH!+mQ%hAa03uG}YZ<(|To`xGA7bu+kfpTR?GpTi3~*HO6_ zkF)(8?Gx*#ge&(YT)9_p<-UR|_ZqI;*KpJxv$~My@4zD4P3dm@WQUUg_q`DvcH}y^B%l5_u-9sAFkX3 zcx&wkaOEDtmHQB`+#|ShAHh9)USbSa?qj%b?Gt!v=Q=9)(w>VuMf7R;23PJm zT)EHT%DsRq_XS+Jm+;WWxr8hC3a;E&aOGapt^YM#xi@g-zJV+E7Ovd4aOLiu+h6C( zy$4tBK0L5<9hG}v&r=4{~27l=Wyjdhb#92uG|-Jrx;=Pq?!yc7KD;y!;Fb9RuG~X-ZS99}1y}Ah zT)D5|%DsUr_YGXRw{YdYg)4XO{Qf#u?mf72_uz&8ui&j+cLmpTAZxgu1G$FlIgkxp&w<>)m3s@Hsv~TS1b7Q!2AH$V< z0$1)6xN=Y7dOqY7uIEE$a6KP#2G{c;bGV)lIfpCv0U9OSp2c;L3dk z*YhE3xN={^TYElaL$~u5o<76f?^}3lxqBD)*Ryi(!IirYSMGhdau48oZsY*2=SGHb zJvVX)*K;EyxSkt1f-CnJuIEOM;d*Xl0$1)6xN=Y7%6$sgb0agja-YF{d){CUFYH`L z-S3T_CyDmn!`<(Xm2l<0ge&(7uH08}bwjvvAHoxBAJOeRfyd8s_xl8%T0bdVxliHB zJ%eY~&kU~Ib9iCx=WzWVT>)>b{Q|DvqbuS1J-Q{`o_ANl^?P(HxPFhWhAa0qT)8)J z<-URI_vl)JCS2(H{?xN;xE zm3so$^Cu^8<(|To`xLI{PiAoCK7%Xw9Io8waOGaWmHPs&+)KD}U&57p1#j$JN97*c za|<_Uujf*>aOJ**D|heG{(4jHJ-BlB;mW-aSMC8^&!rr|m3s(R?nAhqOBunH`v|Vw zW4Ll3!DoeO>U&57p1y}AXxN@)I%6$!2 z?hU-LeSQO1?k!xoZ|Qno;+OBQTjkz^D|a8R-1~6l9>A6R0Iu9axN;xDm3stF>|96P z@4lXMi1vDpWeQjBQ@C=^;Chbb46fXBxSnGrk30Lk*xTohF!j=09 zuH0+5a$m!hdjnVQ8@O_B;mUmrSMJ{Hux{-{{gDdwOuH5Hv0X+IV`}_{q^D{%Zav#E# zdjwCco+G$&kKviMAHxgt1g__2PTv@}Ay1#Cfdk?PMeYkS(!p7eiT)D5{%Dsjw_cdI(H*n>?fh+eGuH3h9(|96P@9E9%e&3*dXmx1e%6$u0?%uWi^>+4LIJk26;b+f< zgP%PY4u1ArIJj~T;mUmoKYK15Jh0qHaOEDumHQa3+!MHRpTL!S3Rmt^xN^_vc3!|6 zJ3WS`&BzO~#_xbF8UT)Ag(Jx6W^ zSME7n&ykzM^&GhZuII=t;L5#(EB7T_&ylO(%6$b_?loMwui?tQfh+e7T)DS!<-Ub0 zckcx2*3JXCXU`uSzytk!9S>G$j4%6$n}?iJmh7q@~d_ZqI}(XHWn9$f?1^XN8k z<=(=T`fEyxN`U5%DoR)?g3o658%o@ge&(UT)B_nS6}h))Bk_BG5q`& zIG@13VeEVgf1~*f{*C5y`0z_zKMVL@kDM>ze`UUcKjhV}{TlunyY2@5G1ku({?eDb zetLK9=exG{1NgJ7{~`PZ<|Fv+=41HX<`ej1zu1ju3V)3G4E`mS;~f4x^9B5hc?qxW zyn=^!ySnIgeO`#Z)O}u9qkZ}&*P?-E<{Nl!-qP=J{cP#~-u-^BH{H)G{1481@Y>vm zhd<)l_u=i2IuGFSPdFdIv!8Sx!lVD>drsXY_i@WfpEfvy|B(cOnbw9l=51TV}-@X|bnSLS1QZJxlrKX&7vz$5b%o|#YK zxp@YU|HSn_gD2)WJlMGQb9ioEz)SN5-2YS8PYDmrm+;uUg6HNdcx7J0<3DrPUBeUe z2A-O4;F);~&&{{+!rZgt_u!4W5BL7J8-E`jmOC(Y*4p`+S<9eQ0$_;ia8t@b+K1`%$l}|LkA7{+DR4&({@PpRZSNeZH>g_W62E zzxiROUuQP(!h8cS&0Bb7zJ=H3p3PhHZOnV{*4&4CFLLAT!z1$mo|zBem3avFZgKq& z;l6nU56nmK&^(4m=3{tlp1@P{2|PDX;idT$UYTd`aOCDYgBRvGyfL4{qZhk=3V3P0 zfLG=vyf$CL8}ka@ny=vA7r61%aNm3l56l~QXx_s8uXOkC7M@sp?<@Ad?oG{m@XXwY z=jMHQVIIIs^8vgv58<`>5bnRk)h&W2<|BAv9>W{+F}yWT;NDB!btiD&JcS45Q+Q~e z!DI6oJT=eZx%nJkm=|#WWp4Zncwk<_6Z0j!GOysZ`3l~c*YMVS4fkH|#@WDq^9?*O zZ{eZ&79N>AHCtbA94D5Y68!1be}h8@Z!PFtFPJb zN9PUwS*~3R??2Y{q+A zYM;Yb_S~%!p4{W+zlOIzdc$ch8+c*oE!?+$`gYWM2*1tsGk~j~5U%kI;px}9aYpdk z#xa4nH$L!m{8PBDo59sj30M0iTac=qUJbk)x_NEk>36yN+P8VDp4B^DJ^S#i zaGt=o_H(}}Jb2NAPwO*-YrZ*L^P0m|hXStoF5uyZ-F&^7JD$x;_Z_@%&yxw@TIV5r z{3-6f7{TMft%osO^G)EI*95LQq;SnQhijY#d~N$r30M0HzO?6`ui)Xr)v<gu_sTl*HSdWK)W zKd;G+uAT{8c*Kl3e|AzhX&ush=JopyZE{1E| z1zh7_!dn~93ZDLq)gKdg@-@y<~4&C*1mvi zUJYFH^78v1Paob|{{whz;~CO_-;F<}+c%a~`d`B{8_x#rHEulKTleRy zJR-R6#}wZFi2L{{-2WfWGy1!n&*1rgc0Pw|JOx}iE#RtG4G-_QuOSnlIxdfy%4I-zJk^^*U z09y-$F#=)MEYB6@3m6<{JU}Ho%ea4?|r^UXQvuKr8{pL|669q{*!+xMqM;J)bBfNLB)8NW5oy8ej+SN$~b zs;nn7z_osT;EgZX@@Ii-JD32jamfMK`YQle|Es`jBI~D?*L%73rvdsck@Zvc)qV%` z>o2nFz4&d>`qh4y2CnrR053{?O#rWb*S5Dw;62eV0N3``0SqhM`qKs86Z;|Xn)ovS?*E7NKYn|(yjuP&@Zoq1 zT>U8muZsOS;4Sf|4!ke=E#T^pHy8C&Z=Ygv~4dCie z2e|qZ0`H6c0r2GaZTpFRGFsmB&#nJS;5shlfDdH7S^%#8%mL4f{W@@8{AmJjiGByT z`V+q+>VGU|*Z*nY>Q4aN`-Ls<1n`{rGl^XE3&6Giw18`S?g3YS2EZF)KlWGAa@EA2 z1n|D-r-5sH^1w4vUsd4QQ*3@U;3@g{i5kFL;!g*-mMa9_c-+Q$0KE1?X@{SRme&{k zB=Fv+tzHgzLh8K$T>Y5?o(!!&b>OWZSbv(pJK|3VxYm1I{L=YL>pcxz{Rx133(^jO zcO*WOzzgDk0l3De3B3B!UCcR#K36~0p8@D6#h=(`qVKeJ+Yqvo)dpk!1G(J|2}Z_XBv1qW&NoE*Z4Gnhho1CydeH`f&1I6KYifZU($aQ zEwA>MEO7N_5_nbYPXlj=KSkgz(XRp5_SplTlJUg5GwP@MlK?*VYg^tF@P5~}pA2yS zS5`j@T>Y5cv}3K1MZ7{1GxGV0?)tN`je3T_i)_X-|{5z_yLxuk;}R^16mc(w+39t z!8&jqj~c*rTxbHGpRnyY0X+LN+rLu4 zYohN1*Zo=nxQ>%O;OgH1xccw?UDQvt9|x}GN&yd^wB^bGuSvNAR$(V{31J^bb)(sw!8;C zE<6OD7TyOQzr@-Z0M82dW2vtH1;C zvjx2NZ?;?=;OciDxW+m5#c2D_{#M2x;4Se#1-v2pKJq_Uy9MCdPiw%{pC)kc8S76Q zc=9nD&o1z)==Xu^x+wjnXnCh4o>}1P&m{1s*q;U-f86?0ME*PLe+~H`tshwT~WaDDID0^Si>KXts- z`#&M*SGU@J=YKUChs;rOzvTsZ7WlNx%Q@is9w86BAhLdyzYqFaAKpJiTDz>^~Dr`p%{mI3|VuWUV5fomM*UVzttYaANDwY{}~cSP1t z^fLtg?60k#1K@?FHZI=RqVdV!VB28~cvg4{cv^TGxGy{lJfZh$fNPwmf#;u*I0J9o zYyF%9o)g{!9!kIPz8)=aT=ruL;5tubzY*2fddUILi>#koFM1wc0DZl8R|TGXUd9LD znr{nuM`Zofd^MgS=oiHP0C?vBX%BZr%iI5FX%E2t?^qrO-ukxX3E)-XDd5S6tbQ7J zTzD4vq|9qM;5z?K15Z9{=hGtaj>KUOctP|Vz_mT}f$O>@es?r(>Q4%}*v|m(i$4MI z^dGGMIpFF~4Y=+rTfo(yF7Sfb4}r(G%eVo&C;IVkM$4=IWPz(cdEn|#5qSDJTi!X~ zS@EY1ye0ZA;Ob8sctPeqUB9KZ~adKSATNAwVfA$t3PwV=fr*;c+a!)zO= zsQ)dg$2jnm%r9x+>gNP-PyFctSN#F-V7rZ5?0-c4Ns65W@SNzUfcJ!_foplIz}25R z@M+Kb(FC3sf7-x3(eDAT^{t)cKSs+nkbdCKX^ zfO}WleCxpVo?8>Rt{Ymwb^dMx*Lk!9T<5bcaGgJTz;zrCf$O-_2d?dV09?o4_H@^a%un5z~js09wYFc=+}U2fALyT|KrQ7oB-Yt`>7Y;nHS(b z^0c)-0eo8Wodn*Oe5Zk{pH<-g7Hhu^yz?>JK0Cnm{){K-wBM!w$=Znn*Lq3=?>uYu zGr+Ze)i1TL^*aIjO^pNaEpGt4EBQ_U_ocj(z}3$JaE)&hc;^$g-dn&m4n5$>6}J2X;QL=-;}H8+G(O4` zFTj()H4YizMaee+o|8CC09QZrz%>qa;JMpv92&qi4jtg?X9&El@d4fwKVuI>;}hS- z%1PkrXAXEE^K}8Z`ZEVS6#I4H{atK*HGvmIzXM$TiA%rN_CF#1_`vm^b^u)O|4#r{ z`#Ip+PbPtDyU7FBdYT5V@tOm!<5CT{j!S*u8t2%9(R$48YUKp*!mc*XDc}v!_mTg> z+9?3neN7Fx`qKpN#jKq+@S6D31)dZAK5#96dOliS^(PBl{h0*b5c|`><1rhbBJh^z z*MRG|?X{!+Xub*Hsoktz3V2rX%>egBKMP#T*#NHjwt?5hP8WDV@(qEvMBjTTS}x5u z2VC==2AsOj{2kdrhwPQP6l{S@(qBuL_Y^y^KAjwe7nF? zdszQM;PKsTyBYxZML+(}(Q;|NdElCF5qMqf%mMc$-#YM?=(m7tzRB-I{n30gz*Bo# zy#RP#@|^(gi+&!s=Gy_T`G&yjVrKxnD*49#CF*}m^pn6f-vV&WcMf=JFKf3Bye0WI zf%~H00j~Kbe-QOk=c6=m9rrT8b^P^#tNj4Dj#F9SI*v>L*M6P@uKjQlxb~AgaBaua zz_pzffNMJ_0@r#<|8VDV^ZzxPaAl858F<zqPyyyes8u09Sw7z?)*f3p}@{ zZC4@i^!_$q@2Ao7>iClZp8F@efAoQe8h_yWem@Uf<68i(<(dONA%50@_oZA-;4RVb z0N4AUv44w}H{G`7iUZg8J{jP>Eml7OuIHRt9!LC>q>z>6t+Zzl;{>nj61et@+b0QdH`?QjBkLG<&$hyDYfkoV3#;OgH1 zxW=c@i?z_q=_ABpCx?J5mi{Rx0K#Qp^E_=t_?B=Bm& z=2rl&ZO6JKY8E-@uv!0{iy>_9%St| zfp^58Ht>Sz_ke4CCI2H@F0C&gxcW1JTF zqW)LKege7plLFoseIK~`Qvj~ot$%Ic9r33Nye9g6;ObBM=h5=2KUv`F z&m{1^*q;XO?PKe!2t0d;&94Sr{pkT$f4pBr{ZxMvz-wYZ1w1MKWPp2zTDw``>Q5E8 z`lI*mbseStv_U^B_PfA+@h1e{5Pk3QXnA!!_kqVgDSzJyxObRMp9k&>F928n=YZ!# zzYe@0{x^YZzHQ(IvC{#r>m@&omRHBO0Jx6(S>QVUP5{?&Fb7=6qeX@+?PuF(3wZ0*wuEiq@iQ!sZ;O^UbE&j*;JQCb1K0lJ1K0I=7I;o%{nYrY z{XFOwMAlE$SNm1aSAS~2Rlk8;&e#U_(Mb=N%&%e^v zM;i3?@5=hXvyyKCxbB-;z_tB!fw#nt|LbUbn3jH>1+I1`f%^y8I24etwk0eAulkmE zfEQ()>;cz&2f*`^Z|*ly|C{1}1Nd;f1)e<8rtbo8iTx0`e~i^10Iv!680aw3kz=!?=FN!~H;DrNi`|JYmtN*}tU7CI}>Zh(tbHLTV0&w+n z4!FP4+N}fci=R#4Rncz)j~{F8bdXE@yTEIg+K9)Vik2&XiRE$NlTt4}a4lyJxR!Ss zcv}1{0`DYjz03h`h<*dO_M;~7Y|i@M2VNBalTSy>o0Rj+6mVUKq=Dz2wdpg!Yr+HI z8kb4n+8_14sFb=@AyjkFJS)b*AYxxVnwf)q9C&lkN@U+Mc;Ob`+xYkz-xcc7%uJtki-j+DW zeiw~fU+N_RJbAp;O9R*acpkXkd#M6ff9k;VV!sJI`4Zbs+Q2)a-vh4mLQ>j`wg;UT zv>ho|edM9(I7&rG19L`y%V-&`&9ELiSov;9eDo+o0Hyy(|omDA?Qzwp9A0>DOc}iyJs0&~$2}jo`k4c+aVr9^9&Gc~`b7UzvTjm7eUkMf1AN6B zt(^dPRrFiH)t@f#+RLr|5crG4{s4GG^yAM*hWwOk?a{wcPe;!C3CRXSqnO{<|to;MGySr6crtbnjSL!_kuJ*lU(ekRFK5(t~3E&;^vw&R2;W^-%z79Mt<9QRf+V22YKjX`z z{>NlKO##>Qu`Fk_fecuI&pF^~zX4qR>;u>K8IymP zOyi^He){i~DOW%1ps(qhz%Q15)CR8hd%)GtWGoubuEa9~JiAKb30(c02CnIgz^@WN z=YXsI25|MW540=U}GBbRkd1Gv_E8@T>mpdN7b za{zppe)nj3^U^*Oz}0>lxW*+9T>UHpubyh_y#`$UYy#KxZQyrGJiEZvejm8{ncgE> zUiC8ou7CF?2VDJ}2CnIg!0*xa30&;u>NF94pCaX$-O``rZa zo{XD0;5vRy0@v{(4_w>ZG;lo^C;->~Pz0{+at^rK_u|od46e3v5xDACk;{I(2D~A% zeri9}^*|f+vxnLC@9z`!N9VgN@SMo{srGgMmcwY{a~-{(<3-zeV) z4}d2hw;EaC+0gPy;K93Wd31lT_6suZwLo9T)h=*N9|GSXehz@E{rG;-c;-dcPxVLh zErNdUVmqGC0dE~;+jAXwU-VnRbsW}v5SnlD)z*Gm{=H4*>Q4Y%(@y}uS>iAWT%&z_I=*E^!EeXGK2; zT;rhsj;q@Dd~3f0`WlB2xTYTf|9go;?8VVItNkSKg2?)*{%F2)px>8r)qxiz4o%?R zrBW{78VCLNb2Q(Y#KD(;S4X+}GXY%FPXcdB9HxP*{VMRj$oh%-#$FPQXHCkL0N#=~ zq<}X>-v_Sa)f{ktwT)W?xW=IkT+?@fe@o&J0$2Oq!O?Q%MAlD?!!+n;|HArN1Rj5> z9Uta^=S05&d>HpbqW<(G4oTn|hYawT$N}*GDRGzpuJ-f5J0j~R#vufK?=3bC1K>G{ zL+sFKx#FUq1g>$I23|PR+OGoFIMjh_`X=xnOB~w3)qW4SFaO@XeqtOZa5c%(o5txt#U0 z3%oCJ2!ZEC-#a|oPIP?GzpJYGwj>UD(APK=fou9X;J=YL)Pbx07VzW|)<6AJe>C5W zJXaontBpedJbjEEA0~h&ML!Q*dyf9F#VCyI6o_KNB~#+Y2a0n z^;7-PeCwd!l5#bH=Oqqp;2qKL0oV4R_xd$oZ_LIadsMVs>dz!_O+O8M#e}VwB5<`| zLw>Z)&y!E}NApbp&tGQ!OaX6595TQQqMrq>ajyffNgP_h)t@eKO&5%iOn+c?Yt?@Ju&z|*4N0!E`VFGwh^wYpK4*LCC&9^6UsDZx5p$S~mw}HP@;?M=I z_WQuID{Xo7Q~l9=C*`^F!WFi@rjbh=iomO)Ujwdj7yvJvZSBX8jmBC1NdedN8Q>X- zLjYXu=YVT}XaY|L)}Ib=^(O?b=?B2i6Mteai8F9eTl^^kSNk>K-tpEC{nYlU`6lGK^7PxR zpDExiX}1~RzUXIxYrCxj_s+HUTfo(yE^tjB0^cBU7ywuM@e`u)&x@>|T3*e!2>LxK z*Bo$vr5(rW!26=#0;E+JV`be1JSX}!;QF4Z2VDIb0PjiM;wMMzMg2?x*Yp|SUy!&3z}0>Z zcuV9OaP?E4W8Au+?@ijcg}|#4w*l~^=*M3kEw9#77P$H|3B0hz=34-+ahn6K>FdDn zlDIX2tNjk}^eNWwxO{4S)K7h`T>S|^za?>)0N#_hO(GZl0&tC63%L5z1)dzYaq9zD zKVzfOdeQU=;9DeaDd1|~2VN7o09^gl=NPvp=oj8${ci(Lzs&a2F7TS@_knBN(yxe? zSN#cqwQ57R?sYcb4seZI2wc+-fIlp8i)EtqrS_A+3nJ%$tDpK@q}fxdUO z^}i0hCvj^6Pl|pAxW+BMD(b)blLGF&-sbBAS3f6!Yx+sxk4xO9fvf#0@V>|$;OeJ7 z$GF8#jh3q=aYz97kF)(W1-vKvK5&g&0l4}z2fQY6YXH}{wSjB;F7T%$ZXs~B@0}Jc zZ%$+%xcaHjF>ceKUwEgj_agAB#BC0EP4pYUwVwLG)t}g_qW=3?n{N`h#w`O}(+9w} zOWY=atNlFij>rw*>Zd-(xP_qazsveR0N#_h#ZHfwHz)c@;2O6aaP?;zcu(S11+HO+33S9lv=NPv(=(i*eUEl?YTL`=- z`ko&xuhx?fT>Y52z}YJAksByja71HAAa z>wf^eBXOGmUK9O1aE)67xcbuu-jcZWfUBPa;KTH1M(gWDiCY4=+D`+oikt_oe(H0L zr}|R|eLrvG)&!nBLBInnO{*M6FOO|)F7ILYr?ExcWH>T+>ejKTYCR1g`dL zz`e7qe?8#pr#{EHB_y44@4eRl6!5&nEdx9$`dQ#wPgUURPaU}T2AgjSxW=suT+@fZ z&z86ifUEuZShODVB4>fCpZZ+mqy7{@za?>)LoRWv1Mi7`3%Is7@3m1s)t?0Ln#3&) zT>T7yYx)V`7fReFfvf!j@Seym;OeJ7$G8nZzi^GM_t@Fd^2SfJ{WJl*Ci-dM8n--f z^`{8jUu*NN0oS-Sfou9U@V7|Zy1>^h z$VI;fT;tXQuKo;w_atudbE5U7ex`tH`V8=O61M=j+Rp*kepmypel~#@-e}{~0j_?A zz%~5<_(t(Fc5bx1YCj2F+kFnW`Z*0e`6laU6}b9Y2d?Rxz&|5?wt=ht9&l}E$@8M+ zQa>}mTjFOHxcWH>T+>ej|GM~D1g`dLz`ZrrzaDV)Q=emhNk}^7-Z~rS6!3J~jx!nH zNzu;&*ZxukuKv`4=O%2vE#MlrE^tjB0)I&2HUO^n!Neg|2K)-ByhD~0NxY11zi2q z=NPvE=ohA}|FPFc%bPt}<~86o(N6={xaEPXKSkg*iCYc0#;pll)3<^5C2n2dYQK+M z-ZQ1M(ekRF0dQaLz2|_dpVPoKeG&L>7u$Hw0ayDC;QBr;e}2?Y{eEHrxZY2$0@uI8 zPy^l(xdGghaYmnO`_b=rgrMJ%d3*r;<~!`)#q}pIpA8Z zJn)*x1>kWR2lP3Xs|or&i9;LsoRq5rJh`VWR~L9+$`!vb8V4;`;stmbxR%!ko)AH%mHsmd27IHQrA-+I`@9&pQCF_nx!B^&ap9aJ?6s1FrW(CxPp|$vkkqM>q{!@6{E6>pim~aJ_d` z1+Mpy=78&cpc-(!ms1C>_hTBs^}a|GxZa;=0oVHkZQ%O8yaQa{2X}$%`_3M4eV-Qs z*Y{O@;QBsh09@ZUcx$8Wd3c@J_uD>j z-A@L%c!PyaoJ2!n?qm!u!B4I?wtOdsEcUheSUK{A0p1z&{}Chb-`t@JZkw67 zqw5ghWy!Yzyd}I1{C43XaQ!}}HxVuG%C$BQ8Q`1WV7U)mzkiwquHO^P1J}Q&T?MY| zv?lP{Dw}WiqNtx)`MYlg;QDvGi@;Ssyf|t{pi8I)U&Q*JMR|%f%k>ifUBR$w?^}A-(=&K0$%%&>r~k?F2JnXPCh(5%7V!8FterOSn(z+rzVI&a+V_Figa^Po z!n4T#-P)M|?)}X29B^OwB=EfOJn)9_Y2dk@wO;_94lOSN_ZKX$0?!Md16~zg1Frv` zP93=ZUFZhz{8pQ96L|JlmbZZGy0HzsCi)%V`QKPOUEo#WJ>a>%)enJZpRl|SydZo4 zJo}{8_pXSx|MXLq$AIhK+m8d+zxSR1u77tr3B0Q7WZ=49N(0Y5YyHUpuL<{o7v%3a z2f#af+j3@s*G4R#0NxUw1Ktxp2|OORcJjc}!l!{}g%^P5g%^?UYwcHoSB1|3ZwRje z?+C90?+b4LkH5&~+XU_lZvoE>Zv(Fi?*RAY{HqJRCg(3b;4R@H@V@Xq@VK0h41lMF zdvCMl8?N*9d;z%bALGDvpOOHs`;jE@hV184z&pazz&+XLXMm@L`@nO;1K?HRS>P?< z6TthzbHI~wjxY&4D?AUpAbc8lLwEsrPk0fyC;R*=@TBlL;ChNeA?lsIK1HSQypG)_zxXE z=kTvOyyozn!|M*e!r={vf8OCuhri9?Er(z2@V3K0=J1ZgKjZMO!~e$NUctth{}t{f z4v#r}sl($AU*_F^Z}PdS|HSpS!Hxc!&G?URhdbu8v5zQgT_pVbc>Zcnr< z&pKS*2%85J4&TeFnx8p`@9pqOhua9+hk1wFo@4p6!}oFQ6db;9Db0)+YWz;!#fT?#Nl0sAL{U)!w++K=F|uhk9D~3 z@RvC}aQN{K&pP}Bhfg^CM2F`bo_6@8!%uQ}-r*-ZeA?kJcX+|!qYf`R{1pzbI{cLm zpL2M|;WdY^a(Lb0r#Zag@Y5aMboi?s-g5XE4sSc$cX-F)s~z5T_?ZsxIs7#a4;_A% z!}|^&bNImFuXVV0<6`?i+u<>X2M&)r{2YfT9Dc6DlMX-6;VFl&ad_I{;||X_{B;iZ z9sYWU2M*6VJnQiD9X{dk3ml$v_=OIibod(_o_F|Khfh2FjSeq3{7nuoI()+6Rfk{X z@HvNH?C_ey-|XJl@1Rb z{&t7=9X{#sfy3Y7aBpU@{a@wqn8V-c@VLX@+mUuPdNO24$nFKI)_g>eA?l8hySI+ryYL1!wU|7zr%|T|A51* z4qxx^IfsAH;WdZf;PAS`3l48Me1pTA4!_aiEr-uIyzTIt9NuyGti!tw|B%Cb4*#&j zLx&d~-gkJ(;RADRzunNfu6y~cs1TzoBzGaHLee~Oew;%l-`Z;o#PrtEjb{Gr2?exE+?`L@l zDKB)4you$dEVqpOHI|pL+%WPNSzgX^&B%AM%txdPRU_ZQ@-8eFjC>2ryi8lj8+jwk zF_v>izLDkKSk4;xdX{%***EevEb~$5LfXhzvCK!H3rQni#`0b)$Ble3%X_oz8TkU1 zd9$?8f1be6=dv7Uxo6}vS>~h7g^rO=WqDtgTSh*aa?kp!*&KY?r%P(d*YvgASC7F*T7knc>$?{8BP8<1`Eb}Xb zg`|-mW%&@6<3@g%Wj=~r@QnODmJegO|3@zWw^>fI+%xk1EFaEt$H<#lK7!?zk-x_B zkt{ci{6&_JV!3AIJ6Yx<#f7So?_l|*EEkM?3(Lo_oHz1DmQyU}jC>=@D_PDO`FfU* zW!X3KH7xTH;X>NTSFwB?%Sj_&#`5tj$Ble3%O|kx8TkU1Ph`3OoT-17(=7Lld?w3$ z6u8ha@~JGJ%yP@fC$s!=mK#PsmgQ4et{M3VmPc8x8u=iWU%_(0$osPVN|y6R-ks$P z%Q+)2WqB3LStCDt2+60i>>K$>mQQ0jZRB6F{3@1{Mt+p#(^-xi`C*p%sBghD^7mLi zgXR7oO#QR$v)nWC{VcC$xntx_ET748%gA42`86yzjQmBG&tkb|*FZsdnq=A*6!&&c0n`7JE>e{brasYQC`3RP$SgsoRAeP_9a>2;^vV0xO zc_Z)6@-)jiBQIt7FImnS`Pr9{d_Bv)k)LGw{Vb=A{7aTUz;e>akFva;<+za_W|@zY z7Ca+=kL4R!?*GozKg$J{dq%#W2rA7(jkhMEBOk=_Cs-~R`Ir0eAUR4*h&Z6|xIh1(*tfOLkvshWN? zO7i0rXGxFW{tNp!9aP?M)a1QB(KV&{@Yy|=m{b`~<#U37eWwIJ`;ASIT~k_j)I?Ca zv0ST$I;KLzUqQsSlfZrgh!hZQKD_bvG({dXAs(aZQ_ z0e3ET7Un5PPB1h4@&FF)cQeq8ZFI&(paAa`fu&vq-Vn7NrcL4NgNwk zZx+jE?UQP0iqdnkwFB3Oi2ce`e3MU=75=Kblq~LO?aHdr->|JlTE-=c3AsJCZRAa@ zk(FZ|PE-zJrSW!9W;a_;jl{>>PmaXRZ)>*&mGzyVw3&B4;S--^x7YVaQez!T+h8sJ zG2RS$_zcQMje}U{aMF!V`fue}mG$_?_+0oATH%YHakn%($(GMHmN)b79Md8vFO*kACdj-cdW)J7ouZ-*N3x-tlwT*3RvvcCeS( z!5+1PMgPe2_&Eo^puOXEu=lDR?EQd3*QIc_DV)@exEb?*;{(#9aPC84AIcn$ef;Gv zp%U%mQx{y+A)of~_oS8wEsE-%t9qyXnLG7(pMIBpr#ZimD!rZ&Eh#{xYwg1?+4 zQnFHvCDOLio^J1x{zT&owHG$c2FYqT`bBO^2;%esOTrlH%C*phW$? zG!?EXjZr%r@2)A0cQ%e~KV^G;$<)%VtH?%|;?<;2ZiX%Tr2fb4hhwomq@$AZdU`t5 z3QAkfDUr0c9VRFOWaFqMlzY~7cjPcTUd?RFvAkcD-sIyGuh~VFhADVm!DKttX|2}8IRrh#*4Gl+YxG9!; z!91m+toGQCoFmQf{&RMrb%`_n+47iSb!rfP{iW@pkmH8f)`26PzzBsG>nY3gYj zPU$}iKQ{|*;7>g>_SBMf`vjMdJzW}mjH>!E@+sUpLKQvWCSNh_IwUcq31{YkNl3moZ%J6p8o(XQ_OG>mZ_7Z!^f5{VZ3qddDE@5`GYx`52*i{^}vo@Z)W{- z-pFmO|E=!#VhVhD>^a-{q<#M1+TIS~_BMT?+uk<4eW&e>>9D_7Iy<(vYv{D*Pqw%7 zkNz*WH>baEy;@q{_r{$5?zFc7wYR53KG0fhZ~Jn4BWH%~Yio>J8qYkYrSaOvHZ>hT zhVAR5*37G;?JFp+qV{!4?0=zs@mi1CD!1|Aw6XrRyHn;gI#IhvH=?bbI*n;BIyRdY zzSH$ymiybz<_;Q#2mjkGc%BX(jq@)!e1zBa)&NAC7U?jHZms`kjOLp2)asisD=NAfPLwBQGOF*D-{ooCv^_g_cPKht(>^KVPVh3C&`nrrUTagq z$r`OPE2AGjBIezf;(}jrFcti<+gF(VwD^-|f9A)YqvziI7@dod$`drsn1O1=!sCRu z(*M!K*bjfa$R8qZi<=3``B?aCl1t>|$pWEIkZQ-KLgv+jb6RCAc?Gp!5m%e<@Vz8vWy+?(iP;v6n2M^c6B)Kp@ z`kNK%+;`a1^j2?ym+j(kliA_q{~-h_qoru#hiUt~a3rt$XC6pXld6o)kwQ?}>#eM} ziqdZ4u&r*sn6vtF&22D|`N_0a>K}b?9WO&dN--e+9vwDtxJ=U@nc;F<>c=+H0JDAM z?y>Esw}`IaXMSv(Jt7#}Mzzx4dJIMOxxe6g@nh6iwr^Nqz2NePM($o7D^ZXu^q*Zs zQ!eBE@@~AUrfnPL*9yuRs<7}1Y9ppH=18+`Yq-M=_DJi+6tT6moYmwttUt2$>ztQj9>dI@w@M@}DJ6JFF@5S-8Pvh(0e|dbR z`9GSUi6?hs@_|FR*uPJA`}daK(m&P5dDx=pzHlG^>Y>^#Odt1dU7_po^iKNs;nXOk ze=m^bVgKH3k^i&Jk)mb$_ullV3_bkR_wBTYA8GJ^+QT1s(awALV~1!_Ob`F_4rki+rz*8DYu8)@$o;O4~F$^`u{7X zszW<5?M}7ECok0d%^+48{cTdFBGax<=8nHF6_MKYPiUMb*M2|>_hr~M+pbSyl@lYb zEw)$NzA1+@ymdK~ml+#qwDh*G7Q@0I_`4WAvqHf+mM@?nVhfUI;^i}w$7 z+7y&-YxA#_%{~4oZEn&>$fs*T+5TQM=O&wNg1d}z>HhF*$z{}L=Vv>l&dzP!jW*|; z4-c`%R(KdCEE|QHaLKyf)! z`A#D!k-xO1d|KX)id!ejfLUQxx8kOrg?9MR!q0Hf|=jb$ChNVK7JQ7JDR0{Ca>D$b2j<42UD^JxkGsE+=I*Mz+`?4br`CS*w%Lw zpQ8q`6R{eI?y2og}@1wT+nvHmYrk@{jfhy~J zbiPm;D{ke&6)2mcISG}(l-E*0_6X7ayQQ)3m>8@Y`_4LAEK=eR{K7qbAI{$tQCjcLw@jH=?YeGHa){=KOn5LAl6o$0 z^N0N{BuxX->^LzHP4{aj3vRA$33%OCAY|IpDK?`r^y}avA?FG^I3#e z);nKj3P)+p7WTpAG#c2!gIpM{PtAD{8KLvuf2IO)CpQa^#jWMRH1bsT|KN*Fh0NbO zN*>>nq#xl{np}++rckzj^4@n?_NfEtF*Vv2m4VFKoyA})`DkV_%9SG%DZf3Rvi`iB z{V}!|7- z*0;h>)2j(OEv3c5Ot_RgRb~IH=fw+3 z#n5Zt-UXy?QZET-R{yby5c9d(Db;&@z&dz@^&}Nb@G`lwB4oCHY&}YChOIu*1eqf zJ%@ANv5j11>%;KGS90UvfVHK5Izf3g*HhQ7z zr@?~;eE#IME)|!8%q#8DTWO_zpDFHK;($odAQp{BK;Eyu#{}^rs$SZxb*VPURdS{>x(n$p z>V>Z)jp+E2Nn;`<8liymZ5L8F~p7Uh(iU&rCG*wrs3l9)GSFv&#Up3ZX2% zPYvz9Bze9m!PE9xv{u|eo3LGJF3GZiBh|ohVqnX{E*lW|Md%UjaoklK={pPy8IMbievrn{0+&K0d z%Fr z4W0cLZuUtcn^NrTtJT@KcilS9>=4Z?JB-4<8y@N}X0<0|70rBUH1lOmuJB>z*bV>U+6Bg>++>r54LeQkmGO+B@K_Ki!Kz0g=IW9S4Q_9T3E#vZXgSbho^4; z^{Ks3>y}jujabk-*S?8*XXgyJcOLPPo%PNySKQwD^M4%n&I@TF@AS@7xOcvOR(j|A zPS(!xU+`(Aqtte!EyG#D-Gb8aJ zPVe)QBk_s!$jVC_BP-X^OQ`WGJuXln`ds|*=q+?kGy4HDK&`@iaQ6NDTTs5sWLP$q z!+$t#DGvcF7M`TymW^_03oQ#~e!sLhdl)5{Ixr~DvJ+R%OdnuRyzGOG=CSFCw3DI9 zWVU7J+IOEw^<9}N4CmTIXvcZaN^)WKJxLk`!gnpuR_jK}Pb_c9kog;?-d^6!zLux9 zk@qxLjrYRWkg3w_I-)b1`KP!3u)sQQu26)_9^j$kWk$p5iOF(>)k`s3qM6o`k|~-! z!?5L<$#^4`uaH+kxx(cmJEX-gbZ0j6Pw##2Et_Aq|39uvjT6|Vcanm&eVR#f?Ve@x zX|tKx%+Jx;H-5`H%g?NZp|b|Xs0~#{lXlm+a4@yQBgwl>CUDJDIB;+Hh+QF@`q(hN zoDAJCbk%%OEgq>9nYcS*Yp}H*5Od`r-q83yAHCv69-LjUQSV= zeeZX8lfgrs1m`>s&MPaC;Kazx4O6G@7@XI$SG2}9Wh+%KA-%HsNhePb1yOp&-*d^j z)jL`mjar&8miQ;l>JR#RN_QGIK5KljcO6QaJMCTkVB;+R+)3~9uy@@@`zh&NS8^Oi zXl=c46ir~_eYwKDiuSWv`WX49e*o~;^eDj~j(QcYbc*%Sq=`^=nmbmW`gJ!|A{UOv8twsQ9!K+o?vihiuVhYK72J52*rDaNbP zgNtvqXcsg?YX)gMALq8S?EGb_8a{q3m8^1l;SW^GpYWc7U&e3tOxac(WXgu`9#tQzh`C8NXt zC+T$h88ay^S$EL<>?!ofxKJ^_QhVoVY3o7KZD-S_GLxqOHHefdBd zth^>yV2_siR7yVRps0>szq=_<{2NrBLkXEhzSI|OReAYmw(>X8?{dC0vn@}1mO33x zmDkowW8a`VZ{;caIo3R<^enA6XwNa8pouuX#@y!MH{rCF7^95WnhPCf!^4{tS*Mig zB9&eH^k@y#Swkl&Ys#0>euh>b6R|a=csTY|s=%2C@;iS&X!i589jBR}x9jt?Dd75( z3mUxtFP$Bywa6gciy!a`K?z{Rr{Nyu9XEWXdzF(vJ)It+EXpM zzj*$W9mbdapC9XyAzKmVEPx%NW#(zCwRQq!AC8zUt?F5%lZY%m`WYy6yd!=(p9UTN3|#sdA?w8lF0EB!a#43@2? znDJtMJ^e?o#Q07zy{_yKY>`rn9PArKa{IcaTWKm`8-9X4T6hO{QMO_f=?sHg4?iEL zbhPm2E@+xc^hT1#KR%3?ZAG-c-^hjA`Td);A{8+tSag+`G=i(iq?v=SS2D|p%tPfblz z_oQRgaO^n~{;qM8x((kb<7;nZ;X!Z7j!Eak*Kk11DbSAX%bs_Sq*i?JpJ;2cl1!ym zTyB5uQ1j`pFg{Lo?&Dv=5=&f%{K}elYjmP(=J|V!-f82l(%7w2bf0FbNWON=yO!{J z8h{9w$8M!H%hd7opnk8<*4|HFN-P2ZwnH~i2H z^>TN=o22@tMnTcxH`bp&$XMyw@rMrHWcPI|`L z|IOdiP)#oiHWKC|ak{|A7g4CHP1oUW!2LShI2InYWaRGl#-;qx+O182rSo9YT}moF zDiobXX@7{shrBi8shv?MGIlVc3LAvWOzzy-hH)8=ro;QMG+)qJC>Mu4`yCmeYZz0% zoB73(@MfBKrJK3s=lpxNe(0S0Y#JDN_~rg@8gzKl_rfDg)$@rtWln$T;7?r9)806kK`NNgCaa zW51(-&OEXtyp7I7?%X@ru)gilL^E;= zHL9;}9Q&%V$ulX9#uR_L%o)6FZI|kQSh5XizgpFhKCT@H2%7d@rm^%y)jy=v1;}Fmgy!P?%2s;i?qj}u4l%-o! z^t>Bh#o^(3uSEADX4ZGSb+kX{s}a=cjis$r+0;VLTp|sDubkXd=3(uO4-6Z^E>@Qs z!$G8HZ#>-0I%R4si!s#lCAl-sk3G#}TY2nh6Pc&Uok5xJQ11Vk_fu;;iB1d2F&gfu zsO%I^>)Oi~%NkjMsQv!~@q3gH)M!ro@5XPbw?q84U%!+1JxpiZPW;YW|KEt;z3-#= zJyHGd$1lzG!}nS3@{g}iPO)n0oUPtvnfS3Pz zEPgHxn>+>4U`bPwJuNxy+!$SLo}w2yd~`}D;WVj)r~VzUpB^iZJ;ozHk5k(>j_cq* zPlNyA)TE5@jef!`2sWORC_F+dgNMx3NIR~Xdz3z|M``83brw#2ZmH)!bLV?*zdW9V zdzcC_MUF?-7gJPT(y6TAQ%+jY49vTJa)}mXFExosg9YMf$4L;(mz2wz%HoAvt^zXYm5-d-pyVdGIIKKYzQUzV9(?VTUi-GMeZ!F3O=!z>4qC5KU!=#pA|gZ+Id{k{ zk9y&rcP{m|zKY(+@(I=C?@dXz*d^FkDVy+Z{-A#Af55IT>lG+rFcZQhjHuhF94I=D3PckP3<@00blw;#`8+1*XS|QmW zbt+^(A1TIS{&WedoZ$<VpzlJ^_Z7Ii%6KULI_oixhqJ#T zr?>Q$1(j2Ly9e6kH+JeFk7>-%r~CQTbH7AKeWr8%iTP~9wm5G?Ot#|#x`O|gDX%zt z49$ce;8TXd%=B^I$fsKtZ8Q(e0mx6ySqu$w2lOcun#wpV9AWcG3Cq(dPEVmo+Rtnv z{N;Vd*B-UXo;UK553`N=F?!=|K0A`MLyPy``U#uLPtq|1RVB4Ht`>T&K)-kCcap~k zW$(1r$MODotX=l^G#5XtcE@ZEVl`S1((OQR)7xpw8NPoVy({?)W!|OCV^RP%Yfg-V zPX@pHJ)PIk1&bwNfzNDsJHmTW`redvjmPz=Zn%t-^6HR}9ACiyk;><2fl0G{ zlIt_n_C`MRFzwJ;GCr4P6K3f_U&5lVc!e+D#F^71ZLwYZ%u$XtPEih)&phJOmvMei z74=d|Hfg&q}xR{&(zlDnQYcZhnlDvr;2) zzU_IM`QqnDrDC5I=vm%4Yd=b}=7gR1Hl>PrIYNWRiR8M$SGN*WeJ!f0I#*R}>P2L} z6DOXIY%INDqqZL==ire>E)7uJC{e^|g*n^q%MH<@9r{+r= zyRqAs6lZrOypF$QPz+|K>3D|QEwhd0r-{Q&c0pC7TA}_t+c#%(yt}Oo_*Ys0%$#mi z?4zq&DLH$i`13YxyhfkYskvT*3?<_`mKK|FJz6f`N?%NYhOfCIjo!Zey4HM-0`Fszn5Zcu(()`%{=m)S$Arp zhRMVvYVxm?h+4|5!HbC=T26U@HA-bp$Oo2i+Qq6ucX(&v0DqlKa3Ev)z&QrtLx`*24-`&Ck-b(z*2z3AtfW4h7& zGpU2`Z=sqwE=G+NYI9IY}cv8l48X=O&aTrtTjqYHnfW&9Mo^<^5< z=>^ID<|QHxq*sr3Q>KZ|PI7ZA+mF(0)nrZ`k$N1JmOB%_Nx6iSs4dd;Vtyqrb40c# z=4U79liCzN;a}wm8MKxvtVdrYpw?xwpqhNhH#Nx}v0#hJ-K%JeIx_P*9>-DJq^am| zmkLEe8}<|5rljsu3CypipJeG*r=MIxqUk5h>CT4L+{|gi%kSWR!Ww1slfphlcXKsl zw(+aPt$JZE3Ier7<7l~JT(68i{YkC#FL9-R^WCOln-G*MrsS2;&QRxztn+cwk&LJ{ zaWIFiiVDbKNgH>~7?|N-sXe}jQW&fup|?)98cd4hVv3Zc;J4ETYl?ZF2h{DRcN(Q~ z#XPT!o;Y;yo9y6|?=pojS(hs&*UIP~L!G->=YNt8dFxK0bpB_i(}w9AMdMMWz#r8A z=QK>8C)_eB$`&noLZUH+{|gi zKhk?st5G(3+{)=*i5+(kXTNQn9lv4C5QQ}|a2^qAODy(OtwAtolJv$COqpG7ZE3!&j7^j_-{dNm) zwP`uC;Q?L`n%j!o2D{Rbwb!>kK`r4}D%2)kNv&?aiQ7Z#s^Rx%k}t46E!g$xm5;H< zY(26*EztUOk6&|GXp#RX)~DwEFTY2l!&iC_OiQjBsW)heSX-yxcFdEzGwU04sNGm% zw(ShesVkq@((q5Oj?IRWSNy!G;G=E#bsu*NyTatPr`Z$fyEoc8+s#iaH2YP4;bISi zIbN;sY*X9gbNts7Mo#dimS0cTH%_86hugREvXqWBO&9BIy|clqt*!Kh$J^CMclQ%L z-z7I`$HlJN4O^FrL5$p{k%gzpkTwDK3sHDm`HkCXzs2t?HocmDgg<%*-j9vj#XenD zPOui8fzy4CM@=PBS$WI9i64aT+Qzj*5&IMGuc_Nj(SGC?%dMH~tr@9nYE4@nT~76U zq_O1I^WuIpRJ7))EdQ?~G?!Nt53yC%=}HALYT~4NLgPIdQg~BqJ?y zl=}2oYwJDMHtkmKv1L&E4Qh_ui_CWg=<7A(1bDARH^k{RMrm!;-VmprGIXgXN$S*s zuRDh7mb+1v6!-!4&ig58H(0qvZmt%7PiwK)lH+xHT%-AD;bZm`V2k++Oq+g4i?r~x zOUy|_(>OrieBFskf>fybXh0a=KkdJS>Vs~l>Py5gerzerHIlR3?(blEevD4AS&#gq zEN4b8|84b^ePvH`|+;WphiDhV03o z)6<#3ifgZ-yH!SD+gl!4PD@O=x5+p0_yQ+s=Tw`QwMM8+kv3&Vf9Q#w=bIkqQQzJA zS~6!9M*pcwBQ=fA-lj(>Jgb}L74*Npjpu#IarDli$|H*^UndoEn6K=O-Mnxhc`$D_ zcUQCsf7Rw@`uUMT>le-pU&dHQTn=(DkTbW-~9JY0q~UOJ%#5<_oPi4e0g| zAE*VT%|1u2LZedYt~C9+iHhk3bd${B3SYsbs>+fS9%o$H%v!WF<8+I~rnmaX{~hfh zSDGctyqW&(6ikQArMps`e$Rc_3pYLG+n}cze)<)1DJUBsNQtd)vMs8@E1mGGrU=H+ z&_*Td1NEmcG*%=JW0>mF7IAGa{I+>&%T_jpqQ5uBVW9Gd5_A9f2}Qv450j=c`nihskANDq^pCqQGyTJ6J$mC%XsctUzpdVrTk-trIQK(o=L23>Rqo>Ir6w1$CH{Bi zsWI{IWQ`T(%^r~}kZ#12$F?6&({HvPucP1iDH-a}uVkpthQ4N7wquACJeyOG6+UJZ zOs_+w&C|}$G2%BM(;6CZZn0T!zl7zJCq4@xRPy3do!=OO!Wtq z+qeaq!S8W)xU%_8bXAAC*ltvB;W=f~>s~ilM6a-jweEdCm2(sS2$PGH&H>+l?<_z0 z9zWT|d9q=iH~07c6+b+aehU{i8vAT4*f9T5s@Z$_lzP+kobo&NA!kmGvyOG@wJ*T` zNZg!2{UslARyMm{7hWLEf6yPR6xB!`|Dd)G+|kx4j;)#bD>Pk_ef~Jvo1YEHWs=B= zS>ydo>k1mEGDKO4MgpJ9G(XFK+SKUL28+omLq=vMC^j^v@M9V&Sb5{}SaJ45D;rG1 z4@o0;8(5nC4zFGveuQ+?3Yp*r5ckPALZjD}rH7G4V+j!Fown#4_u*YO z$v#ToU$+`%qi0&)_o-yi@^&FTXkmwQ`gc6N=nEZ{vH77NMUq@UZY5d#;78;K>u)l4 zb~S#mMtPQh8b3yN^y7mc-ocO6?8hTdxqeKt`Jo?ql3YJNK(hG3kH`9EK=$do z0VLD?Yx-&Ypg%{Wh1VhFnGfyYM~?lt$nj%-mj9?PW1cm+baSAIx+g~`Ya zpW0GuV1XX7vgs?kTG`;z?10V+sIM@jb2#I=VPrnXlIbkho<^s0=2^w+Ye!j^95!LT zxAo!=X%oJan{e-9TJLj%G?pr(&(7-O+G2y;!VW zfBk>iJNLk?bLp9f+M)8eBDXo2=5Tw>fXmV;! zj;EK~mR{Owo8CU84{K}-2HHTVmPBneZGEJz)zgZ))6g2NSL37d`+V2zz0b}AU+ulW z-yc6TXU}8J%$hYbYu2opS>s*rM6It0NK?CMO1$|g8VMa2p@d0%m2b=QpmeH~AYzoISD_f# zn+3HgH}7&6G*LnIZ31Rt7l*&$6CA!?!=z0h_+-bImilZ1O#v0KzvFT!QV!|0GMS7# z^SSGhXMl`($By13wtd7^+s`QY5H;wBi7Ob$m>>}oG)CXTy!W{rJY||*EBnll)jm){G|FUMT(%6K^#QK;?VC=W zir2J%3I{C%&X&LVhtV-_SG~G`ATsuAUEsR~)S@HRh%`XKTzhDfQ>|uADUX_R4c~cP z#GA&)zJMa&JP1O{(NXI4Or&Z`;V z_n!&I$FFG`?;966Ayx^ql&Wd{ho|k3;lnf zv{INMm+|otms1(X>+3`mb`1mqr^zE<7KCOTb&~8Q0_0cWfDp^4RfQ)nv?^F~#{cS| zev0&~u(zv%738WQXU`{9h1K_IU2l5JEn(UYWt>vR+4A*a=uZ{;Nf-M0FjTkpy^CGw zO<|~RsCZ|((8XcscN99+g;s^3>lAu`3q2(a{k%d8TG_a)oYnp??lT&sOMnUFa{v(B~y^e!+!q3`75>&{`MT9ESc?p&ur6;CbPaLHeye z)GH`^ijq!&+b@%khhf^rHsyAE{o|;l+xjM%G?#p|6C@`~L#_Y)OzptV;=DdEIO`Co zXn0bv0)R^N)f9)N>F!BU?+2Wp9bd%;c~B|C#RC`eD$?ap z>8W)#%#yJi7}XK_=WnZ=ZdO$>m8RjAPUJ}J*Q&D1RDpTjAJ)GTY%D)$14SpHG1D=s z(GEeQ7j&ndIS|oM?*MX~TUKSSGJJHyVn(9121O5rpzf%FwswmpXCxWXdo11i{+omD z@`jpq&H2`~ejJ9ruFxA5YA3c}%ZZ#NToZ!4B9Mz*!W+ZTmlZnOC6o?R=Px>YbU*~X zTGcT0c_;nnPw?@#?mucIkrV2wE%5o>r-))pqUYO&E02^?^K*iQ#A;;Qdmx80?@Mo6 z^vSL;dP~@KeN5&R`CZ1xWw@>!9?^{Gi>1qd5B=rUx9cx=NBc{0Je84Ow~|&MN~yDO z2x7TAC;#1>g8p&17{}82))PFtzw`FJ>)J4NsZyV))Y;eP>3%K5>D$b=SqEiw`ABA;G+j6R)e%LJ zEjG$-b6|-zkVc~{Pqo{)PUTZgBj1g*H8qEmz>PFVyN`c5pxwzrcbd?xuU!)hh9p$3 znUo)svL3A=d2*QSR3-bzxmNd*Fm$FupHrv}N%~tbCf`8vbL+bk1#_=U`D_?^f6G6GO~KH(4w((oOQ+2+r$zRU5w@uat7Ez=xA5!M0@u5Pa44plcf z_#@rtI?)}w;JjklfcesH&FJi)$XVuIB8iKm(pPZ>8n z$tANEVtNT%$VV77wY?Gs_sHI#%a1#QZ72FR3!Uw9)d>^^HXxZA&kAehm@Jtli+VPP z-N2gGtC{Z5v8E-Zn%2)XY(+n#kP(toQ7=0jsv|f}2B*fz)te`w07t-#0-oqoB!I+| zO^GLs03&*X#<8yE7YL+Z4T_I84iRFjMcTpcWlZX7OTLNx`MP3GV>?X*oZC`utbDF9 z@hs!B^M)e0*w}~oxWT5SoA+7fJMv;9lp0XIY7aZ0&!Lk^JnJ=`pt#;Mi0$@f?PTNz z7e?9g3zxUDXVLYr?VX>byltCR+M3y|SEz)Bv&BDT>=WL_of(d)Mvbxkm*xKax~MU> zynN*L!`D%vHL8$XHJ$M^T!52{y6$-4y}0EV>o#M%tr`kARRNh=(n{#CYc}07zh%4M zoUs-Mw#&=f`<^?|4=>?MtIjRuOQXy!;|ne4PUq5d1=WF6boKPyBzM(Fb8fNi3+m2e zcx;lb!5N8`Wix&WdLo78d4+h}v6yQCY9BN;!&zHIBfN;Pp#c-$5yYw?7 zV-UI}Xn4xZv1ROeFD}(Mr4I1NSg-DfA*d>ux8#PAY<0FW(=YGgfQCQ*xP|*OpaG8c zc9Ubfw{-2UUHSIcZelg}HP}^??!omfzx}9bnd}tWeg9~41@d17xWa&39`&mx##Wu{ zhzIV|1Ju2(-zML*mLH6+83}Lsk?byICv+2x0_5(;IcC2r{pO~_DSq~*HEbn$cQzXh z#YWt`4w5=zM#l-bk_Od`M3>Co=@38b61tT%dx?j+g!-`e(L*UTdPwD0RE-QH>#_Qs z!aoQ8pf)-=V~=?KDfOOo$988Oa91=AYr?I z-a45+(Re&-BM!K5aHg_ds0L{<>(zT4E!$}k*o%9RGcG0Mw^`aj@9$?xh7y8sxz7>| zJUv%-wrL$qyiNC(-s)RM<9ei?2N2b=<$rk~$mgrd=Th>~SqVz%BKDVI?AH~WRVk>$ z2xZo|OOeM41>rHf^*;sjy+rhahTnh6pdHzXX_B?R_3h$$)DEUQau0{)=;Rc+`h~BI zR6oyz^ZcZC@}8w1wiabjO9$1Z9-I9vV*~&?40hqn0PSybBocLbR@vrmfM5b?{64#+p}|US%#pJO6m^ZZ8(io zlVmCnaGdqII--44UYEE6D)nRzD)dIgs%`XxA|PoLX764ir~+6ZiUw6U!mq;FE}g5w zh}~6TtzXKa@3jh7SryQ8xhhPGp=8ci;$%PjEjyqPh9~!L3Qf{Ef=}=PZU-P=%aOy> z5=kRc%UO6uooie=SId#RtL0rv3-kws#(Qa~OI$7AAJ&rn-Fz*p{Or4*mWe`d*RJB& z3RgYdwN}Afh{;!P)S&9Av%;hd@{2%*_ggaPVpeghaO{(qPT4G@JszzagXcJY8NQFj zaM83bxg3_C*QLPvVH=p7Ty_avg*!;}qiug0;qDTw2O|Nr5G8h~14_#fxg}7@0z)O2 z@5hWoU_6a+-ip745xrx3zy-!3rFq{zLlvup`<6d2AZE6iDD+YmPcgnOL`CVYRApyl z;*Mpy9o;#~Zk6BBRC$Ll`F{twcfOC?8YKX?b;6BZG3o&S7K_Y}M!U86o!<9>mST>p#@K=SMreq26#W35P zW8xsMOHqEV9Wh=AV!j&tAHNt4Pb{G%@7V@T(*EmVxGJh>pE{owjcUjnAc8_1u4W3O zx{Di;!CPVwp%DViB2R6xJI1eqd?TULP9C;@-ADftgZ93~dE2mm>74*EtG9T+A}=3W zJLS~4oy(Y@68#}(cC*>u{EGJo&)g)Fv%nS1=xc(yP_}_ z$OjUw`oWV%;lSfy`NGL>OzTj*gF2H~CY$UUePPcJ#cPbI7ty0wf`Dnf{>Cs=Q*X?0 zjc327BHZjoRt3P|RWkpk9|zVoJ0y#m_H3+t-9<4(=r)OVS5J3xPe9c~u;!D++`O4| zCWO~zfb(8*=6GW})o-Qxse6OrwLc3iXDog7G@EG|z2%FE&QoUsAl?zD8*5QHIsZ1D z_mrVq-EDW5bLq;L9A?eQ%wAN1;f*zHEYpIb^bI8CV45BKeF2NJn8plVS>V>Vq=~~p zumuE3XvYh4KM#;RL>T<(BrtFighzHB62x)zV_T#862wB2Al8TJ_EEY6PqTVSdiWeM z`FicE*t3ZxW_g%qFNHocYoNSaK}FibKA5EoNxatA$qh`KhzTPlK0zJCi79dl&78XD zQ#8Xf$!&8VNC>=t<;VH<_H9&C4d4Kh1-ADgut4o_0R zlX+I<7jUItz#TwCeVu9cB}O4*}7 z_~YsUfhrATX!RzHve)t+T zj{e_}AHKCE;2kDETyu)*XYxbSfEZtXNLc*;y8Q5FTY#m>4_jvpmLCq?j{M+hl`xF_ z5ZiaK{P2l!|AX?we313!hwt3r!$O&v~t_!{8D$q)8kjwgHX!KG(Z zCIvDrs^xB?uVd6|u>fB>?CV8*$Q$*3ZlF=`=b9>?Ytbnw6p}Ujv}&--OuS*js;@JWOq;qc+Y5 ztnbT$xd#0Z=Q;Mjk8bcMtwAI|YUPg<&VQ#bCDshs*`0*&?3fH;LE2o(P8%Y?$Opi&EHn6*EtPPxaB zE!;|^aATY!Kk!9jLaU(X91tc?Ah21Y%}9H(v(sz;DasrZM<_^e(x}^o!D8@7)<9Ni zCqx3(c&!8ur)HZU<1CW*-{k}4hhk*KKCtM2kNT>G)MtH|M_N0ld!qC`(XS-nC(Z96uC)^tS* zVs@*&_jLM+QRJfgBPyReU+?n0r|3c^SiObsJ$*!$vK3?NoI(3ygUDjv3yI$aw?hrNj zM`{KxVp%wm-P1n~vNJXK1!PBItfArM+45h6v8D$9tP0DPuObvJ(t1S>R)c@@I8o5; zj|clz;strdOW5D(-?ESS&gbjZJLx;nytc(9^R_QC5uwF)R!TGrv%aM2Kk#lNCR6(Z zwivtWcF;T-qkq1D498{ zG`XuindVc!{e5mL_lCc!<5sq$+d14-8c&@xq@+4Od()l8Z~2?ZVfwR5LV6&LRHpC& z&DdWiH@*EF7^%VZO~GR?^(JxKIiY>c;!yVapWN?zI1TN^s>QPN`+XiK@!9X&h8#S2 zzpt%>`bK>OvcdT^fn;f8PXQ?aih4 z(<{2zb>obKw*_2_pwp2~8PG>pj? zDj8qPIIL9*|4s17*_=Y&HUF9Stt(Z?&s4|^3bC#ruKBUeL1%k8-xcmbNVI%iXY+d3 z&@m1QQEv4vwA|?D+r25vtOeLh9?)O@IsUZ=`D@$^Z#_S}&HDKr$b0_+`XPS!I*$BQn6v3LkaQ#p z&q#DHD}}dq!jLp+c$ra+>BJ+Mnn%34g9f+t; z_cs=V{QWD}tpOT;U;nZH%l!RuJ4E=el22bHw|C3mYyM(#!oP^W-*8cszt6jN zAb+3nqk#KHH0Ow^GpC=r^Z@B(e4Qgu@1|$NyRRd?E8AW69?qQT^t@ z4L%wEm-L%o{gHJfpD5^0P3a3C+l_wn;Fh4Tn11e5Hp_?OSMO4OFOj@3RKN6v59akt z|J7teu8$U!NbU`zU;4Vch)`mhYU!6gaaXkaNAydn@zM7DpPw(Reqnp-VA4sLX|@9t zBarkJAPJ2ApGzlp^5~&gk4>rGN1YZhPvB60hhX`x&THJ)AD-8^%dO^_jEY#N2j?|D z9fnpE@vM0_+K2k@8cL>w8TPcsCv5iO5C(?dD*Ii2txg-2Kdr$9z9N0KMMD!3Hq9_B$K?gQ!(L4-2u<=TBP(eGev4qsrO?s|B5|ghR`C$r* zSYqxC)7XKHX@rL7+3b8QJ3c`_mONt1`n{-`6F7EcYIk_gU*+%i7xuJ^I@wuwu4kid z<^7ak8*Qvnl(G{==oenvo51KsTY*9{$))dUqb=NE<2>=i{~9g*!V6y?9osSFG9yu5?sB z>wWm!1x&QV9TlH756R#i92HM|7_$fw{gL>M)tUV-4_Y!fD+n`12JV$5F09PE4buB; zNV}vXWLMzjmG-BMlqy|r!kFl!zjsqH zvs%zU-TMTteKmEAe#ja|wd4;A>c2_8a$VBxj#|@CBsAySd2!Rl$-+nzaZ4mrB#P3e@lf&JAcsqUK1}iR4 z-*-xnS-UIm9pZcFd!^_2RS|l=>+#Y5_xQNP8~jwtRs9k_m-k^kG$C(H4h2<=l8f+h z6-9C>LB*ITdHwZiy8p#F#3${y!hWaQZ<+m;+HZ;dPPE_R7b(A=pUOUdsy%)#&+&6j zH$NZm;-{vQpW5~p$riXv+J%=qz?-LHlzb#~z9RX^!TH9>M^?^9VZ{mZbiVQOk-76t zl#f!J?-2O_cfJz&0C2t|FB@hqg~3D*9)IXv)!$Qw>`@mnI&k#x9;q6N3Z%*|AGlkO&G@iLBHeu>AZ& zd%N_0|JezM^^-weN4?2)9U!dhIDWEvXBS%_JVB(55U|rxLLS2!VV^!`i&*@kc6-;5 zZ25LEb?~P%E$j{bZf`;V5-2{M?sK2}wCe*TrN8wy2(~okC&>ZZ zk?Q8xYTuEP9Y1qs?Rf#N0Q8Xnx)okVc66RpxATwvnDb|I&OhO5{N4v3yq`O1Zueo^ z1OtNYWX`9>eVW~84IiE2N~b)alG^y;UvUMK=XCzc_$%eFB#0?e%tZd+^h~u#E*QzN zJlgtIjM`N-jh8+bFMU2<`ii%&^37O9ps9c$PfBF*?)Z@Ee=EsVC{}txmkdWLjNIiE z1wNmmhTo=!8B4*|B@y%!-xlRkd}N$eDB#Wxz9XaeN!rSKCI%w?Mr#(blbzlBY@2Kj zs*ICW##Ps-9w{H9N~L7m^by1%f;fEuM1_N}Pr9v@j0O051AzNGKt)klnad;iW~VE- zbgc@HPhMN%VuSDPr55{b6&#=Z?P3=jeD9oy-|L`Wkk%DB&Mc*?kHnOu*nQ}i+@KIa z{I6MA_bL~vXsbSm<$MtToAvNhXQAyqjZkB>n~9?%^#oC_vARRoBcZFycad05qeDG( z*yn1)NMRJGH(-U4|IK#d_lu*)uY-WzomU!u!hi%VegglSZB;%Y;hJ6STK{|ddW#JR zx5mYO+yCCV4!`#~PWV7L6$QbvjRrF=Ri~82?lU>H)TIo**_BE;-XZ2%CAH88@xR$6 z_yfY}^#LQ?PFACiQ`EUmSLLAeAzUrCMs?Q1D71+WRN-gEM`ZljXCPw-5O}^Va3C!M zx|IV7zS-%@w{)#CP`7fi!T0u3{N8EQUlpHdk>gUuf(wj(I`TT`DvG5u5k?nY>Y{>gb|rpNr~t1H^o^!6M=cZO$%LRz6-46R6VX#UgwEb z6sHtMJxW|u@XeOuCxr^|T0!6H!6Rd_tr&-hZ8?k|<#ecWS_xL^)FFV@x9RuO@zjTa zL}_wXc@g6=#w;}6<)_aU<=`zNktPg<{2lp^+{Qk&N|WJb+dL*c2*w>Km9dS`#qr~| zHKtZEK31HfR1+hqzU!xw6zM&2fn|q4TU^-aC*)Nnm$u1ru&R7tYw&E_zT|^ABT36U zxm@Cm1#Q6|QOv6l78|n$(_a7T2O3j1gFwxG*jwC>boKookha7Eo9x$eo=MIs{cuY6 zrjmtfHa0*dwFlAhrkD?;aBrOt)PJ+9Xgu{G#mAd|!SB{FV%9GMG3zCzOnrqwWxoty z?+SR4vj2pivgRW!Ey?~g^MY)gcp%N5$;LXQtauUF{ZF7&`K^g4xp)rF1>LzgNv zVQ95Ndq-Q1&ksW{Q0SvBbXFL8jzYJ((4)i9xeEQR3mq4Rp03a@xX{;63~D@8p|vjb znK1Ndg?^aOf%+BXH4dfw`y*OhXf@yzNY$Q)Ap(Y(Hckf`Tgk8AtCSwjq4gq*l62djDCh@w~zRCAC8k1 z!08NqJIa+#;1WOkd;GFdjozMADH!3CZgO3G#U7v#>#gdo5HRZ8r%wpzvXgE;+uiED zYY!64yZmaRi z9g29wo8?Dng)Zd`D{)11dq?^a3X@`{xKfMo>L{P%DZs? zz@29WGk>_?%AEE;mZ&q?OUy1v;f`pMI<=^N1gKS-!4CE)p^xr=A z7dhwW9mx0`uIdy}YXTnT!msqz*7R{zVy9$>NYi|&`$zyas@SGE;l2;k+W#LG<4 zF23;3D$6_o?7LJ;ymH?vf?-E zET%QrE82aGXFzWj2oHa=^&t@P{2bjShgfHO6EN>r&>(T{{QbwmbB=>(o9R*TaMj0~ z!h&KDJ{s8?qNYGK7272G(<%(DC{Ri=KRVR6*XHu{_mzdzJ95`=)N%~z8TTL@yvbwK zYX2NjU+*7NMFUfzdwq_V*>lShNxmITBj#I{7j z_hR1;-;wVMUu{CVqY-R{{5=^zW*ha3@uYd+t{BBGN9ZZyYGLRZPCw0liBIIb!W$KL z{J2E_^%q+k;Cy4nZu$lQA#(-=jeUlhK@ZbS1RZvihY;-PC@)VQrlX8_b5zXf&(+pq zCm05CYEMnJe%E7D*u;`f9WG>#yz3k;waums{`QP7*v5-YBjTlr+(131+CD#?-+TU- zz2p1?)TutoWn11gQpiG~3M`Gi=mOzuH}5e)_5G_Qy|j zZZNK4JYeU|dzf;2=Zo=UHPCn7Tx2etw@B<9C_mM9>nsXKQs5fuS?%gR0|wxTx9!ki zlb1)s`6uy)ExzI#`@D@ukBH0*k@+e=_TlGjQTq&CJJcp$Sp0xlsXtI__N~(OpD*&N zu1cTd_<24*>j@gpo2J3Bl8f$7{?<#H!Gq+~U5HF#jNF*>Vzmd-6|M9YdqLX5wxy$4 zFA>I~iTG)?7mEcX7j*_`#AC|JvC2N?$sFQwY`MhazD=j+%TnMN0(17Dtz+bX_U#I$ z)?Q{N2AHs~BiUQ>qZPa3N7-3_O^l6sb!QCR3=H|<>YXK8uLs8^P{wp_uERrFigERiX$TqJKhum#7>PE z*ee3tWME%=9v%~6?}O%pU_xO|@QyfK6tQ=`yj!mD@qdf?fw4q$Q){mz-tZ`TxL&_A zdxymv?vMHpk2kbM{YPN^HtIi;=S!mgN%4j+NBu{|8?sUV(eZ}WQGaQ?p(g5|9B=qY z)PGF8;qs_|3hy;X{l~@|5>fxuc*BgS|G0R=)TsaXc*9{)e_6a?LezgkykXC%|HOF1 zKhVd8^f@Ws@Iur-E#B}<)X#$hzl-`$jyL=&>iIY(>YovB_-@pHO1$Cr zsDEa>fk*1{_?#MV;Gv7We^$KVQ&InE@rI8_{inwpu8R6A;tkbN|Ll0fyr}<-c*Cry z|IBy;i`#s8bK(v3-@HE&Z#XdOKP%oaHtL@nZzzcRlktZCMj;T=cV4`qC+h!Tyy1^g z|Jm_|Uq}7t#2bDQ^;gCl^twZs-@nBh?u`1+jW=-aD<5AKZ&(}k&yP2xqyF>a4Yg7K z`SFJ9qW%lw4cA2d)$xXlqy7tdNjd7jDBdtT>R%9VD3AItjyFt>`Y(w$92)gs8gCdE z^sQ(7Wf7HK{@gMbnit!)y z-^lon`ajM1kNR(7{73z@jQ^^6(LCA#`@<1fy zA`96T3AxHbo{5AkvXCbtA*(DzN{}Gu?^y_Tx5AL`TL>oH!;m{I1`k`MIB1fw|)4x;uALiP(B;{r!<;5ajI zBm&2rz;RaK7!x?+fn$|lggQm*X@01AP7grJ0>=q~B6gUj13&81`gTWvwEEpIJ9MIAr*mRw(mHhJ*rIh^#|OwLZxve2D)BHA5q`_3RWJl z;WSlbj^8qgvC8_ho$cqNKZLqz(U?Z;(C*6Rhpp*I^WJ~eXeQf9a0@i2FEu4z_YaX5 zV%zfad-xAhaS3HwgQgjbcqa^@baNTx!Li+DM2hxIixQt z>6lwebgX0UvHFND2HF-bqEPPK=}n1V3YuHNC571>ZeT6LCi?ghF>lq$-0a*&l5S4_ z)vr7@cGFeB`aQKw;hAJUv|a{DxBJ z@B0NxozoP$n9#`n7P|U$4LcVv)#qfNba^o)^k<4z->+j77>@q9MU5H|RYyTYRS`8w zV2T{;($(KzM9efxG-5z_G2sVU3Ydsu_6|~%5QA``|DqfzIKNv$3EbrQ7S&)ouXPK_ z(H?DB!oJ3)?T|8YLc8}T>92V7oiL}@Ze|Cg1wf^|ft1_qP>7Y|&#p+0Gwm5_{%nre8 zm?<303^H5(;5ab*$T(pph>ZOjW(Verj43M+jhX$aC*&~9st${%%-pM^X+Ot%0kWax5dIr5E=UgtC~2^jDw6a=($-4 zV*R=}7;gK)9lTdK0@5q}sjwmXngP*z-vIm1tn$={%9CN_zDoPkAgwA)^yC52F70y$ zL*$q+vRG+X1!>hjME^A&prvRtgzSAkNZS=g#+CNWAg#IpY408o?b3cSNc+Vwa;(yh z4$>xF+8Uzs`eFl_79_nmOgctMf63FAMye{8^ppWf4dhh=0j2kaN%vCH|M0^Zqbv61 z8k@BWkDk;V0bS8^(=@P4|Min~>BJXZyFvU|@BPdV>%31gG@|P3IsSe?{m!LH?j)t( zWZd$Rl}VmUDL7bc!!~SN`1TXo3bV$|-BSTHZ`A1TxD{t!9lu+w@&CE3i|dAP=NdTbmBH(l~eC;Ec1<;8~mCn)_U`d z#BIwP0=Vx*_cvDW>@zI1MXL*9H6EDdlpkMi;xch+72rL^L#g1}6@59!b_ryZn@1VV zwwX=ir-Me9x9TLprz+HR>9t}vLsDie7&h&I$cC)a#g1WP?<&!*;`uiEU#lj5*{p(G zpvs*#IQeB`Y$|AUBVZD5`fBuGiYr^w=&cwhFK^w5^6AwBDK98*2M}Oh*fYvTEFm9) z#e+Ouz_DyO@UPUzHnBIz>CL>vDrX~#M|T5g^JlU)Sb`U6RL*S^EZ2zvoE+r3RG*I2 z5>AwpwrA-jjy36}!&Jr#(KeqWs`cZ3LNLD#I!>tD%t0Zo&$+&zc zcT%RZ>RoHKKZ^0;$mLCOq*71rW**AH4;QG6v|R$}NS%X6y|S0mY|$UX0{$b3FAMIP}(q0{M6V@<9y*GpfAvkRI@KyK9kV@)rB@ zJX&Vm?tH;tiE0fH8pj?c>w@SNqP^S7OPZ5oR8BH5N+oAjdb~qUjLlG02C~6HwkfT5 z!d{x81i_o+{Mx+vu*gG+l-5=%s6uROx!t!G@4yRHr0cpJiSl zrq`DEapnj?EL%_FJRrqN#iPqUq}^Sj0`jv?ZHA)jli3L|&{E%YSd8LaE=gl9X;F~W z{Ja70lCB}?I;g*%+?{-YmpxgN1C(*L4`uOlK+TIP}G6v6Ril1!8 zYVs@!L+?=Nr(Niaql1#ZuFz{-=o4Y+?Fv2Dg>DZ+b#mI9;X+%&&@UO6c+`ZJP=afe|(J|^;EJ}m+Xea zhXHSm+L!FTh+{EK?&aUyBP!8!(V+eg_-&l@?k$0l>d=P(1oWde}O-wIx_fZ-8xh?SZz+3sABe^O;_7l!tRG@|I7nhjfj_sQcr}xj^ zR0U`BijNao^sEdWY&ued<>JjC1%1l(FRX6HZ&~9;jI+VHlA7eamx^SngCgpmE1;Be zSITh%OSx2~9OG0I9$C^wWjerY0N)_A)n|RQIXlMrF+#HCoVR!4zi{1rnKG&Ql{I3t zn%VMp;G9{g1%lc3ct9_mCHzRDzxZf>(USaf@|9Pm6AI6lR1K8R℞FhzGLC#mFWB zF(l!Dm1jarvB)rJfZ2K4)jOriWv+Bnic>E|@?1j{-G-^Fa2iJku=-!YdAKf4$zlAT z2LQMqTg*M#$(OgsCs((`Cs#J>L~?+G-RJ2@+)C-O?FqHj1}i6Hd3sH7*T&QVWZxTW zvabmYY4kRk#I0%G)n%Dl(3sjEh#CoH!env%%Ke=Bz+3mX;b)EJNkLppuBNs%BP{N}n;zVnl@0%w*+F+tS7@aJWky62qs%%N1h^ zmd}pnw8V0fBo@g@-gMUFWc%f2_V$V~8e*<9;>eG+*8v`OtSO=?rQc!3+EUutjkP_l z8Zg!tiw5T%D|~wH#vQbG<*mM~AHSz!f8<3yuww0QeuN%LqgA2^?{WEfT9p*W5U;t! z5!IKS9sA1GMNQ_wPQr@=$<{maX|7}lJRQx zgnJeA^oUiuK^nhj_Qd!-^Y%wqn0i(nF+1znGZF1?StZflZu%=5lcN3NU`d<4us5;e zk{z>YCncINmypc$Rq5-h;>BmcPd^AhJ+CZYd z9#;Hc|A5G8vvI)Ex&o5$AO;-S*GJ^cUP1ZZ3+az~f^pN4{LFTWtnW}VOv|Kr&LoD$ zqhOO~U&-q%Ho!N1LCyBye~t)1y}PcH;)YtDbq2Nk#?4kstpTi-ZZTl(N1cBA`N6fk zija3x%X^X&;~SIIw7m5V)ijq(FP$i30v#1v{vsmt_zd5Um}&-C38+(p4~|5NvKkA@ zJI2-3up3m@E3XLaN-fdIv!b)+g!-B;dJoXx zF-=M`>pm`mHdj2CA5wIF77L|*`rdfPLQvDWO;j2~bD~!{T5BMIrBgdVLwbcr#HpNT zM9oo&6I;OB(QxV86#6sfjQRxczwN%aamSE8g8#}l9MS65%lNb zN9`j0`mqLQVpTt>?Fr%f{z=OVd&-97(8{z9%87PA2R$Mjzs2d~?HP9>q>tp0=F-nf zF07{bF28sLn83Nt&!;(=`JgaapUj-c*Pa!O-=fWF0H{kP@=Gm1HS3X|;6ty?8(GB@ zgQ!GLFnd<@D=S9CztA2^kl&nQMth&Q%$HM3q0j71+LZGa9Bpzc_~`Wj3bV;I?^{W8 zqnZ~sbw)&XO9FlrzeR+0D7j>r8i3ZiH0PmD{5h|h{EhXYLn|y|VVJ2cS8Wqz8M2Wr zSRJuh6Hd}Y0lXog1EMVj!!&HqcPJiBzNSQm*gr1yMO#&G^PZ~RC5W~Nzm1To4v0Sh zVQ*M%9!;!cH#hv;K%#Fk{v-q|R3_C9Lbov5$>d7|ijm6FJINptIa)?brR8Dzk&1ov zmnL5$i<_z6{+?@Xb4(4X&at$Dj*;}@4Sqv(R3yP)9Hc_u0bM%3_zdLj_{NLGg~nY% z%?<+GLt>@x=f?~8UmClDrCv-L>cd#!%n`^roTvYSmoe(dM!{*<(4(nWK>j&25~ zDA8t}ng_0P_*$XGyRbcy-eelME>hCXTOdcc?a@?80zxq#al7^sx=lgeG z-XAN5D{uGkQ_mP4z9L$m#2ZN8DT!(}J!fYfa4OTq^(!@9xaY>Qg+IAf(?j0;VSPt2 zBtA`{_1lX#&mpmQ%YPSeDd`P8K$_0Ul1z5&>)c#7gEAd4v3`;~c)3K4u@4f#o3xMc z*{Z8on-x8~6~R8{EfG=mPR=0qUrf?XG9EB{)33$=ms=zD&*HG-qy9X1#Y_<2bVGnR z9k1~9%y5XO6dEG_5LfF#?Fu2A9Xpv~K<#3o#xRR*7Jjo^5m92^9>*`%+jVvKH0KG~$_DE$?6{cPihZ(Qi} zLnl)7YN4AvT*Hv|&}!P4ZJF`yr6h4WfP4-8`<@kZSbe8E(Z*ogJKdG3euRD1tG19lg@jB<^R-f^RIYM`Bx0ef9o*$v;QPhG<1_X zbrr^*1hdBNa}SDjXljft?wE`G&F@5=E3zeg(m!Uzw?rTj!LgBHP-jxzjG}n`GY1f9 z0UTXOKY)BwkxZ{O@gqZ#ZZpP&NOygmB^!?nI{5@C#LSBNl4N^MC**APT<;wkzh%}0 zW$iW!vxR$LjwL+IhlJxKDko#{{^I#CQxkG@kkYHUPYZa)It9R^Ovvysb)l-X6qv&5 zuTEs8CP*E-+O0y9J9+1m#n5(DikF5QcVvyS;XL@evY)+4=NP^6L&XvyLm)A`Wu3Be zE8rx@pd{*OP?Dc7Uo@MvZ3WY-JF)8R*)u^KL$pS z)Imv4A4uj?YZBCs8WOk*(kf1C333W*`h&qWeQG?Td{gq_Z@BED(~QVuFw z#7#A0>uYx?V;#@!T|O{Zx8OB0y8SRCqn&x7R~`Wg9Yi$8(i&75J51%WL$6%9BQm~< zAX|QWRnYBprq+9t%Mk`uY*@Q}JKnnrp(+K{EvS!?m(k3rCJ;a7hfwnb^&_Bwu~yF5 znJHkVhA?Le=5r2afh)~=RJMH25au+&d=!`-Gxar~zjm=&wVseRLxnzxZC6p9^l5}1 z2;!ik1i2}m+F#7Xy1H!ydBOPd2i9kX^xxKeS?zKT85^AnRk4S~K}jEv~Ue9mj~Ij;+HE_FFOsA$fU z>3%mWGCS*`GUU<8+!iuH+RPCmk}g@jHvxlX=@;t=4MozKe?cV8RD+Jc5Kb-0qqEeU zS`M38M7JVdTjwyl;ltF|L9AVAfLWJxUQx1OTXOQx=|9&V5ioB0mJ3Gtu0@imz6(V}4@&*yxtY8YMYl7Q$R9 znC%>B>`jtWi_2-fKH2iqL#WFI)eICcoerkm!5kdI=Sxd!92EB;IP~9-)iNVuO-u z*ecl&C4{Z^krA`S79FS;Cd#LEvMrsmCFVsR;*cpduOU+==U`+;^qxqITaK9xF6~;E zrp+=&2p)MZs*o2s$E3Abk2o}qr_8|Afx1Go<-a^TXuJ=LoFD&@NS+lD0If1i9I>+H z-v~h$3-k;?8Bv3XZkNMDqU(OQW_(xAe)EO(j9Knh&muX8*7Ho4zq4bRX>;i}xO8h> z-sjQDUyG=HIx42qQqmlh>DxPn+9-Ew-S#uam*&S{ zyD$z%WT)$9J`YKCnb$^Tw>hP!T5IRgr21OSYp%4DWs%w7fY&;}Hp^*nJE63b*rtQ( zEJEtsZq;qii-HnsiX0V-dM+d5D9CqT8Uiw75Xf12PI6!_`ws%ScW5qu=QMJ(pgK+} z4a%i!5J=llkUM=4SgkM!MaK0;vtlPT6-#VOn}JY&W@=Tmrij;AUqeR+9uXiJ@V&a8EyS(g}Ys$OhE z)P|L*UH@v0Tut*-)}^Gkow$#Y z!ugE}*X(QBj5p7cMyICFpT@GH%LDsSLa<;F#q}z>GApvQoMqg6B+ca=KHk@$mt|`2 z^S(ufO4X>_4UO@Qzge7~zyIP4f9d%s0K&njBEo$1_O$nV%CiN>LZXz_#bni}TNrim zjrT83C(-Dt9@z?`f;14RB+h(Kl#Y-F^y9mp|)I-bU8r(ytE70$u2EZ(0DF*b= z*&N{FsoGN49((U`~E8sPApG9x9RmYDCDEPYPkaLQbxS zZu|Zyqi+u*!_`xFHhO0Hdy5*$QNHQ((?0bEg-i4cmaoND8}-tO=CW~FBBwaeWVC{s zaV;vsfkvU?IHu-(qA=N!F`)O#|VM7h#VE~l*Jn=M~)X3(UY)$j*=&*vo-oa%v( zXkBF$W&>UI&Xy;_1R4h3caR}nhmFn{?N%2NuG3uBN?op2@%k&#C2PL5s0iWIN~hN_ z=vrWV23Kb1q<=ndH^MGZ-5juqJJTc6<#9Y?SrRKDD zE^~$4kc0y`2xs@117C`Xa)4&jh3kIVUN)}$N@)I^Qb}Y{j~07$2jvMJTq#-0mGOUi zK<1}KhXcMd+;EN=VxmKlxr`3Qa*7UrQq2(BEh<6>`u@7fZ^;L9b{bOo+EWO&jhxl{ z3;w#fUrwJ7ItV{@gQbj8VGUGR2OnHx_BzFp0zNp(gtsZ|Li>DBxk3k5PS*0}{k_uy zI`oJR@o$HHNDb#SM^?eCk$@AXVS?wB;A?mJ`lY0Us?aA}en1HIl%Q4u)f1RCP(v}x z+tfZD8nmmn;Y8nQWYFO2vhYEoXtx4I{RfQt{tT1JS|*t`OOx5)GFeen(KPL}iblqN zz-MHKKksX{veXXi&1Jo@#hlg~Tjiu3PNtbHWoCl|TEt zzjkUs^Or@OuYS{%2;Ek0)@qO~e=LMy3zPRYkafwY)e*VH5&1_U%&!EqpM&XgFr5zO zb0N%qf_eT<%f|!<&i}iq?V};gj|B6e!PpA}6uHnOfb0SXdU^<|D~n$4zZ_Z)rp3V= z9Kzfvn44U7IU>of+ktjD(7u@gC9V_bf4J;&Zc*Q@59|LB=0d?tB|BuOJv>Fu+I1-E ztV=GDI?Lop2~6p=YedTIgwKCsZ^EO;q)G^RX9tMbPOL~~l1UKwgAh1`?&kg4`dpi3 z&#VwV^mG(JK6igjXg+rR2$+L`dYjLQ?zsB`S&~ABFAg240l>_g%Z|uh2 zT#0SOV6oSf^66>{az_v-71K-Yx=zT zgmdwMOBI|PV%xaho3ea7XQ||xT63DtCXjuB)|{5lH-I-sKbM8_z8oO=k9`W!p7!{FhDr8>V8^9R3T{j%=gQ#keiPkZEVg zkdjqHw)_}%F(I<~P2utS?cz8A(UaM+dlA3c5N+L?#fNtc`Xkvz_zmW?{P)%}qcg>? z{GPl{`+!yOB0hGiWD`r!n8$JrE!u$lJ!Qf8OILI10EVDT0{#%hm;tEiazM_zont9r zjU9vN{ZzC6u07Ol-s~cC(4Eeqr6TX&Mh@!hmoE>y=6C3BLAAVV2)Dj2gU!~XWa61l zDTRxfrEra}v*gx0$K&uj z{KqxXuDJNuVOJdQT52kvAzg7IXZ@`!K7W>VMIB%MAL@K}o;;xQ-Tc)-oi9s#wDbK# z{ejL`4Q2z*ll@Eh@idUJsqZn}O&X3LPZfyqHS!kmBD1#bKyDK55ge*uCB#tP6yqScyeZ9OTvgh&KMeEO3!3s#H|SW7Z9IynVCA&VKkSR-+Bz9$8-E5y$GFuyaO zMlQcgAQ6*d-r8%Kwk??)o(M4JG6MmdV2v@obNWJ>BUeuh3?gwqA!OiROq5$^og}pA zMjz|z{qW=f>dRC=QUCL@#_>hH?}G()5zN$4e)WlTys4D2`CNXy2}sdGCl*hc?BFtF zPOuDN?dn)=R+va25#sj<00j?l^nkh!od-sQCCpa|fB#Rei@e{Rr_4^6KxFITgh$U# z1?MyEEMrX{50SjV6UKcU;jlwg1IOn8dW!B~i0tOHfP3`4>5n(bi`ECyU20)hzP%?+ znuxsS-7A?|%4g9?HzKn#;8WYVMWfSu#sqIBUH_6BMdhHT=V^EwZ~L(z2HghCmsdts zWJjftN|~V4OtcPuF0grbTq}m?&ZVg$-eX+EAv30_P~J^5LHOyt1MIS@JId)RW;lxv zCfXO%>=@h5(I1pG2L|SXj`^j=s&xpmp(FFZD?FLLu80HG#THZzekeKbD;daNR_|#L z6D`;45hYccBlbaR;-*8j7EdZn3bE=*U*K|waGBW46%z}VPltid5evX_kY4lV&|!V; z`q*+b$vz?^=ivLc9%xz=7Sv0q(QJF-4wYqHIhn1#!<&1ENWl`#5iMQxa^jAHBaXMju9xxIIs?QvYjn+Sy%j~8cf;2h-PyvN@XprIa)+E!{tB0)POV2`3#PG0^_ri7?F^_0(~;Zu@3s z072Z5`xO}!!Sjov9LAR~ojtEU#*=4vVQa+Dy)7C!-lzMGbujeAJd@jURNA<0e=^<% zr+eY_*3(ts{`?LiEp{Qx^z8Gkl8HSV~hoOP*E5$thJ6liU7`aG2iaU5_#{Hq$Wtw*pYkWb2))T)hQC}H*HMPc*GqL24B*g#e2(R^%te@}^ZoE*?0LbjU$Xlr zL-=(jZVPl(07kQ`-GuiB$Pk>b2c!1lD1U}QXe}+;7+dM%i(4#fy0^p>6om*p8e$$@ z+2>eu{QQ`eGv`tnh(uk^z;#|Rx5z_$wcdV<{EPmF^I!j(_~Ji>e-*S*|Aj^x64e}1 zrsH=cv{cYwP_Gkl`n>PI@}^r%Pf+mL7F@V-3e1AZt{2NMzRdFDSKs8$<$d+F_w7}4 zF#P0cK(?L9n2jag~Xdtv_jRz|O&zUQlOCkTet4hGKGM&GwtPi9>% zaEpQKNyeYwK0$d1vTsq|yMqt&mQ-4e8Pz4PA%d3kK3JSnupEzDzRlqS`mM9Hjdhi8<`RU!~|BLu()jqrD zr}W3wwQuYK%N5dPJ}ShDL&T8K3Qsh|2J13^26A~_=A^BrLI8Zi(?=Nvb{>feL5nJ1 zmuW9>K0a26Fq!>u8dc9Sj<`uM3^(=X|IBEy;{oGusgsA=2kG}d@jSv_TEZkFBM>E} z)2>+<>iHfwY2R1R)e=6ep6@Q8ocUS$VGePI17LiW*Zrh1M+pvJ=cj8s)W{RF@=9H% z19W~*0APk}QABTbI=?5JmT!yG`T4%Kh|aIADbd!L*wU2PLYk(;R$Cn$c5UJb)Xy@E zI|Q@iDcI@%3TVFh6+ypZR2D8fPyK3e^ZjFfwD}gdS@QutVf+!+d{g;EH9)3{o;b#u zuf==*MAQF4boeIPgi!gs&MBXpo$`6Tl+UMwEf6e0GS!5$04R7NqI|BUHW(VH6&+>G zEST0L9hmV#WCJd7B}l3l8Oy(TI3w#Ypq*Cwnp*}b2A2~bRSfR1q1WM^3d;G})$xmA z`j@*;TGQwEA^&CyUCN`#7_Tx?3wk+s8xI!7>LOBDnB1DrK9E1sh|_jGmD`utD=9Kv z0eAIu`CgPj<}(r6@9*fBG=FG3a&iInZ+HpteH4b|zuo)AU*FtC_jFt_Utq}piW$S> zcI_SW&fyscw;$0@C-_9waGjw4+-N7b>ZjHT0H5%F*9l4w8#sowb?xnkojB_4uRR9O zk7Wby?|LWiG#1%S0t7r8M>$CtP8qX6u}*$4`G;$T&wD0c5$GMGSYO2->Jv*yoohtu zaT1E%5ymOy%P}&r$Zg2@#+v87k6&SlO9skw?|%LA*7tF5i80*%d}=^x*hJxx8dyVy z+Yd$m`rtn9E1ZiPbRYNHpK9WvON94vrzs>mb|xP#z0TpYRYFDdKCV{Esjq4bRU zwvKj--p8$~wsD*DK5)E$ANL`3k;x(A-5`GLuwCT82Xv9sK%6o75T>g^?elyKPbqJ=x7RJjFi zFp*AGJSTHGcRCq?ZrX|ojq}4b;1BLS zTku@xYRD&{Td`o=Jg9~+4GDe-eYQyS3r$y2%S5~Pkj??v-XHsa?nq!O3D$49nyPqx zip8R-CMgXSp9tQZOeIS+iGEz)#Rdq^6Y3hTxU0au^-32$Ya3Zz<@r?wrF0>OLO}@5 zF#2y#;8F&`P4rgwiWqSZ6fsgM?*jpYXJG zXyLHKlLcqX7=OL=cJlYz#Y;Zd^xu&e&__7hcByMQd}_MAUyZYZhpZPD`W=y`3fA+k zsk|xAk;2Swh(ID1TIe(;$!*bAsn`t4*g;LCHnHYm|Hak2)f*?+`ui3}my5xAtBfoe z&DIVibX+oMhahur*9BG@)$!ZlZx$e>xs=zg4Suh%!Tk5F`QZ((!&ZLtfha#5f6j3H z@M~vB`QdXv8Nv@Q-8h&Z_8wwPX9^K8ooRfwN^unBhn<@1hvA1yNgCyc6;(bzJo*@) zA8vUK#19M+7eBmIC=Oxd&wMb7_;DZ(KismxP@6|FptcF0=q z)Qlf~n@gr@1n<_#L-`@>@U7|p%Bxi4JRYWUGk=b1d{GDwsmA*TRO7=x9zy>={A4iw zGhhnS|2`2^@+W+@N_dabKPi3KF!b*`D6FK}hiLydpZ<50`t(0dh<~{}KwR|y!@S`T zzeb_qMEXNcYC-?gglu+f55<7m4522S)Mnx5(|?vjZ3z9V^Qam9Cppx*y)mGcXV|`c zm7VYl;9HL)-{{~A_Pb~w#-CJK3?!I^4L>9$EodeDI29<%b_8B64*h8%ufJWrvskl* zv$dN{Zzz*8-xSs#GaZc0on^~mfqKZ-MW-gP_ujvYw-)YxXZhtRl zs{KpI6NLlk`zHG8fD^%Z^HC1o z3A~+bNDb$lk!W9b5=UbPU{={qTo)H{STjN4t)AYzBBOp~YS&0jp*vpw?b#&;=Lnn~ThlQ*hL%(28=K?B1t>e2KIb!=UM%yCYcStf z7oTi*;CU{d)fwYrX$ezXX)@a;ulIuuEZKs*FIB5&Hk2CST>Q_7M}L#LlCUQGwH4=x z-ol=#2HmFGd(~||#NyGQcFvqMSa=t?h5@&j7bhC3}ycjDR1Z1bik zok0hzVX{xj1N64Mp6?TjDY2QsyWX2JQ+0Lbr?>vuh^aB>J^gP!#Yglm2-CQ3ky)yl zbGp}e3Pn!~5`QL=_&fQ;2ZxFM0yisFtS8IH%IpY`a)MC!iYN{9?--wJ>K0|annw&kE^rm>rZ;*gKXF|xUPZ4#;&l9gU zP_O@RvFlzLPIH4J&mf)r5!gGctaI`#pV~%aMegl`=FL?q{*@nyZPzwqG5yiaqB1~^ zN3P-9Pl9#GJ!_oY<8O$wtl8G)7|JE!ObHkY%dakMRIY0i{LFR^@ZAv^FY8t+{$k5O3GZg*b{m#($gg%-O zFAXTDmkiqPW3dIT!PlR%YL2JQ-WKb4C&OUnBl%_vD8E5HF^E2ZXjw`UdB`S9A@{8e z3dwi2$b9=2_QGy#3Q~sft9NQ&?Hp&y1QxVJ+(?tPvy0*%ZO~$K!%~a#_vx7*%|tCd zv#zPKBx&-s(=$8Sx;j_)r-H`HrXw5z{&d+ zXjOMtvw!6FvkRa}jA5lt3t9Cvg_q6{=>e)l{$cg)1!f&&0r zN89rT$Ro%A{`}9Og`1~PO`52t-@6EngF8=QxY=3J={Eh%vKTEY+k}QUwUw6{FoFE? zHZXjS5XQhhoEhkf#lH?}3Tevf*9Uplfv_22$kngJTC)HZ-jvm^52yo0>4qyq4-;A<>ob@f39Z(tp- zVwqVNBJ3pucO|0DzY=lhk4JN>=8gg^ehMOEzs%b@!soh+gxm;rQ?yRDiZ~k|p&0?A z_M&;CxDG`foLQm{JDy`C5e<9+%>t2YG_vCLCmZ&zPx@w&xCtk&5S)JTO$JC_?gU5V z<#_!sRI#vZ2dqo{|7uxdYAcY-KSt9zD+m6OBmdUCva;(VoclX+xNIaA9cP_O z`Iu~E@R{s-VUR6PjSXa@GZ_Ki9thk`R;CTP(tNp&ETZ9_$tmstQP{@4vn*$;6nBbT z&Qk{F{DT`!>M{=Mq%JvoHq!e|LJ?yN>lQK%$C?vcj|OB^Vb4 zDs^N7aZA(!BiaA+?LoQq)lBo%vi`K`5%4m>xuwmP5;F9v=pRA28yf=YZIj(AN9V8I z#cOu~tAm8d$R*EP7NFaQsmf0o=SInf+LFzu$dy$kMV4 zUhG@z->0)gles+aR-22^H_R~mVmI$iODJdSE*)ll%eqI{C|$1DZhdB&39i~3DaQQV zbyskGn{tTNz-e9aj`W$O#ohz+MD<|uf*JZ&&4O-Zm9m527O_Rbkym(@C9)!1!^+vS zLN$-%H6ziYoAY5-P*_D?M3L6P+JzMVNMrR+`zE|nil8p7e4-u9f-&<#u*0J^VFg;a z!$VHj!CVvS#bXG#o?yQuV_hTBd!>CdUlvJe&A`O#Uvc;-0TAo-sjqE`)o^TnFzNo? z4Jd!kf^_tajO!oH?Ks~I%VpUC+f)BeZiub+CG$0SdoL$nD`kp<=3FymauRxWshrHZ zbZi$q(&QFPC@TmS&rxB4Wy{~cM=;BNQ?qRIGR=hn@s&m^yS-d{Tm2l#RoS6rA1qh_KEkwmv?$4(WHQ7AptB?)~A$(g) zWwz-uS$z%Bh)jIEmO4JOkPy*DAH*X*QM@eJ+2e9}&3AZNxWh}%2wrX_;cqkiSUoG4 zK0c?rvS6o{_741k&nI3`PeB<)Efzs$tg5gk`wgdx z>Ev%?Kbw-1Tq}gPri!wlXw1^*qo9c^H!DClRV3x|EpnkE!xyEMszAP_e72NO7jM!T zd2mN7fiSMF52�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

q*;;7H%Z81JJ=i{&R0Lm>%1VW@npm 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 z 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 )u1`!Rf?Q<_QF(q`g($Rlz8K^+!R^ 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%0A$$5V+|09QNSr@0@niP6~^ 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

1L*nb<2O}UAvBla#?P!Le-Si)% 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 D;UU;I diff --git a/alloc.d b/alloc.d index 7665334..0b13654 100644 --- a/alloc.d +++ b/alloc.d @@ -5,9 +5,11 @@ import dlib.math; import dlib.platform; import dlib.util; +import core.stdc.string; + version(WebAssembly) { - + import dlib.externdecl; } else { @@ -15,7 +17,7 @@ else } static Scratch g_scratch; -static u64 g_scratch_index; +static usize g_scratch_index; const DEFAULT_ALIGNMENT = (void *).sizeof * 2; @@ -28,29 +30,55 @@ struct Scratch struct ArenaPool { u8* mem; - u64 pos; - u64 length; + usize pos; + usize length; ArenaPool* next; } struct Arena { ArenaPool* first, last; - u64 def_size; + usize def_size; } struct TempArena { Arena* arena; - u64 start_pos; + usize start_pos; ArenaPool* start_pool; } +/* extern(C) { void gc_setProxy(void* p); void gc_clrProxy(); } +*/ + +version(WebAssembly) +{ + +pragma(LDC_intrinsic, "llvm.wasm.memory.grow.i32") +extern(C) size_t grow(size_t index, size_t size); + +pragma(LDC_intrinsic, "llvm.wasm.memory.size.i32") +extern(C) size_t size(size_t index); + + +extern(C) u32 +WasmGrow(u32 size) +{ + return grow(0, size); +} + +extern(C) u32 +WasmSize() +{ + return size(0); +} + +} T* MAlloc(T)() @@ -60,7 +88,7 @@ MAlloc(T)() } T[] -MAlloc(T)(u64 count) +MAlloc(T)(usize count) { void* mem = MemAlloc(T.sizeof * count); return (cast(T*)mem)[0 .. count]; @@ -75,14 +103,14 @@ MFree(T)(T* ptr) void MFree(T)(T[] slice) { - MemFree(slice.ptr, cast(u64)slice.length * T.sizeof); + MemFree(slice.ptr, cast(usize)slice.length * T.sizeof); } T* Alloc(T)() { void* mem = malloc(T.sizeof); - MemSet(mem, 0, T.sizeof); + memset(mem, 0, T.sizeof); return (cast(T*)mem); } @@ -90,7 +118,7 @@ T[] Alloc(T)(usize count) { void* mem = malloc(T.sizeof * count); - MemSet(mem, 0, T.sizeof * count); + memset(mem, 0, T.sizeof * count); return (cast(T*)mem)[0 .. count]; } @@ -111,7 +139,7 @@ Alloc(string target) } T[] -Alloc(T)(T[] target, u64 start, u64 len) +Alloc(T)(T[] target, usize start, usize len) { T[] arr = Alloc!(T)(len); arr[0 .. $] = target[start .. start+len]; @@ -119,7 +147,7 @@ Alloc(T)(T[] target, u64 start, u64 len) } string -Alloc(string target, u64 start, u64 len) +Alloc(string target, usize start, usize len) { u8[] str = Alloc!(u8)(len); str[0 .. $] = cast(u8[])target[start .. start+len]; @@ -127,7 +155,7 @@ Alloc(string target, u64 start, u64 len) } T[] -Alloc(T)(u64 count, T set) +Alloc(T)(usize count, T set) { T[] arr = Alloc!(T)(count); arr[] = set; @@ -135,9 +163,19 @@ Alloc(T)(u64 count, T set) } T[] -Realloc(T)(T[] arr, u64 count) +Realloc(T)(T[] arr, usize count) { - void* mem = realloc(arr.ptr, T.sizeof * count); + static if(NativeTarget) + { + void* mem = realloc(arr.ptr, T.sizeof * count); + } + else + { + void* mem = alloc(T.sizeof*count); + memcpy(mem, arr.ptr, T.sizeof*arr.length); + Free(arr); + } + return (cast(T*)mem)[0 .. count]; } @@ -154,7 +192,7 @@ Free(T)(T* ptr) } Arena -CreateArena(u64 size) +CreateArena(usize size) { Arena arena = { def_size: size, @@ -213,13 +251,13 @@ Alloc(T)(TempArena* t, T[] target) } T[] -Alloc(T)(TempArena* t, u64 count, T set) +Alloc(T)(TempArena* t, usize count, T set) { return Alloc!(T)(t.arena, count, set); } T[] -Alloc(T)(TempArena* t, u64 count) +Alloc(T)(TempArena* t, usize count) { return Alloc!(T)(t.arena, count); } @@ -231,7 +269,7 @@ Alloc(T)(TempArena* t, T[] target) } T[] -Alloc(T)(TempArena* t, T[] target, u64 start, u64 len) +Alloc(T)(TempArena* t, T[] target, usize start, usize len) { return Alloc!(T)(t.arena, target, start, len); } @@ -243,7 +281,7 @@ Alloc(T)(TempArena* t) } void -AddArenaPool(Arena* arena, u64 size) +AddArenaPool(Arena* arena, usize size) { u8* mem = Alloc!(u8)(size + ArenaPool.sizeof).ptr; @@ -259,10 +297,10 @@ AddArenaPool(Arena* arena, u64 size) } T[] -Alloc(T)(Arena* arena, u64 count) +Alloc(T)(Arena* arena, usize count) { void* mem = AllocAlign(arena, T.sizeof * count, DEFAULT_ALIGNMENT); - MemSet(mem, 0, T.sizeof * count); + memset(mem, 0, T.sizeof * count); return (cast(T*)mem)[0 .. cast(usize)count]; } @@ -283,7 +321,7 @@ Alloc(Arena* arena, string target) } T[] -Alloc(T)(Arena* arena, T[] target, u64 start, u64 len) +Alloc(T)(Arena* arena, T[] target, usize start, usize len) { T[] arr = Alloc!(T)(arena, len); arr[0 .. $] = target[start .. start+len]; @@ -291,7 +329,7 @@ Alloc(T)(Arena* arena, T[] target, u64 start, u64 len) } string -Alloc(Arena* arena, string target, u64 start, u64 len) +Alloc(Arena* arena, string target, usize start, usize len) { u8[] str = Alloc!(u8)(arena, len); str[0 .. $] = cast(u8[])target[start .. start+len]; @@ -299,7 +337,7 @@ Alloc(Arena* arena, string target, u64 start, u64 len) } T[] -Alloc(T)(Arena* arena, u64 count, T set) +Alloc(T)(Arena* arena, usize count, T set) { T[] arr = Alloc!(T)(arena, count); arr[] = set; @@ -310,22 +348,22 @@ T* Alloc(T)(Arena* arena) { void* mem = AllocAlign(arena, T.sizeof, DEFAULT_ALIGNMENT); - MemSet(mem, 0, T.sizeof); + memset(mem, 0, T.sizeof); return cast(T*)mem; }; void* -AllocAlign(Arena* arena, u64 size, u64 alignment) +AllocAlign(Arena* arena, usize size, usize alignment) { void* ptr = null; - u64 pool_alloc_size = size; + usize pool_alloc_size = size; if(pool_alloc_size > arena.def_size) { pool_alloc_size += arena.def_size; } - uintptr mem_pos, current, offset; + usize mem_pos, current, offset; ArenaPool* node = arena.first; while (true) { @@ -335,7 +373,7 @@ AllocAlign(Arena* arena, u64 size, u64 alignment) node = arena.first; } - mem_pos = cast(uintptr)node.mem; + mem_pos = cast(usize)node.mem; current = mem_pos + node.pos; offset = AlignPow2(current, alignment) - mem_pos; @@ -378,7 +416,7 @@ Free(Arena* arena) } void -ResetScratch(u64 size) +ResetScratch(usize size) { if(!g_scratch.init) { @@ -396,7 +434,7 @@ ScratchAlloc(T)() } T[] -ScratchAlloc(T)(u64 count) +ScratchAlloc(T)(usize count) { return Alloc!(T)(&g_scratch.arena, count); } @@ -434,7 +472,7 @@ ScratchAlloc(string target, usize start, usize len) } T[] -ScratchAlloc(T)(u64 count, T set) +ScratchAlloc(T)(usize count, T set) { T[] arr = ScratchAlloc!(T)(count); arr[] = set; diff --git a/build.sh b/build.sh index 3d3bc5c..e39e526 100755 --- a/build.sh +++ b/build.sh @@ -6,80 +6,91 @@ if [ -z "$1" ]; then exit 1 fi +wasm="" +if [[ $# -eq 2 ]]; then + if [[ "$2" -eq "wasm" ]]; then + wasm="1" + fi +fi + script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) build="$1" + +if [ -n "$wasm" ]; then + ext_path="${script_dir}/external" -mkdir -p $build + cpp_compiler="clang++" + c_compiler="clang" + flags="-target wasm32 -nostdlib -Wl,--no-entry -c -static -mbulk-memory -mbulk-memory-opt -matomics -msimd128 -mno-gc" + files="${ext_path}/tinyalloc/tinyalloc.c" + includes="-I${ext_path}/tinyalloc" + out="" -if [ -x "$(command -v g++)" ]; then cpp_compiler="g++"; c_compiler="gcc"; -elif [ -x "$(command -v clang++)" ]; then cpp_compiler="clang++"; c_compiler="clang"; -else echo "Unable to find c++ cpp_compiler"; exit -1; fi; + $c_compiler $flags $includes $files $out +else + if [ -x "$(command -v g++)" ]; then cpp_compiler="g++"; c_compiler="gcc"; + elif [ -x "$(command -v clang++)" ]; then cpp_compiler="clang++"; c_compiler="clang"; + else echo "Unable to find c++ cpp_compiler"; exit -1; fi; -if [ -x "$(command -v mold)" ]; then linker_cmd="-fuse-ld=mold"; -elif [ -x "$(command -v lld)" ]; then linker_cmd="-fuse-ld=lld"; -elif [ -x "$(command -v ld)" ]; then linker_cmd="-fuse-ld=ld"; -else echo "Unable to find c/c++ linker"; exit -1; fi; + if [ -x "$(command -v mold)" ]; then linker_cmd="-fuse-ld=mold"; + elif [ -x "$(command -v lld)" ]; then linker_cmd="-fuse-ld=lld"; + elif [ -x "$(command -v ld)" ]; then linker_cmd="-fuse-ld=ld"; + else echo "Unable to find c/c++ linker"; exit -1; fi; -# COMPILER FLAGS -out="-o" + shared_flags="-c -static -msse4.2 -Wno-everything $linker_cmd" -# STB_IMAGE -src="${script_dir}/external/stb/stb.c" -flags="-std=c99 -Wno-everything -Iexternal/stb -c -static" -obj="${build}/stb.o" -lib="${build}/libstb.a" + mkdir -p $build -if ! [ -f "${build}/libstb.a" ]; then - $c_compiler $flags $src $out $obj - ar rcs $lib $obj - rm $obj + # COMPILER FLAGS + out="-o" + + # STB_IMAGE + src="${script_dir}/external/stb/stb.c" + flags="-std=c99 -Iexternal/stb $shared_flags" + obj="${build}/stb.o" + lib="${build}/libstb.a" + + if ! [ -f "${build}/libstb.a" ]; then + $c_compiler $flags $src $out $obj + ar rcs $lib $obj + rm $obj + fi + + # M3D + #src="${script_dir}/external/m3d/m3d.c" + #flags="-std=c99 -Wno-everything -Iexternal/m3d -c -static" + #obj="${build}/m3d.o" + #lib="${build}/libm3d.a" + # + #if ! [ -f "${build}/libm3d.a" ]; then + # $c_compiler $flags $src $out $obj + # ar rcs $lib $obj + # rm $obj + #fi + + # CGLTF + src="${script_dir}/external/cgltf/cgltf.c" + flags="-std=c99 -Iexternal/cgltf $shared_flags" + obj="${build}/cgltf.o" + lib="${build}/libcgltf.a" + + if ! [ -f "${build}/libcgltf.a" ]; then + $c_compiler $flags $src $out $obj + ar rcs $lib $obj + rm $obj + fi + + + # XXHASH + #src="${script_dir}/external/xxhash/xxhash.c" + #flags="-std=c99 -Iexternal/xxhash $shared_flags" + #obj="${build}/xxhash.o" + #lib="${build}/libxxhash.a" + + #if ! [ -f $lib ]; then + # $c_compiler $flags $src $out $obj + # ar rcs $lib $obj + # rm $obj + #fi fi -# M3D -#src="${script_dir}/external/m3d/m3d.c" -#flags="-std=c99 -Wno-everything -Iexternal/m3d -c -static" -#obj="${build}/m3d.o" -#lib="${build}/libm3d.a" -# -#if ! [ -f "${build}/libm3d.a" ]; then -# $c_compiler $flags $src $out $obj -# ar rcs $lib $obj -# rm $obj -#fi - -# CGLM -src="${script_dir}/external/cglm/cglm.c" -flags="-std=c99 -Wno-everything -Iexternal/cglm -c -static" -obj="${build}/cglm.o" -lib="${build}/libcglm.a" - -if ! [ -f "${build}/libcglm.a" ]; then - $c_compiler $flags $src $out $obj - ar rcs $lib $obj - rm $obj -fi - -# CGLTF -src="${script_dir}/external/cgltf/cgltf.c" -flags="-std=c99 -Wno-everything -Iexternal/cgltf -c -static" -obj="${build}/cgltf.o" -lib="${build}/libcgltf.a" - -if ! [ -f "${build}/libcgltf.a" ]; then - $c_compiler $flags $src $out $obj - ar rcs $lib $obj - rm $obj -fi - - -# XXHASH -src="${script_dir}/external/xxhash/xxhash.c" -flags="-std=c99 -Wno-everything -Iexternal/xxhash -c -static" -obj="${build}/xxhash.o" -lib="${build}/libxxhash.a" - -if ! [ -f $lib ]; then - $c_compiler $flags $src $out $obj - ar rcs $lib $obj - rm $obj -fi diff --git a/dlibincludes.c b/dlibincludes.c index cbe9173..ee1cc83 100644 --- a/dlibincludes.c +++ b/dlibincludes.c @@ -22,9 +22,8 @@ # include "external/stb/stb_image_write.h" #endif -#ifndef BUILD_WASM -# define CGLM_FORCE_DEPTH_ZERO_TO_ONE -# include "external/cglm/cglm.h" +#ifdef BUILD_WASM +# include "external/tinyalloc/tinyalloc.c" #endif #ifndef NO_STBI @@ -35,12 +34,9 @@ # include "../VulkanRenderer/vulkan_includes.c" #endif - -#include "external/cgltf/cgltf.h" - -#define PRINTF_SUPPORT_FLOAT -#include "external/printf/printf.c" +#ifndef BUILD_WASM +# include "external/cgltf/cgltf.h" +#endif #define XXH_NO_STDLIB 1 -#define XXH_STATIC_LINKING_ONLY 1 -#include "external/xxhash/xxhash.h" +#include "external/xxhash/xxhash.c" diff --git a/external.d b/external.d new file mode 100644 index 0000000..94b494d --- /dev/null +++ b/external.d @@ -0,0 +1,101 @@ +module dlib.externdecl; + +import dlib.aliases; + +enum stbtt_curvetype : u8 +{ + none, + vmove, + vline, + vcurve, + vcubic, +} + +alias stbtt_vertex_type = short; + +struct stbtt__buf +{ + u8* data; + i32 cursor; + i32 size; +} + +struct stbtt_vertex +{ + stbtt_vertex_type x, y, cx, cy, cx1, cy1; + stbtt_curvetype type; + u8 padding; +} + +struct stbtt_fontinfo +{ + void* userdata; + u8* data; + i32 fontstart; + + i32 numGlyphs; + + i32 loca, head, glyf, hhea, hmtx, kern, gpos, svg; + i32 index_map; + i32 indexToLocFormat; + + stbtt__buf cff; + stbtt__buf charstrings; + stbtt__buf gsubrs; + stbtt__buf subrs; + stbtt__buf fontdicts; + stbtt__buf fdselect; +} + +extern(C): + +// stb_truetype + +i32 +stbtt_FindGlyphIndex(const stbtt_fontinfo* info, i32 unicode_codepoint); + +void +stbtt_GetGlyphHMetrics(const stbtt_fontinfo* info, i32 glyph_index, i32* advanceWidth, i32* leftSideBearing); + +i32 +stbtt_GetGlyphShape(const stbtt_fontinfo* info, i32 glyph_index, stbtt_vertex** pvertices); + +void +stbtt_FreeShape(const stbtt_fontinfo* info, stbtt_vertex* v); + +f32 +stbtt_ScaleForPixelHeight(const stbtt_fontinfo* info, f32 height); + +void +stbtt_GetFontVMetrics(const stbtt_fontinfo* info, i32* ascent, i32* descent, i32* lineGap); + +i32 +stbtt_InitFont(stbtt_fontinfo* info, const(u8*) data, i32 offset); + +i32 +stbtt_GetGlyphBox(const stbtt_fontinfo* info, i32 glyph_index, i32* x0, i32* y0, i32* x1, i32* y1); + +i32 +stbtt_GetFontOffsetForIndex(const(u8*) data, i32 index); + +// tinyalloc + +version(WebAssembly) +{ + void + ta_init(const usize heap_blocks, const usize split_thresh, const usize alignment); + + void* + malloc(usize size) nothrow @nogc; + + void* + calloc(usize size, usize count); + + void + free(void *ptr); + + void* + realloc(void *ptr, usize size); +} + + diff --git a/external/arsd-webassembly/core/arsd/aa.d b/external/arsd-webassembly/core/arsd/aa.d index aa7cff3..eb095a6 100644 --- a/external/arsd-webassembly/core/arsd/aa.d +++ b/external/arsd-webassembly/core/arsd/aa.d @@ -12,7 +12,6 @@ module core.arsd.aa; extern (C) immutable int _aaVersion = 1; import core.internal.hash; -import core.arsd.memory_allocation; uint min(uint a, uint b) { return a < b ? a : b; } uint max(uint a, uint b) { return a > b ? a : b; } diff --git a/external/arsd-webassembly/core/arsd/memory_allocation.d b/external/arsd-webassembly/core/arsd/memory_allocation.d index dd6ac92..6c5fbe3 100644 --- a/external/arsd-webassembly/core/arsd/memory_allocation.d +++ b/external/arsd-webassembly/core/arsd/memory_allocation.d @@ -1,7 +1,5 @@ module core.arsd.memory_allocation; - - private __gshared ubyte* nextFree; private __gshared size_t memorySize; // in units of 64 KB pages @@ -257,4 +255,4 @@ ubyte[] realloc(ubyte[] ptr, size_t newSize, string file = __FILE__, size_t line return ret; } else return realloc(ptr.ptr, newSize, file, line); -} \ No newline at end of file +} diff --git a/external/arsd-webassembly/core/arsd/objectutils.d b/external/arsd-webassembly/core/arsd/objectutils.d index 5c41a94..d7baf51 100644 --- a/external/arsd-webassembly/core/arsd/objectutils.d +++ b/external/arsd-webassembly/core/arsd/objectutils.d @@ -52,7 +52,7 @@ void __doPostblit(void *ptr, size_t len, const TypeInfo ti) return; // optimized for struct, call xpostblit directly for each element - immutable size = ti.size; + immutable size = ti.tsize; const eptr = ptr + len; for (;ptr < eptr;ptr += size) pblit(ptr); @@ -60,7 +60,7 @@ void __doPostblit(void *ptr, size_t len, const TypeInfo ti) else { // generic case, call the typeinfo's postblit function - immutable size = ti.size; + immutable size = ti.tsize; const eptr = ptr + len; for (;ptr < eptr;ptr += size) ti.postblit(ptr); diff --git a/external/arsd-webassembly/core/arsd/utf_decoding.d b/external/arsd-webassembly/core/arsd/utf_decoding.d index cf14a5d..72719b0 100644 --- a/external/arsd-webassembly/core/arsd/utf_decoding.d +++ b/external/arsd-webassembly/core/arsd/utf_decoding.d @@ -64,7 +64,7 @@ Params: Returns: non-zero when the loop was exited through a `break` */ -extern (C) int _aApplycd1(in char[] aa, dg_t dg) +extern (C) int _aApplycd1(char[] aa, dg_t dg) { int result; size_t len = aa.length; @@ -87,7 +87,7 @@ extern (C) int _aApplycd1(in char[] aa, dg_t dg) /// ditto -extern (C) int _aApplywd1(in wchar[] aa, dg_t dg) +extern (C) int _aApplywd1(wchar[] aa, dg_t dg) { int result; size_t len = aa.length; @@ -109,7 +109,7 @@ extern (C) int _aApplywd1(in wchar[] aa, dg_t dg) /// ditto -extern (C) int _aApplycw1(in char[] aa, dg_t dg) +extern (C) int _aApplycw1(char[] aa, dg_t dg) { int result; size_t len = aa.length; @@ -143,7 +143,7 @@ extern (C) int _aApplycw1(in char[] aa, dg_t dg) /// ditto -extern (C) int _aApplywc1(in wchar[] aa, dg_t dg) +extern (C) int _aApplywc1(wchar[] aa, dg_t dg) { int result; size_t len = aa.length; @@ -179,7 +179,7 @@ extern (C) int _aApplywc1(in wchar[] aa, dg_t dg) /// ditto -extern (C) int _aApplydc1(in dchar[] aa, dg_t dg) +extern (C) int _aApplydc1(dchar[] aa, dg_t dg) { int result; @@ -211,7 +211,7 @@ extern (C) int _aApplydc1(in dchar[] aa, dg_t dg) /// ditto -extern (C) int _aApplydw1(in dchar[] aa, dg_t dg) +extern (C) int _aApplydw1(dchar[] aa, dg_t dg) { int result; @@ -255,7 +255,7 @@ extern (D) alias dg2_t = int delegate(void* i, void* c); /** Variants of _aApplyXXX that include a loop index. */ -extern (C) int _aApplycd2(in char[] aa, dg2_t dg) +extern (C) int _aApplycd2(char[] aa, dg2_t dg) { int result; size_t len = aa.length; @@ -281,7 +281,7 @@ extern (C) int _aApplycd2(in char[] aa, dg2_t dg) } /// ditto -extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg) +extern (C) int _aApplywd2(wchar[] aa, dg2_t dg) { int result; size_t len = aa.length; @@ -307,7 +307,7 @@ extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg) } /// ditto -extern (C) int _aApplycw2(in char[] aa, dg2_t dg) +extern (C) int _aApplycw2(char[] aa, dg2_t dg) { int result; size_t len = aa.length; @@ -344,7 +344,7 @@ extern (C) int _aApplycw2(in char[] aa, dg2_t dg) /// ditto -extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg) +extern (C) int _aApplywc2(wchar[] aa, dg2_t dg) { int result; size_t len = aa.length; @@ -383,7 +383,7 @@ extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg) /// ditto -extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg) +extern (C) int _aApplydc2(dchar[] aa, dg2_t dg) { int result; size_t len = aa.length; @@ -417,7 +417,7 @@ extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg) /// ditto -extern (C) int _aApplydw2(in dchar[] aa, dg2_t dg) +extern (C) int _aApplydw2(dchar[] aa, dg2_t dg) { int result; debug(apply) printf("_aApplydw2(), len = %d\n", aa.length); diff --git a/external/arsd-webassembly/core/demangle.d b/external/arsd-webassembly/core/demangle.d new file mode 100644 index 0000000..b6117cb --- /dev/null +++ b/external/arsd-webassembly/core/demangle.d @@ -0,0 +1,2376 @@ +package core.demangle; + +private enum TypeCtor : ushort { + None = 0, + //// 'x' + Const = (1 << 1), + /// 'y' + Immutable = (1 << 2), + /// 'O' + Shared = (1 << 3), + /// + InOut = (1 << 4), +} + +private immutable ManglingFlagInfo[] typeCtors = [ + ManglingFlagInfo(TypeCtor.Immutable, "immutable"), + ManglingFlagInfo(TypeCtor.Shared, "shared"), + ManglingFlagInfo(TypeCtor.InOut, "inout"), + ManglingFlagInfo(TypeCtor.Const, "const"), +]; + +private enum FuncAttributes : ushort { + None = 0, + //// 'a' + Pure = (1 << 1), + //// 'b' + Nothrow = (1 << 2), + //// 'c' + Ref = (1 << 3), + //// 'd' + Property = (1 << 4), + //// 'e' + Trusted = (1 << 5), + //// 'f' + Safe = (1 << 6), + //// 'i' + NoGC = (1 << 7), + //// 'j' + Return = (1 << 8), + //// 'l' + Scope = (1 << 9), + //// 'm' + Live = (1 << 10), + + /// Their order matter + ReturnScope = (1 << 11), + ScopeReturn = (1 << 12), +} + +// The order in which we process is the same as in compiler/dmd/src/dmangle.d +private immutable ManglingFlagInfo[] funcAttrs = [ + ManglingFlagInfo(FuncAttributes.Pure, "pure"), + ManglingFlagInfo(FuncAttributes.Nothrow, "nothrow"), + ManglingFlagInfo(FuncAttributes.Ref, "ref"), + ManglingFlagInfo(FuncAttributes.Property, "@property"), + ManglingFlagInfo(FuncAttributes.NoGC, "@nogc"), + + ManglingFlagInfo(FuncAttributes.ReturnScope, "return scope"), + ManglingFlagInfo(FuncAttributes.ScopeReturn, "scope return"), + + ManglingFlagInfo(FuncAttributes.Return, "return"), + ManglingFlagInfo(FuncAttributes.Scope, "scope"), + + ManglingFlagInfo(FuncAttributes.Live, "@live"), + ManglingFlagInfo(FuncAttributes.Trusted, "@trusted"), + ManglingFlagInfo(FuncAttributes.Safe, "@safe"), +]; + +private struct NoHooks +{ + // supported hooks + // static bool parseLName(ref Demangle); + // static char[] parseType(ref Demangle, char[]) +} + +private struct Demangle(Hooks = NoHooks) +{ + // NOTE: This implementation currently only works with mangled function + // names as they exist in an object file. Type names mangled via + // the .mangleof property are effectively incomplete as far as the + // ABI is concerned and so are not considered to be mangled symbol + // names. + + // NOTE: This implementation builds the demangled buffer in place by + // writing data as it is decoded and then rearranging it later as + // needed. In practice this results in very little data movement, + // and the performance cost is more than offset by the gain from + // not allocating dynamic memory to assemble the name piecemeal. + // + // If the destination buffer is too small, parsing will restart + // with a larger buffer. Since this generally means only one + // allocation during the course of a parsing run, this is still + // faster than assembling the result piecemeal. + +pure @safe: + enum AddType { no, yes } + + + this( return scope const(char)[] buf_, return scope char[] dst_ = null ) + { + this( buf_, AddType.yes, dst_ ); + } + + + this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null ) + { + buf = buf_; + addType = addType_; + dst.dst = dst_; + } + + const(char)[] buf = null; + Buffer dst; + size_t pos = 0; + size_t brp = 0; // current back reference pos + AddType addType = AddType.yes; + bool mute = false; + Hooks hooks; + + ////////////////////////////////////////////////////////////////////////// + // Type Testing and Conversion + ////////////////////////////////////////////////////////////////////////// + + + static bool isAlpha( char val ) + { + return ('a' <= val && 'z' >= val) || + ('A' <= val && 'Z' >= val) || + (0x80 & val); // treat all unicode as alphabetic + } + + + static bool isDigit( char val ) nothrow + { + return '0' <= val && '9' >= val; + } + + + static bool isHexDigit( char val ) + { + return ('0' <= val && '9' >= val) || + ('a' <= val && 'f' >= val) || + ('A' <= val && 'F' >= val); + } + + + static ubyte ascii2hex( out bool errStatus, char val ) nothrow + { + if (val >= 'a' && val <= 'f') + return cast(ubyte)(val - 'a' + 10); + if (val >= 'A' && val <= 'F') + return cast(ubyte)(val - 'A' + 10); + if (val >= '0' && val <= '9') + return cast(ubyte)(val - '0'); + + errStatus = true; + return 0; + } + + BufSlice shift(scope const BufSlice val) return scope + { + if (mute) + return dst.bslice_empty; + return dst.shift(val); + } + + void putComma(size_t n) + { + version (DigitalMars) pragma(inline, false); + if (n) + put(", "); + } + + void put(char c) return scope + { + char[1] val = c; + put(val[]); + } + + void put(scope BufSlice val) return scope + { + put(val.getSlice); + } + + void put(scope const(char)[] val) return scope nothrow + { + if (mute) + return; + dst.append(val); + } + + + void putAsHex( size_t val, int width = 0 ) + { + import core.internal.string; + + UnsignedStringBuf buf = void; + + auto s = unsignedToTempString!16(val, buf); + int slen = cast(int)s.length; + if (slen < width) + { + foreach (i; slen .. width) + put('0'); + } + put(s); + } + + + void pad( const(char)[] val ) + { + if ( val.length ) + { + put(" "); + put( val ); + } + } + + + void silent( out bool err_status, void delegate(out bool err_status) pure @safe nothrow dg ) nothrow + { + auto n = dst.length; + dg(err_status); + if(!err_status) + dst.len = n; + } + + + ////////////////////////////////////////////////////////////////////////// + // Parsing Utility + ////////////////////////////////////////////////////////////////////////// + + @property bool empty() + { + return pos >= buf.length; + } + + @property char front() + { + if ( pos < buf.length ) + return buf[pos]; + return char.init; + } + + char peek( size_t n ) + { + if ( pos + n < buf.length ) + return buf[pos + n]; + return char.init; + } + + + bool test( char val ) nothrow + { + return val == front; + } + + void popFront() nothrow + { + if ( pos++ >= buf.length ) + assert(false); + } + + + void popFront(int i) nothrow + { + while (i--) + popFront(); + } + + + bool match( char val ) nothrow + { + if (!test(val)) + return false; + else + { + popFront(); + return true; + } + } + + bool match( const(char)[] val ) nothrow + { + foreach (char e; val ) + if (!match( e )) + return false; + + return true; + } + + + void eat( char val ) + { + if ( val == front ) + popFront(); + } + + bool isSymbolNameFront(out bool errStatus) nothrow + { + char val = front; + if ( isDigit( val ) || val == '_' ) + return true; + if ( val != 'Q' ) + return false; + + // check the back reference encoding after 'Q' + val = peekBackref(); + if (val == 0) + { + // invalid back reference + errStatus = true; + return false; + } + + return isDigit( val ); // identifier ref + } + + // return the first character at the back reference + char peekBackref() nothrow + { + assert( front == 'Q' ); + auto n = decodeBackref!1(); + if (!n || n > pos) + return 0; // invalid back reference + + return buf[pos - n]; + } + + size_t decodeBackref(size_t peekAt = 0)() nothrow + { + enum base = 26; + size_t n = 0; + for (size_t p; ; p++) + { + char t; + static if (peekAt > 0) + { + t = peek(peekAt + p); + } + else + { + t = front; + popFront(); + } + if (t < 'A' || t > 'Z') + { + if (t < 'a' || t > 'z') + return 0; // invalid back reference + + n = base * n + t - 'a'; + return n; + } + n = base * n + t - 'A'; + } + } + + ////////////////////////////////////////////////////////////////////////// + // Parsing Implementation + ////////////////////////////////////////////////////////////////////////// + + + /* + Number: + Digit + Digit Number + */ + const(char)[] sliceNumber() return scope + { + auto beg = pos; + + while ( true ) + { + auto t = front; + if (t >= '0' && t <= '9') + popFront(); + else + return buf[beg .. pos]; + } + } + + + size_t decodeNumber(out bool errStatus) scope nothrow + { + return decodeNumber( errStatus, sliceNumber() ); + } + + size_t decodeNumber( out bool errStatus, scope const(char)[] num ) scope nothrow + { + size_t val = 0; + + foreach ( c; num ) + { + import core.checkedint : mulu, addu; + + bool overflow = false; + val = mulu(val, 10, overflow); + val = addu(val, c - '0', overflow); + if (overflow) + { + errStatus = true; + return 0; + } + } + return val; + } + + void parseReal(out bool errStatus) scope nothrow + { + char[64] tbuf = void; + size_t tlen = 0; + real val = void; + + void onError() + { + errStatus = true; + } + + if ( 'I' == front ) + { + if (!match("INF")) + return onError(); + put( "real.infinity" ); + return; + } + if ( 'N' == front ) + { + popFront(); + if ( 'I' == front ) + { + if (!match("INF")) + return onError(); + put( "-real.infinity" ); + return; + } + if ( 'A' == front ) + { + if (!match("AN")) + return onError(); + put( "real.nan" ); + return; + } + tbuf[tlen++] = '-'; + } + + tbuf[tlen++] = '0'; + tbuf[tlen++] = 'X'; + errStatus = !isHexDigit( front ); + if (errStatus) + return; // Expected hex digit + + tbuf[tlen++] = front; + tbuf[tlen++] = '.'; + popFront(); + + while ( isHexDigit( front ) ) + { + if (tlen >= tbuf.length) + return onError(); // Too many hex float digits + tbuf[tlen++] = front; + popFront(); + } + if (!match('P')) + return onError(); + tbuf[tlen++] = 'p'; + if ( 'N' == front ) + { + tbuf[tlen++] = '-'; + popFront(); + } + else + { + tbuf[tlen++] = '+'; + } + while ( isDigit( front ) ) + { + tbuf[tlen++] = front; + popFront(); + } + + tbuf[tlen] = 0; + pureReprintReal( tbuf[] ); + put( tbuf[0 .. tlen] ); + } + + + /* + LName: + Number Name + + Name: + Namestart + Namestart Namechars + + Namestart: + _ + Alpha + + Namechar: + Namestart + Digit + + Namechars: + Namechar + Namechar Namechars + */ + void parseLName(out string errMsg) scope nothrow + { + static if (__traits(hasMember, Hooks, "parseLName")) + { + auto r = hooks.parseLName(errMsg, this); + if (errMsg !is null) + return; + if (r) return; + } + + void error(string msg) + { + errMsg = msg; + } + + if ( front == 'Q' ) + { + // back reference to LName + auto refPos = pos; + popFront(); + size_t n = decodeBackref(); + if (!n || n > refPos) + return error("Invalid LName back reference"); + + if ( !mute ) + { + auto savePos = pos; + scope(exit) pos = savePos; + pos = refPos - n; + parseLName(errMsg); + } + return; + } + + bool err_flag; + auto n = decodeNumber(err_flag); + if (err_flag) + return error("Number overflow"); + + if ( n == 0 ) + { + put( "__anonymous" ); + return; + } + if ( n > buf.length || n > buf.length - pos ) + return error("LName must be at least 1 character"); + + if ( '_' != front && !isAlpha( front ) ) + return error("Invalid character in LName"); + + foreach (char e; buf[pos + 1 .. pos + n] ) + { + if ( '_' != e && !isAlpha( e ) && !isDigit( e ) ) + return error("Invalid character in LName"); + } + + put( buf[pos .. pos + n] ); + pos += n; + } + + + /* + Type: + Shared + Const + Immutable + Wild + TypeArray + TypeVector + TypeStaticArray + TypeAssocArray + TypePointer + TypeFunction + TypeIdent + TypeClass + TypeStruct + TypeEnum + TypeTypedef + TypeDelegate + TypeNone + TypeVoid + TypeNoreturn + TypeByte + TypeUbyte + TypeShort + TypeUshort + TypeInt + TypeUint + TypeLong + TypeUlong + TypeCent + TypeUcent + TypeFloat + TypeDouble + TypeReal + TypeIfloat + TypeIdouble + TypeIreal + TypeCfloat + TypeCdouble + TypeCreal + TypeBool + TypeChar + TypeWchar + TypeDchar + TypeTuple + + Shared: + O Type + + Const: + x Type + + Immutable: + y Type + + Wild: + Ng Type + + TypeArray: + A Type + + TypeVector: + Nh Type + + TypeStaticArray: + G Number Type + + TypeAssocArray: + H Type Type + + TypePointer: + P Type + + TypeFunction: + CallConvention FuncAttrs Arguments ArgClose Type + + TypeIdent: + I LName + + TypeClass: + C LName + + TypeStruct: + S LName + + TypeEnum: + E LName + + TypeTypedef: + T LName + + TypeDelegate: + D TypeFunction + + TypeNone: + n + + TypeVoid: + v + + TypeNoreturn + Nn + + TypeByte: + g + + TypeUbyte: + h + + TypeShort: + s + + TypeUshort: + t + + TypeInt: + i + + TypeUint: + k + + TypeLong: + l + + TypeUlong: + m + + TypeCent + zi + + TypeUcent + zk + + TypeFloat: + f + + TypeDouble: + d + + TypeReal: + e + + TypeIfloat: + o + + TypeIdouble: + p + + TypeIreal: + j + + TypeCfloat: + q + + TypeCdouble: + r + + TypeCreal: + c + + TypeBool: + b + + TypeChar: + a + + TypeWchar: + u + + TypeDchar: + w + + TypeTuple: + B Number Arguments + */ + BufSlice parseType(out bool errStatus) return scope nothrow + { + static immutable string[23] primitives = [ + "char", // a + "bool", // b + "creal", // c + "double", // d + "real", // e + "float", // f + "byte", // g + "ubyte", // h + "int", // i + "ireal", // j + "uint", // k + "long", // l + "ulong", // m + null, // n + "ifloat", // o + "idouble", // p + "cfloat", // q + "cdouble", // r + "short", // s + "ushort", // t + "wchar", // u + "void", // v + "dchar", // w + ]; + + static if (__traits(hasMember, Hooks, "parseType")) + { + auto n = hooks.parseType(errStatus, this, null); + if (errStatus) + return dst.bslice_empty; + else + if (n !is null) + return BufSlice(n, 0, n.length); + } + + auto beg = dst.length; + auto t = front; + + BufSlice parseBackrefType(out string errStatus, scope BufSlice delegate(bool err_flag) pure @safe nothrow parseDg) pure @safe nothrow + { + if (pos == brp) + { + errStatus = "recursive back reference"; + return dst.bslice_empty; + } + + auto refPos = pos; + popFront(); + auto n = decodeBackref(); + if (n == 0 || n > pos) + { + errStatus = "invalid back reference"; + return dst.bslice_empty; + } + + if ( mute ) + return dst.bslice_empty; + auto savePos = pos; + auto saveBrp = brp; + scope(success) { pos = savePos; brp = saveBrp; } + pos = refPos - n; + brp = refPos; + + bool err_flag; + auto ret = parseDg(err_flag); + if (err_flag) + { + errStatus = "parseDg error"; + return dst.bslice_empty; + } + + return ret; + } + + // call parseType() and return error if occured + enum parseTypeOrF = "parseType(errStatus); if (errStatus) return dst.bslice_empty;"; + + switch ( t ) + { + case 'Q': // Type back reference + string errMsg; + auto r = parseBackrefType(errMsg, (e_flag) => parseType(e_flag)); + if (errMsg !is null) + return dst.bslice_empty; + return r; + case 'O': // Shared (O Type) + popFront(); + put( "shared(" ); + mixin(parseTypeOrF); + put( ')' ); + return dst[beg .. $]; + case 'x': // Const (x Type) + popFront(); + put( "const(" ); + mixin(parseTypeOrF); + put( ')' ); + return dst[beg .. $]; + case 'y': // Immutable (y Type) + popFront(); + put( "immutable(" ); + mixin(parseTypeOrF); + put( ')' ); + return dst[beg .. $]; + case 'N': + popFront(); + switch ( front ) + { + case 'n': // Noreturn + popFront(); + put("noreturn"); + return dst[beg .. $]; + case 'g': // Wild (Ng Type) + popFront(); + // TODO: Anything needed here? + put( "inout(" ); + mixin(parseTypeOrF); + put( ')' ); + return dst[beg .. $]; + case 'h': // TypeVector (Nh Type) + popFront(); + put( "__vector(" ); + mixin(parseTypeOrF); + put( ')' ); + return dst[beg .. $]; + default: + errStatus = true; + return dst.bslice_empty; + } + case 'A': // TypeArray (A Type) + popFront(); + mixin(parseTypeOrF); + put( "[]" ); + return dst[beg .. $]; + case 'G': // TypeStaticArray (G Number Type) + popFront(); + auto num = sliceNumber(); + mixin(parseTypeOrF); + put( '[' ); + put( num ); + put( ']' ); + return dst[beg .. $]; + case 'H': // TypeAssocArray (H Type Type) + popFront(); + // skip t1 + auto tx = parseType(errStatus); + if (errStatus) + return dst.bslice_empty; + mixin(parseTypeOrF); + put( '[' ); + shift(tx); + put( ']' ); + return dst[beg .. $]; + case 'P': // TypePointer (P Type) + popFront(); + mixin(parseTypeOrF); + put( '*' ); + return dst[beg .. $]; + case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction + auto r = parseTypeFunction(errStatus); + if (errStatus) + return dst.bslice_empty; + return r; + case 'C': // TypeClass (C LName) + case 'S': // TypeStruct (S LName) + case 'E': // TypeEnum (E LName) + case 'T': // TypeTypedef (T LName) + popFront(); + parseQualifiedName(errStatus); + if (errStatus) + return dst.bslice_empty; + return dst[beg .. $]; + case 'D': // TypeDelegate (D TypeFunction) + popFront(); + auto modifiers = parseModifier(); + if ( front == 'Q' ) + { + string errMsg; + auto r = parseBackrefType(errMsg, (e_flag) => parseTypeFunction(e_flag, IsDelegate.yes)); + if (errMsg !is null) + return dst.bslice_empty; + return r; + } + else + { + parseTypeFunction(errStatus, IsDelegate.yes); + if (errStatus) + return dst.bslice_empty; + } + + if (modifiers) + { + // write modifiers behind the function arguments + while (auto str = typeCtors.toStringConsume(modifiers)) + { + put(' '); + put(str); + } + } + return dst[beg .. $]; + case 'n': // TypeNone (n) + popFront(); + // TODO: Anything needed here? + return dst[beg .. $]; + case 'B': // TypeTuple (B Number Arguments) + popFront(); + // TODO: Handle this. + return dst[beg .. $]; + case 'Z': // Internal symbol + // This 'type' is used for untyped internal symbols, i.e.: + // __array + // __init + // __vtbl + // __Class + // __Interface + // __ModuleInfo + popFront(); + return dst[beg .. $]; + default: + if (t >= 'a' && t <= 'w') + { + popFront(); + put( primitives[cast(size_t)(t - 'a')] ); + return dst[beg .. $]; + } + else if (t == 'z') + { + popFront(); + switch ( front ) + { + case 'i': + popFront(); + put( "cent" ); + return dst[beg .. $]; + case 'k': + popFront(); + put( "ucent" ); + return dst[beg .. $]; + default: + errStatus = true; + return dst.bslice_empty; + } + } + errStatus = true; + return dst.bslice_empty; + } + } + + + /* + TypeFunction: + CallConvention FuncAttrs Arguments ArgClose Type + + CallConvention: + F // D + U // C + W // Windows + R // C++ + + FuncAttrs: + FuncAttr + FuncAttr FuncAttrs + + FuncAttr: + empty + FuncAttrPure + FuncAttrNothrow + FuncAttrProperty + FuncAttrRef + FuncAttrReturn + FuncAttrScope + FuncAttrTrusted + FuncAttrSafe + + FuncAttrPure: + Na + + FuncAttrNothrow: + Nb + + FuncAttrRef: + Nc + + FuncAttrProperty: + Nd + + FuncAttrTrusted: + Ne + + FuncAttrSafe: + Nf + + FuncAttrNogc: + Ni + + FuncAttrReturn: + Nj + + FuncAttrScope: + Nl + + Arguments: + Argument + Argument Arguments + + Argument: + Argument2 + M Argument2 // scope + + Argument2: + Type + J Type // out + K Type // ref + L Type // lazy + + ArgClose + X // variadic T t,...) style + Y // variadic T t...) style + Z // not variadic + */ + void parseCallConvention(out bool errStatus) nothrow + { + // CallConvention + switch ( front ) + { + case 'F': // D + popFront(); + break; + case 'U': // C + popFront(); + put( "extern (C) " ); + break; + case 'W': // Windows + popFront(); + put( "extern (Windows) " ); + break; + case 'R': // C++ + popFront(); + put( "extern (C++) " ); + break; + default: + errStatus = true; + } + } + + /// Returns: Flags of `TypeCtor` + ushort parseModifier() + { + TypeCtor res = TypeCtor.None; + switch ( front ) + { + case 'y': + popFront(); + return TypeCtor.Immutable; + case 'O': + popFront(); + res |= TypeCtor.Shared; + if (front == 'x') + goto case 'x'; + if (front == 'N') + goto case 'N'; + return TypeCtor.Shared; + case 'N': + if (peek( 1 ) != 'g') + return res; + popFront(); + popFront(); + res |= TypeCtor.InOut; + if ( front == 'x' ) + goto case 'x'; + return res; + case 'x': + popFront(); + res |= TypeCtor.Const; + return res; + default: return TypeCtor.None; + } + } + + ushort parseFuncAttr(out bool errStatus) nothrow + { + // FuncAttrs + ushort result; + while ('N' == front) + { + popFront(); + switch ( front ) + { + case 'a': // FuncAttrPure + popFront(); + result |= FuncAttributes.Pure; + continue; + case 'b': // FuncAttrNoThrow + popFront(); + result |= FuncAttributes.Nothrow; + continue; + case 'c': // FuncAttrRef + popFront(); + result |= FuncAttributes.Ref; + continue; + case 'd': // FuncAttrProperty + popFront(); + result |= FuncAttributes.Property; + continue; + case 'e': // FuncAttrTrusted + popFront(); + result |= FuncAttributes.Trusted; + continue; + case 'f': // FuncAttrSafe + popFront(); + result |= FuncAttributes.Safe; + continue; + case 'g': + case 'h': + case 'k': + case 'n': + // NOTE: The inout parameter type is represented as "Ng". + // The vector parameter type is represented as "Nh". + // The return parameter type is represented as "Nk". + // The noreturn parameter type is represented as "Nn". + // These make it look like a FuncAttr, but infact + // if we see these, then we know we're really in + // the parameter list. Rewind and break. + pos--; + return result; + case 'i': // FuncAttrNogc + popFront(); + result |= FuncAttributes.NoGC; + continue; + case 'j': // FuncAttrReturn + popFront(); + if (this.peek(0) == 'N' && this.peek(1) == 'l') + { + result |= FuncAttributes.ReturnScope; + popFront(); + popFront(); + } else { + result |= FuncAttributes.Return; + } + continue; + case 'l': // FuncAttrScope + popFront(); + if (this.peek(0) == 'N' && this.peek(1) == 'j') + { + result |= FuncAttributes.ScopeReturn; + popFront(); + popFront(); + } else { + result |= FuncAttributes.Scope; + } + continue; + case 'm': // FuncAttrLive + popFront(); + result |= FuncAttributes.Live; + continue; + default: + errStatus = true; + return 0; + } + } + return result; + } + + void parseFuncArguments(out bool errStatus) scope nothrow + { + // Arguments + for ( size_t n = 0; true; n++ ) + { + switch ( front ) + { + case 'X': // ArgClose (variadic T t...) style) + popFront(); + put( "..." ); + return; + case 'Y': // ArgClose (variadic T t,...) style) + popFront(); + put( ", ..." ); + return; + case 'Z': // ArgClose (not variadic) + popFront(); + return; + default: + break; + } + putComma(n); + + /* Do special return, scope, ref, out combinations + */ + int npops; + if ( 'M' == front && peek(1) == 'N' && peek(2) == 'k') + { + const c3 = peek(3); + if (c3 == 'J') + { + put("scope return out "); // MNkJ + npops = 4; + } + else if (c3 == 'K') + { + put("scope return ref "); // MNkK + npops = 4; + } + } + else if ('N' == front && peek(1) == 'k') + { + const c2 = peek(2); + if (c2 == 'J') + { + put("return out "); // NkJ + npops = 3; + } + else if (c2 == 'K') + { + put("return ref "); // NkK + npops = 3; + } + else if (c2 == 'M') + { + const c3 = peek(3); + if (c3 == 'J') + { + put("return scope out "); // NkMJ + npops = 4; + } + else if (c3 == 'K') + { + put("return scope ref "); // NkMK + npops = 4; + } + else + { + put("return scope "); // NkM + npops = 3; + } + } + } + popFront(npops); + + if ( 'M' == front ) + { + popFront(); + put( "scope " ); + } + if ( 'N' == front ) + { + popFront(); + if ( 'k' == front ) // Return (Nk Parameter2) + { + popFront(); + put( "return " ); + } + else + pos--; + } + + // call parseType() and return error if occured + enum parseTypeOrF = "parseType(errStatus); if (errStatus) return;"; + + switch ( front ) + { + case 'I': // in (I Type) + popFront(); + put("in "); + if (front == 'K') + goto case; + mixin(parseTypeOrF); + continue; + case 'K': // ref (K Type) + popFront(); + put( "ref " ); + mixin(parseTypeOrF); + continue; + case 'J': // out (J Type) + popFront(); + put( "out " ); + mixin(parseTypeOrF); + continue; + case 'L': // lazy (L Type) + popFront(); + put( "lazy " ); + mixin(parseTypeOrF); + continue; + default: + mixin(parseTypeOrF); + } + } + } + + enum IsDelegate { no, yes } + + /* + TypeFunction: + CallConvention FuncAttrs Arguments ArgClose Type + */ + BufSlice parseTypeFunction(out bool errStatus, IsDelegate isdg = IsDelegate.no) return scope nothrow + { + auto beg = dst.length; + + parseCallConvention(errStatus); + if (errStatus) + return dst.bslice_empty; + + auto attributes = parseFuncAttr(errStatus); + if (errStatus) + return dst.bslice_empty; + + auto argbeg = dst.length; + put(IsDelegate.yes == isdg ? "delegate" : "function"); + put( '(' ); + parseFuncArguments(errStatus); + if (errStatus) + return dst.bslice_empty; + put( ')' ); + if (attributes) + { + // write function attributes behind arguments + while (auto str = funcAttrs.toStringConsume(attributes)) + { + put(' '); + put(str); + } + } + + // A function / delegate return type is located at the end of its mangling + // Write it in order, then shift it back to 'code order' + // e.g. `delegate(int) @safedouble ' => 'double delegate(int) @safe' + { + auto retbeg = dst.length; + parseType(errStatus); + if (errStatus) + return dst.bslice_empty; + put(' '); + shift(dst[argbeg .. retbeg]); + } + + return dst[beg .. $]; + } + + static bool isCallConvention( char ch ) + { + switch ( ch ) + { + case 'F', 'U', 'V', 'W', 'R': + return true; + default: + return false; + } + } + + /* + Value: + n + Number + i Number + N Number + e HexFloat + c HexFloat c HexFloat + A Number Value... + + HexFloat: + NAN + INF + NINF + N HexDigits P Exponent + HexDigits P Exponent + + Exponent: + N Number + Number + + HexDigits: + HexDigit + HexDigit HexDigits + + HexDigit: + Digit + A + B + C + D + E + F + */ + + void parseValue(out bool errStatus) scope nothrow + { + parseValue(errStatus, dst.bslice_empty); + } + + void parseValue(out bool errStatus, scope BufSlice name, char type = '\0' ) scope nothrow + { + void onError() + { + errStatus = true; + } + + switch ( front ) + { + case 'n': + popFront(); + put( "null" ); + return; + case 'i': + popFront(); + if ('0' > front || '9' < front) + return onError(); // Number expected + goto case; + case '0': .. case '9': + parseIntegerValue( errStatus, name, type ); + return; + case 'N': + popFront(); + put( '-' ); + parseIntegerValue( errStatus, name, type ); + return; + case 'e': + popFront(); + parseReal(errStatus); + return; + case 'c': + popFront(); + parseReal(errStatus); + if (errStatus) + return; + put( '+' ); + if (!match('c')) + return onError(); + parseReal(errStatus); + if (errStatus) + return; + put( 'i' ); + return; + case 'a': case 'w': case 'd': + char t = front; + popFront(); + auto n = decodeNumber(errStatus); + if (errStatus) + return; + if (!match('_')) + return onError(); + put( '"' ); + foreach (i; 0..n) + { + auto a = ascii2hex( errStatus, front ); + if (errStatus) + return; + popFront(); + + auto b = ascii2hex( errStatus, front ); + if (errStatus) + return; + popFront(); + + auto v = cast(char)((a << 4) | b); + if (' ' <= v && v <= '~') // ASCII printable + { + put(v); + } + else + { + put("\\x"); + putAsHex(v, 2); + } + } + put( '"' ); + if ( 'a' != t ) + put(t); + return; + case 'A': + // NOTE: This is kind of a hack. An associative array literal + // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type + // is "Hii" and the value is "A2i1i2i3i4". Thus the only + // way to determine that this is an AA value rather than an + // array value is for the caller to supply the type char. + // Hopefully, this will change so that the value is + // "H2i1i2i3i4", rendering this unnecesary. + if ( 'H' == type ) + goto LassocArray; + // A Number Value... + // An array literal. Value is repeated Number times. + popFront(); + put( '[' ); + auto n = decodeNumber(errStatus); + if (errStatus) + return; + foreach ( i; 0 .. n ) + { + putComma(i); + parseValue(errStatus); + if (errStatus) + return; + } + put( ']' ); + return; + case 'H': + LassocArray: + // H Number Value... + // An associative array literal. Value is repeated 2*Number times. + popFront(); + put( '[' ); + auto n = decodeNumber(errStatus); + if (errStatus) + return; + foreach ( i; 0 .. n ) + { + putComma(i); + parseValue(errStatus); + if (errStatus) + return; + put(':'); + parseValue(errStatus); + if (errStatus) + return; + } + put( ']' ); + return; + case 'S': + // S Number Value... + // A struct literal. Value is repeated Number times. + popFront(); + if ( name.length ) + put( name ); + put( '(' ); + auto n = decodeNumber(errStatus); + if (errStatus) + return; + foreach ( i; 0 .. n ) + { + putComma(i); + parseValue(errStatus); + if (errStatus) + return; + } + put( ')' ); + return; + case 'f': + // f MangledName + // A function literal symbol + popFront(); + parseMangledName(errStatus, false, 1); + return; + default: + errStatus = true; + } + } + + void parseIntegerValue( out bool errStatus, scope BufSlice name, char type = '\0' ) scope nothrow + { + switch ( type ) + { + case 'a': // char + case 'u': // wchar + case 'w': // dchar + { + auto val = sliceNumber(); + auto num = decodeNumber( errStatus, val ); + if (errStatus) + return; + + switch ( num ) + { + case '\'': + put( "'\\''" ); + return; + // \", \? + case '\\': + put( "'\\\\'" ); + return; + case '\a': + put( "'\\a'" ); + return; + case '\b': + put( "'\\b'" ); + return; + case '\f': + put( "'\\f'" ); + return; + case '\n': + put( "'\\n'" ); + return; + case '\r': + put( "'\\r'" ); + return; + case '\t': + put( "'\\t'" ); + return; + case '\v': + put( "'\\v'" ); + return; + default: + switch ( type ) + { + case 'a': + if ( num >= 0x20 && num < 0x7F ) + { + put( '\'' ); + put( cast(char)num ); + put( '\'' ); + return; + } + put( "\\x" ); + putAsHex( num, 2 ); + return; + case 'u': + put( "'\\u" ); + putAsHex( num, 4 ); + put( '\'' ); + return; + case 'w': + put( "'\\U" ); + putAsHex( num, 8 ); + put( '\'' ); + return; + default: + assert( 0 ); + } + } + } + case 'b': // bool + auto d = decodeNumber(errStatus); + if (errStatus) + return; + put( d ? "true" : "false" ); + return; + case 'h', 't', 'k': // ubyte, ushort, uint + put( sliceNumber() ); + put( 'u' ); + return; + case 'l': // long + put( sliceNumber() ); + put( 'L' ); + return; + case 'm': // ulong + put( sliceNumber() ); + put( "uL" ); + return; + default: + put( sliceNumber() ); + return; + } + } + + + /* + TemplateArgs: + TemplateArg + TemplateArg TemplateArgs + + TemplateArg: + TemplateArgX + H TemplateArgX + + TemplateArgX: + T Type + V Type Value + S Number_opt QualifiedName + X ExternallyMangledName + */ + void parseTemplateArgs(out bool errStatus) scope nothrow + { + L_nextArg: + for ( size_t n = 0; true; n++ ) + { + if ( front == 'H' ) + popFront(); + + switch ( front ) + { + case 'T': + popFront(); + putComma(n); + parseType(errStatus); + if (errStatus) + return; + continue; + case 'V': + popFront(); + putComma(n); + // NOTE: In the few instances where the type is actually + // desired in the output it should precede the value + // generated by parseValue, so it is safe to simply + // decrement len and let put/append do its thing. + char t = front; // peek at type for parseValue + if ( t == 'Q' ) + { + t = peekBackref(); + if (t == 0) + { + // invalid back reference + errStatus = true; + return; + } + } + BufSlice name = dst.bslice_empty; + silent( errStatus, delegate void(out bool e_flg) nothrow { name = parseType(e_flg); } ); + if (errStatus) + return; + parseValue( errStatus, name, t ); + if (errStatus) + return; + continue; + case 'S': + popFront(); + putComma(n); + + if ( mayBeMangledNameArg() ) + { + auto l = dst.length; + auto p = pos; + auto b = brp; + + if (parseMangledNameArg()) + continue; + dst.len = l; + pos = p; + brp = b; + } + if ( isDigit( front ) && isDigit( peek( 1 ) ) ) + { + // ambiguity: length followed by qualified name (starting with number) + // try all possible pairs of numbers + auto qlen = decodeNumber(errStatus); + if (errStatus) + return; + + qlen /= 10; // last digit needed for QualifiedName + pos--; + auto l = dst.length; + auto p = pos; + auto b = brp; + while ( qlen > 0 ) + { + errStatus = false; + parseQualifiedName(errStatus); + + if (!errStatus) + { + if ( pos == p + qlen ) + continue L_nextArg; + } + + qlen /= 10; // retry with one digit less + pos = --p; + dst.len = l; + brp = b; + } + } + + parseQualifiedName(errStatus); + if (errStatus) + return; + continue; + case 'X': + popFront(); + putComma(n); + { + string errMsg; + parseLName(errMsg); + if (errMsg) + return; + } + continue; + default: + return; + } + } + } + + + bool mayBeMangledNameArg() nothrow + { + bool errStatus; + auto p = pos; + scope(exit) pos = p; + + if ( isDigit( buf[pos] ) ) + { + auto n = decodeNumber(errStatus); + + return !errStatus && n >= 4 && + pos < buf.length && '_' == buf[pos++] && + pos < buf.length && 'D' == buf[pos++] && + isDigit( buf[pos] ); + } + else + { + const isSNF = isSymbolNameFront(errStatus); + + return !errStatus && + pos < buf.length && '_' == buf[pos++] && + pos < buf.length && 'D' == buf[pos++] && + isSNF; + } + } + + bool parseMangledNameArg() nothrow + { + bool errStatus; + + size_t n = 0; + if ( isDigit( front ) ) + { + n = decodeNumber(errStatus); + + if (errStatus) + return false; + } + + parseMangledName(errStatus, false, n ); + + return !errStatus; + } + + /* + TemplateInstanceName: + Number __T LName TemplateArgs Z + */ + void parseTemplateInstanceName(out bool errStatus, bool hasNumber) scope nothrow + { + auto sav = pos; + auto saveBrp = brp; + + void onError() + { + errStatus = true; + pos = sav; + brp = saveBrp; + } + + size_t n = 0; + if (hasNumber) + { + n = decodeNumber(errStatus); + if (errStatus) + return onError(); + } + + auto beg = pos; + errStatus = !match( "__T" ); + if (errStatus) + return onError(); + + { + string errMsg; + parseLName(errMsg); + if (errMsg !is null) + return onError(); + } + + put( "!(" ); + + parseTemplateArgs(errStatus); + if (errStatus) + return onError(); + + if (!match('Z')) + return onError(); + + if ( hasNumber && pos - beg != n ) + { + // Template name length mismatch + return onError(); + } + + put( ')' ); + } + + + bool mayBeTemplateInstanceName() scope nothrow + { + auto p = pos; + scope(exit) pos = p; + + bool errStatus; + auto n = decodeNumber(errStatus); + if (errStatus) + return false; + + return n >= 5 && + pos < buf.length && '_' == buf[pos++] && + pos < buf.length && '_' == buf[pos++] && + pos < buf.length && 'T' == buf[pos++]; + } + + + /* + SymbolName: + LName + TemplateInstanceName + */ + void parseSymbolName(out bool errStatus) scope nothrow + { + // LName -> Number + // TemplateInstanceName -> Number "__T" + switch ( front ) + { + case '_': + // no length encoding for templates for new mangling + parseTemplateInstanceName(errStatus, false); + return; + + case '0': .. case '9': + if ( mayBeTemplateInstanceName() ) + { + auto t = dst.length; + + parseTemplateInstanceName(errStatus, true); + if (!errStatus) + return; + else + { + dst.len = t; + } + } + goto case; + case 'Q': + string errMsg; + parseLName(errMsg); + errStatus = errMsg !is null; + return; + default: + errStatus = true; + } + } + + // parse optional function arguments as part of a symbol name, i.e without return type + // if keepAttr, the calling convention and function attributes are not discarded, but returned + BufSlice parseFunctionTypeNoReturn( bool keepAttr = false ) return scope nothrow + { + // try to demangle a function, in case we are pointing to some function local + auto prevpos = pos; + auto prevlen = dst.length; + auto prevbrp = brp; + + if ( 'M' == front ) + { + // do not emit "needs this" + popFront(); + auto modifiers = parseModifier(); + while (auto str = typeCtors.toStringConsume(modifiers)) + { + put(str); + put(' '); + } + } + if ( isCallConvention( front ) ) + { + BufSlice attr = dst.bslice_empty; + // we don't want calling convention and attributes in the qualified name + bool errStatus; + parseCallConvention(errStatus); + if (!errStatus) + { + auto attributes = parseFuncAttr(errStatus); + if (!errStatus) + { + if (keepAttr) { + while (auto str = funcAttrs.toStringConsume(attributes)) + { + put(str); + put(' '); + } + attr = dst[prevlen .. $]; + } + + put( '(' ); + parseFuncArguments(errStatus); + if (errStatus) + return dst.bslice_empty; + put( ')' ); + return attr; + } + } + + // not part of a qualified name, so back up + pos = prevpos; + dst.len = prevlen; + brp = prevbrp; + } + + return dst.bslice_empty; + } + + /* + QualifiedName: + SymbolName + SymbolName QualifiedName + */ + void parseQualifiedName(out bool errStatus) return scope nothrow + { + size_t n = 0; + bool is_sym_name_front; + + do + { + if ( n++ ) + put( '.' ); + + parseSymbolName(errStatus); + if (errStatus) + return; + + parseFunctionTypeNoReturn(); + + is_sym_name_front = isSymbolNameFront(errStatus); + if (errStatus) + return; + + } while ( is_sym_name_front ); + } + + + /* + MangledName: + _D QualifiedName Type + _D QualifiedName M Type + */ + void parseMangledName( out bool errStatus, bool displayType, size_t n = 0 ) scope nothrow + { + BufSlice name = dst.bslice_empty; + + auto end = pos + n; + + eat( '_' ); + errStatus = !match( 'D' ); + if (errStatus) + return; + + do + { + size_t beg = dst.length; + size_t nameEnd = dst.length; + BufSlice attr = dst.bslice_empty; + bool is_sym_name_front; + + do + { + if ( attr.length ) + dst.remove(attr); // dump attributes of parent symbols + if (beg != dst.length) + put( '.' ); + + parseSymbolName(errStatus); + if (errStatus) + return; + + nameEnd = dst.length; + attr = parseFunctionTypeNoReturn( displayType ); + + is_sym_name_front = isSymbolNameFront(errStatus); + if (errStatus) + return; + } while (is_sym_name_front); + + if ( displayType ) + { + attr = shift( attr ); + nameEnd = dst.length - attr.length; // name includes function arguments + } + name = dst[beg .. nameEnd]; + + if ( 'M' == front ) + popFront(); // has 'this' pointer + + auto lastlen = dst.length; + auto type = parseType(errStatus); + if (errStatus) + return; + + if ( displayType ) + { + if ( type.length ) + put( ' ' ); + // sort (name,attr,type) -> (attr,type,name) + shift( name ); + } + else + { + // remove type + assert( attr.length == 0 ); + dst.len = lastlen; + } + if ( pos >= buf.length || (n != 0 && pos >= end) ) + return; + + switch ( front ) + { + case 'T': // terminators when used as template alias parameter + case 'V': + case 'S': + case 'Z': + return; + default: + } + put( '.' ); + + } while ( true ); + } + + void parseMangledName(out bool errStatus) nothrow + { + parseMangledName(errStatus, AddType.yes == addType); + } + + char[] doDemangle(alias FUNC)() return scope nothrow + { + while ( true ) + { + bool errStatus; + FUNC(errStatus); + if (!errStatus) + { + return dst[0 .. $].getSlice; + } + else + { + return dst.copyInput(buf); + } + } + } + + char[] demangleName() nothrow + { + return doDemangle!parseMangledName(); + } + + char[] demangleType() nothrow + { + return doDemangle!parseType(); + } +} + +private struct Buffer +{ + enum size_t minSize = 4000; + + @safe pure: + + private char[] dst; + private size_t len; + + public alias opDollar = len; + + public size_t length () const scope @safe pure nothrow @nogc + { + return this.len; + } + + public BufSlice opSlice (size_t from, size_t to) + return scope @safe pure nothrow @nogc + { + return bslice(from, to); + } + + static bool contains(scope const(char)[] a, scope const BufSlice b) @safe nothrow + { + return + b.from < a.length && + b.to <= a.length; + } + + char[] copyInput(scope const(char)[] buf) + return scope nothrow + { + if (dst.length < buf.length) + dst.length = buf.length; + char[] r = dst[0 .. buf.length]; + r[] = buf[]; + return r; + } + + private void checkAndStretchBuf(size_t len_to_add) scope nothrow + { + const required = len + len_to_add; + + if (required > dst.length) + dst.length = dst.length + len_to_add; + } + + // move val to the end of the dst buffer + BufSlice shift(scope const BufSlice val) return scope nothrow + { + version (DigitalMars) pragma(inline, false); // tame dmd inliner + + if (val.length) + { + const ptrdiff_t s = val.from; + const size_t f = len; + + assert(contains( dst[0 .. len], val ), + "\ndst=\""~dst[0 .. len]~"\"\n"~ + "val=\""~val.getSlice~"\"\n" + ); + + checkAndStretchBuf(val.length); + + // store value temporary over len index + dst[len .. len + val.length] = val.getSlice(); + + // shift all chars including temporary saved above + // if buf was allocated above it will be leave for further usage + for (size_t p = s; p < f; p++) + dst[p] = dst[p + val.length]; + + return bslice(len - val.length, len); + } + + return bslice_empty; + } + + // remove val from dst buffer + void remove(scope BufSlice val) scope nothrow + { + version (DigitalMars) pragma(inline, false); // tame dmd inliner + + if ( val.length ) + { + assert( contains( dst[0 .. len], val ) ); + + assert( len >= val.length && len <= dst.length ); + len -= val.length; + for (size_t p = val.from; p < len; p++) + dst[p] = dst[p + val.length]; + } + } + + void append(scope const(char)[] val) scope nothrow + { + version (DigitalMars) pragma(inline, false); // tame dmd inliner + + if (val.length) + { + if ( !dst.length ) + dst.length = minSize; + + checkAndStretchBuf(val.length); + + // data is already not in place? + if ( &dst[len] != &val[0] ) + dst[len .. len + val.length] = val[]; + + len += val.length; + } + } + + @nogc: + + private scope bslice(size_t from, size_t to) nothrow + { + return BufSlice(dst, from, to); + } + + private static scope bslice_empty() nothrow + { + return BufSlice.init; + } +} + +private struct BufSlice +{ + char[] buf; + size_t from; + size_t to; + + @safe pure nothrow: + + @disable this(); + + this(return scope char[] buf) scope nothrow @nogc + { + this(buf, 0, 0); + } + + this(return scope char[] buf, size_t from, size_t to, bool lastArgIsLen = false) scope nothrow @nogc + { + this.buf = buf; + this.from = from; + + if (lastArgIsLen) + this.to = from + to; + else + this.to = to; + } + + invariant + { + if (buf is null) + { + assert(from == 0); + assert(to == 0); + } + + assert(from <= to); + } + + auto getSlice() inout nothrow scope { return buf[from .. to]; } + size_t length() const scope { return to - from; } +} + +/** + * Demangles a D mangled type. + * + * Params: + * buf = The string to demangle. + * dst = An optional destination buffer. + * + * Returns: + * The demangled type name or the original string if the name is not a + * mangled D type. +*/ +char[] demangleType( const(char)[] buf, char[] dst = null ) nothrow pure @safe +{ + auto d = Demangle!()(buf, dst); + return d.demangleType(); +} + +extern (C) private +{ + pure @trusted @nogc nothrow pragma(mangle, "fakePureReprintReal") void pureReprintReal(char[] nptr); + + void fakePureReprintReal(char[] nptr) + { + import core.stdc.stdlib : strtold; + import core.stdc.stdio : snprintf; + import core.stdc.errno : errno; + + const err = errno; + real val = strtold(nptr.ptr, null); + snprintf(nptr.ptr, nptr.length, "%#Lg", val); + errno = err; + } +} diff --git a/external/arsd-webassembly/core/internal/cast_.d b/external/arsd-webassembly/core/internal/cast_.d new file mode 100644 index 0000000..dd2eb03 --- /dev/null +++ b/external/arsd-webassembly/core/internal/cast_.d @@ -0,0 +1,206 @@ +module core.internal.cast_; + +// Needed because ClassInfo.opEquals(Object) does a dynamic cast, +// but we are trying to implement dynamic cast. +bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) pure nothrow @safe @nogc +{ + // same class if signatures match, works with potential duplicates across binaries + if (a is b) + return true; + + // new fast way + if (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig) + return a.nameSig[0] == b.nameSig[0] + && a.nameSig[1] == b.nameSig[1] + && a.nameSig[2] == b.nameSig[2] + && a.nameSig[3] == b.nameSig[3]; + + // old slow way for temporary binary compatibility + return a.name == b.name; +} + + +/***** + * Dynamic cast from a class object `o` to class or interface `To`, where `To` is a subtype of `o`. + * Params: + * o = instance of class + * To = class or interface that is a subtype of `o` + * Returns: + * null if `o` is null or `To` is not a subclass type of `o`. Otherwise, return `o`. + */ +private void* _d_dynamic_cast(To)(const return scope Object o) @trusted +{ + void* res = null; + size_t offset = 0; + + if (o && _d_isbaseof2!To(typeid(o), offset)) + { + res = cast(void*) o + offset; + } + return res; +} + +/** + * Dynamic cast `o` to final class `To` only one level down + * Params: + * o = object that is instance of a class + * To = final class that is a subclass type of `o` + * Returns: + * o if it succeeds, null if it fails + */ +private void* _d_paint_cast(To)(const return scope Object o) +{ + /* If o is really an instance of c, just do a paint + */ + auto p = o && cast(void*)(areClassInfosEqual(typeid(o), typeid(To).info)) ? o : null; + debug assert(cast(void*)p is cast(void*)_d_dynamic_cast!To(o)); + return cast(void*)p; +} + +private void* _d_class_cast_impl(const return scope Object o, const ClassInfo c) pure nothrow @safe @nogc +{ + if (!o) + return null; + + ClassInfo oc = typeid(o); + int delta = oc.depth; + + if (delta && c.depth) + { + delta -= c.depth; + if (delta < 0) + return null; + + while (delta--) + oc = oc.base; + if (areClassInfosEqual(oc, c)) + return cast(void*)o; + return null; + } + + // no depth data - support the old way + do + { + if (areClassInfosEqual(oc, c)) + return cast(void*)o; + oc = oc.base; + } while (oc); + return null; +} + +/***** + * Dynamic cast from a class object o to class type `To`, where `To` is a subclass type of `o`. + * Params: + * o = instance of class + * To = a subclass type of o + * Returns: + * null if `o` is null or `To` is not a subclass type of `o`. Otherwise, return `o`. + */ +private void* _d_class_cast(To)(const return scope Object o) +{ + return _d_class_cast_impl(o, typeid(To)); +} + +/************************************* + * Attempts to cast interface Object o to class type `To`. + * Returns o if successful, null if not. + */ +private void* _d_interface_cast(To)(void* p) @trusted +{ + if (!p) + return null; + + Interface* pi = **cast(Interface***) p; + + Object o2 = cast(Object)(p - pi.offset); + void* res = null; + size_t offset = 0; + if (o2 && _d_isbaseof2!To(typeid(o2), offset)) + { + res = cast(void*) o2 + offset; + } + return res; +} + +/** +* Hook that detects the type of cast performed and calls the appropriate function. +* Params: +* o = object that is being casted +* To = type to which the object is being casted +* Returns: +* null if the cast fails, otherwise returns the object casted to the type `To`. +*/ +void* _d_cast(To, From)(From o) @trusted +{ + static if (is(From == To)) + { + return *cast(void**) &o; + } + else static if (is(From == class) && is(To == interface)) + { + return _d_dynamic_cast!To(o); + } + else static if (is(From == class) && is(To == class)) + { + + /* Check for: + * class A { } + * final class B : A { } + * ... cast(B) A ... + */ + /* Multiple inheritance is not allowed, so we can safely assume + * that the second super can only be an interface. + */ + static if (is(From FromSupers == super) && is(To ToSupers == super) && + __traits(isFinalClass, To) && is(ToSupers[0] == From) && + ToSupers.length == 1 && FromSupers.length <= 1) + { + return _d_paint_cast!To(o); + } + else static if (is (To : From)) + { + return _d_class_cast!To(o); + } + else + { + return null; + } + } + else static if (is(From == interface)) + { + return _d_interface_cast!To(cast(void*)o); + } + else + { + return null; + } +} + +private bool _d_isbaseof2(To)(scope ClassInfo oc, scope ref size_t offset) +{ + auto c = typeid(To).info; + + if (areClassInfosEqual(oc, c)) + return true; + + do + { + if (oc.base && areClassInfosEqual(oc.base, c)) + return true; + + // Bugzilla 2013: Use depth-first search to calculate offset + // from the derived (oc) to the base (c). + foreach (iface; oc.interfaces) + { + if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof2!To(iface.classinfo, offset)) + { + offset += iface.offset; + return true; + } + } + + oc = oc.base; + } while (oc); + + return false; +} diff --git a/external/arsd-webassembly/core/internal/lifetime.d b/external/arsd-webassembly/core/internal/lifetime.d new file mode 100644 index 0000000..0c604d8 --- /dev/null +++ b/external/arsd-webassembly/core/internal/lifetime.d @@ -0,0 +1,31 @@ +module core.internal.lifetime; + +void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted +if (!is(T == const) && !is(T == immutable) && !is(T == inout)) +{ + import core.internal.traits : hasElaborateAssign; + + static if (__traits(isZeroInit, T)) + { + import core.stdc.string : memset; + memset(cast(void*) &chunk, 0, T.sizeof); + } + else static if (__traits(isScalar, T) || T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) + { + chunk = T.init; + } + else static if (__traits(isStaticArray, T)) + { + // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. + foreach (i; 0 .. T.length) + { + emplaceInitializer(chunk[i]); + } + } + else + { + import core.stdc.string : memcpy; + const initializer = __traits(initSymbol, T); + memcpy(cast(void*)&chunk, initializer.ptr, initializer.length); + } +} diff --git a/external/arsd-webassembly/core/internal/string.d b/external/arsd-webassembly/core/internal/string.d new file mode 100644 index 0000000..a49bfcf --- /dev/null +++ b/external/arsd-webassembly/core/internal/string.d @@ -0,0 +1,53 @@ +module core.internal.string; + +alias UnsignedStringBuf = char[64]; + +T[] unsignedToTempString(uint radix = 10, bool upperCase = false, T)(ulong value, return scope T[] buf) +if (radix >= 2 && radix <= 36 && + (is(T == char) || is(T == wchar) || is(T == dchar))) +{ + enum baseChar = upperCase ? 'A' : 'a'; + size_t i = buf.length; + + static if (size_t.sizeof == 4) // 32 bit CPU + { + if (value <= uint.max) + { + // use faster 32 bit arithmetic + uint val = cast(uint) value; + do + { + uint x = void; + if (val < radix) + { + x = cast(uint)val; + val = 0; + } + else + { + x = cast(uint)(val % radix); + val /= radix; + } + buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + baseChar); + } while (val); + return buf[i .. $]; + } + } + + do + { + uint x = void; + if (value < radix) + { + x = cast(uint)value; + value = 0; + } + else + { + x = cast(uint)(value % radix); + value /= radix; + } + buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + baseChar); + } while (value); + return buf[i .. $]; +} diff --git a/external/arsd-webassembly/core/lifetime.d b/external/arsd-webassembly/core/lifetime.d new file mode 100644 index 0000000..41aaafa --- /dev/null +++ b/external/arsd-webassembly/core/lifetime.d @@ -0,0 +1,73 @@ +module core.lifetime; + +void copyEmplace(S, T)(ref S source, ref T target) @system + if (is(immutable S == immutable T)) +{ + import core.internal.traits : BaseElemOf, hasElaborateCopyConstructor, Unconst, Unqual; + + // cannot have the following as simple template constraint due to nested-struct special case... + static if (!__traits(compiles, (ref S src) { T tgt = src; })) + { + alias B = BaseElemOf!T; + enum isNestedStruct = is(B == struct) && __traits(isNested, B); + static assert(isNestedStruct, "cannot copy-construct " ~ T.stringof ~ " from " ~ S.stringof); + } + + void blit() + { + import core.stdc.string : memcpy; + memcpy(cast(Unqual!(T)*) &target, cast(Unqual!(T)*) &source, T.sizeof); + } + + static if (is(T == struct)) + { + static if (__traits(hasPostblit, T)) + { + blit(); + (cast() target).__xpostblit(); + } + else static if (__traits(hasCopyConstructor, T)) + { + // https://issues.dlang.org/show_bug.cgi?id=22766 + import core.internal.lifetime : emplaceInitializer; + emplaceInitializer(*(cast(Unqual!T*)&target)); + static if (__traits(isNested, T)) + { + // copy context pointer + *(cast(void**) &target.tupleof[$-1]) = cast(void*) source.tupleof[$-1]; + } + target.__ctor(source); // invoke copy ctor + } + else + { + blit(); // no opAssign + } + } + else static if (is(T == E[n], E, size_t n)) + { + static if (hasElaborateCopyConstructor!E) + { + size_t i; + try + { + for (i = 0; i < n; i++) + copyEmplace(source[i], target[i]); + } + catch (Exception e) + { + // destroy, in reverse order, what we've constructed so far + while (i--) + destroy(*cast(Unconst!(E)*) &target[i]); + throw e; + } + } + else // trivial copy + { + blit(); // all elements at once + } + } + else + { + *cast(Unconst!(T)*) &target = *cast(Unconst!(T)*) &source; + } +} diff --git a/external/arsd-webassembly/core/stdc/string.d b/external/arsd-webassembly/core/stdc/string.d new file mode 100644 index 0000000..2b0ce22 --- /dev/null +++ b/external/arsd-webassembly/core/stdc/string.d @@ -0,0 +1,61 @@ +module core.stdc.string; + +pragma(LDC_intrinsic, "llvm.memcpy.p0.p0.i#") +void llvm_memcpy(T)(void* dst, const(void)* src, T length, bool volatile_ = false) pure @nogc nothrow @trusted +if(__traits(isIntegral, T)); + +extern(C) void* +memcpy(scope return void* dst, scope const(void*) src, ulong length) pure @nogc nothrow @trusted +{ + llvm_memcpy!(long)(dst, src, cast(long)length); + return dst; +} + +pragma(LDC_intrinsic, "llvm.memset.p0.i#") +void llvm_memset(T)(void* dst, ubyte value, T length, bool volatile_ = false) pure @nogc nothrow @trusted +if(__traits(isIntegral, T)); + +extern(C) void* +memset(scope return void* s, int c, ulong n) pure nothrow @nogc +{ + ubyte value = cast(ubyte)(c & 0xFF); + llvm_memset!(long)(s, value, cast(long)n); + return s; +} + +extern(C) int memcmp(const(void)* s1, const(void)* s2, size_t n) pure @nogc nothrow @trusted +{ + auto b = cast(ubyte*) s1; + auto b2 = cast(ubyte*) s2; + foreach(i; 0 .. n) { + if(auto diff = *b - *b2) + return diff; + b++; + b2++; + } + return 0; +} + +extern(C) ulong strlen(scope const(char)* s) pure nothrow @nogc +{ + const(char)* a = s; + size_t* w; + + size_t Ones() => (cast(size_t)-1/ubyte.max); + size_t Highs() => (Ones() * (ubyte.max/2+1)); + size_t HasZero(size_t x) => ((x)-Ones() & ~(x) & Highs()); + + for(; cast(size_t)s % size_t.sizeof; s += 1) + { + if(!*s) + { + return s-a; + } + } + + for(w = cast(size_t*)s; !HasZero(*w); w += 1) {} + + for(s = cast(char*)w; *s; s += 1) {} + + return s-a; +} diff --git a/external/arsd-webassembly/math/package.d b/external/arsd-webassembly/math/package.d new file mode 100644 index 0000000..76f5581 --- /dev/null +++ b/external/arsd-webassembly/math/package.d @@ -0,0 +1,10 @@ +module core.math; + +pragma(LDC_intrinsic, "llvm.sqrt.f32") +float llvm_sqrt(float x) pure nothrow @nogc @safe; + +pragma(LDC_intrinsic, "llvm.sqrt.f64") +double llvm_sqrt(double x) pure nothrow @nogc @safe; + +float sqrt(float x ) => x < 0 ? float.nan : llvm_sqrt(x); +double sqrt(double x) => x < 0 ? double.nan : llvm_sqrt(x); diff --git a/external/arsd-webassembly/object.d b/external/arsd-webassembly/object.d index 51e1739..64c952a 100644 --- a/external/arsd-webassembly/object.d +++ b/external/arsd-webassembly/object.d @@ -1,28 +1,68 @@ // Minimal druntime for webassembly. Assumes your program has a main function. module object; +public import core.internal.cast_ : _d_cast; + static import arsd.webassembly; +import std.meta; + +// import core.arsd.memory_allocation; + +import core.stdc.string; +import dlib.externdecl; + version(CarelessAlocation) { version = inline_concat; } -import core.arsd.memory_allocation; - alias noreturn = typeof(*null); -alias string = immutable(char)[]; + +alias hash_t = size_t; // For backwards compatibility only. +alias equals_t = bool; // For backwards compatibility only. + +alias string = immutable(char)[]; alias wstring = immutable(wchar)[]; alias dstring = immutable(dchar)[]; -alias size_t = uint; -alias ptrdiff_t = int; +alias size_t = typeof(int.sizeof); +alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0); + +alias sizediff_t = ptrdiff_t; + +enum immutable(void)* rtinfoNoPointers = null; +enum immutable(void)* rtinfoHasPointers = cast(void*)1; + +template RTInfoImpl(size_t[] pointerBitmap) +{ + immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[]; +} + +template RTInfo(T) +{ + enum pointerBitmap = __traits(getPointerBitmap, T); + static if (pointerBitmap[1 .. $] == size_t[pointerBitmap.length - 1].init) + enum RTInfo = rtinfoNoPointers; + else + enum RTInfo = RTInfoImpl!(pointerBitmap).ptr; +} // then the entry point just for convenience so main works. extern(C) int _Dmain(string[] args); -export extern(C) void _start() { _Dmain(null); } -extern(C) bool _xopEquals(in void*, in void*) { return false; } // assert(0); +T[] +AllocTypeArray(T)(size_t count) @trusted nothrow @nogc +{ + T* ptr = cast(T*)malloc(T.sizeof*count); + return ptr[0 .. count]; +} + +void* +AllocPtr(size_t size) @trusted nothrow @nogc +{ + return malloc(size); +} // basic array support { @@ -47,7 +87,7 @@ extern(C) void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t s } void reserve(T)(ref T[] arr, size_t length) @trusted { - arr = (cast(T*) (malloc(length * T.sizeof).ptr))[0 .. 0]; + arr = (cast(T*) (malloc(length * T.sizeof)))[0 .. 0]; } @@ -77,44 +117,6 @@ extern(C) void _d_arraybounds_index(string file, uint line, size_t index, size_t arsd.webassembly.abort(); } - -extern(C) void* memset(void* s, int c, size_t n) @nogc nothrow pure -{ - auto d = cast(ubyte*) s; - while(n) { - *d = cast(ubyte) c; - d++; - n--; - } - return s; -} - -pragma(LDC_intrinsic, "llvm.memcpy.p0i8.p0i8.i#") - void llvm_memcpy(T)(void* dst, const(void)* src, T len, bool volatile_ = false); - -extern(C) void *memcpy(void* dest, const(void)* src, size_t n) pure @nogc nothrow -{ - ubyte *d = cast(ubyte*) dest; - const (ubyte) *s = cast(const(ubyte)*)src; - for (; n; n--) *d++ = *s++; - return dest; -} - -extern(C) int memcmp(const(void)* s1, const(void*) s2, size_t n) pure @nogc nothrow @trusted -{ - auto b = cast(ubyte*) s1; - auto b2 = cast(ubyte*) s2; - foreach(i; 0 .. n) { - if(auto diff = *b - *b2) - return diff; - b++; - b2++; - } - return 0; -} - -public import core.arsd.utf_decoding; - // } extern(C) void _d_assert(string file, uint line) @trusted @nogc pure @@ -159,8 +161,8 @@ bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs) { extern(C) Object _d_allocclass(TypeInfo_Class ti) { - auto ptr = malloc(ti.m_init.length); - ptr[] = ti.m_init[]; + auto ptr = (cast(byte*)malloc(ti.m_init.length))[0 .. ti.m_init.length]; + ptr[0 .. $] = ti.m_init[0 .. $]; return cast(Object) ptr.ptr; } @@ -174,6 +176,32 @@ extern(C) void* _d_dynamic_cast(Object o, TypeInfo_Class c) { return res; } +extern(C) int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @nogc nothrow pure @safe +{ + import core.internal.cast_ : areClassInfosEqual; + + if (areClassInfosEqual(oc, c)) + return true; + + do + { + if (oc.base && areClassInfosEqual(oc.base, c)) + return true; + + // Bugzilla 2013: Use depth-first search to calculate offset + // from the derived (oc) to the base (c). + foreach (iface; oc.interfaces) + { + if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof(iface.classinfo, c)) + return true; + } + + oc = oc.base; + } while (oc); + + return false; +} + /************************************* * Attempts to cast Object o to class c. * Returns o if successful, null if not. @@ -238,26 +266,27 @@ int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted pure @nogc nothr static if (is(U == char)) { - int dstrcmp(scope const char[] s1, scope const char[] s2 ) @trusted pure @nogc nothrow - { - immutable len = s1.length <= s2.length ? s1.length : s2.length; - if (__ctfe) + int dstrcmp(scope const char[] s1, scope const char[] s2 ) @trusted pure @nogc nothrow { - foreach (const u; 0 .. len) + immutable len = s1.length <= s2.length ? s1.length : s2.length; + if (__ctfe) { - if (s1[u] != s2[u]) - return s1[u] > s2[u] ? 1 : -1; + foreach (const u; 0 .. len) + { + if (s1[u] != s2[u]) + return s1[u] > s2[u] ? 1 : -1; + } } + else + { + const ret = memcmp( s1.ptr, s2.ptr, len ); + if ( ret ) + return ret; + } + return (s1.length > s2.length) - (s1.length < s2.length); } - else - { - const ret = memcmp( s1.ptr, s2.ptr, len ); - if ( ret ) - return ret; - } - return (s1.length > s2.length) - (s1.length < s2.length); - } - return dstrcmp(cast(char[]) lhs, cast(char[]) rhs); + + return dstrcmp(cast(char[]) lhs, cast(char[]) rhs); } else static if (!is(U == T)) { @@ -305,13 +334,20 @@ int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted pure @nogc nothr } } +template Unqual(T : const U, U) +{ + static if (is(U == shared V, V)) + alias Unqual = V; + else + alias Unqual = U; +} + // This function is called by the compiler when dealing with array // comparisons in the semantic analysis phase of CmpExp. The ordering // comparison is lowered to a call to this template. int __cmp(T1, T2)(T1[] s1, T2[] s2) if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) { - import core.internal.traits : Unqual; alias U1 = Unqual!T1; alias U2 = Unqual!T2; @@ -461,14 +497,15 @@ private int __switchSearch(T)(/*in*/ const scope T[][] cases, /*in*/ const scope // for closures -extern(C) void* _d_allocmemory(size_t sz) { - return malloc(sz).ptr; +extern(C) void* _d_allocmemory(size_t sz) +{ + return malloc(sz); } ///For POD structures extern (C) void* _d_allocmemoryT(TypeInfo ti) { - return malloc(ti.size).ptr; + return malloc(ti.tsize); } @@ -522,66 +559,204 @@ bool opEquals(const Object lhs, const Object rhs) return opEquals(cast()lhs, cast()rhs); } -class TypeInfo +class TypeInfo { - override string toString() const @safe nothrow + override string toString() const @safe nothrow { return typeid(this).name; } - const(TypeInfo) next()nothrow pure inout @nogc { return null; } - size_t size() nothrow pure const @safe @nogc { return 0; } - - bool equals(in void* p1, in void* p2) const { return p1 == p2; } - - override size_t toHash() @trusted const nothrow + override size_t toHash() @trusted const nothrow { return hashOf(this.toString()); } + override int opCmp(Object rhs) + { + if (this is rhs) + return 0; + auto ti = cast(TypeInfo) rhs; + if (ti is null) + return 1; + return __cmp(this.toString(), ti.toString()); + } - size_t getHash(scope const void* p) @trusted nothrow const - { - return hashOf(p); - } + @system unittest + { + assert(typeid(void) <= typeid(void)); + assert(typeid(void).opCmp(null)); + assert(!typeid(void).opCmp(typeid(void))); + } - /** - * Return default initializer. If the type should be initialized to all - * zeros, an array with a null ptr and a length equal to the type size will - * be returned. For static arrays, this returns the default initializer for - * a single element of the array, use `tsize` to get the correct size. - */ - const(void)[] initializer() const @trusted nothrow pure - { - return (cast(const(void)*) null)[0 .. typeof(null).sizeof]; - } + override bool opEquals(Object o) + { + return opEquals(cast(TypeInfo) o); + } - @property uint flags() nothrow pure const @safe @nogc { return 0; } - /// Run the destructor on the object and all its sub-objects + bool opEquals(const TypeInfo ti) @safe nothrow const + { + /* TypeInfo instances are singletons, but duplicates can exist + * across DLL's. Therefore, comparing for a name match is + * sufficient. + */ + if (this is ti) + return true; + return ti && this.toString() == ti.toString(); + } + + @system unittest + { + auto anotherObj = new Object(); + + assert(typeid(void).opEquals(typeid(void))); + assert(typeid(void) != anotherObj); // calling .opEquals here directly is a type mismatch + } + + /** + * Computes a hash of the instance of a type. + * Params: + * p = pointer to start of instance of the type + * Returns: + * the hash + * Bugs: + * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface. + */ + size_t getHash(scope const void* p) @trusted nothrow const + { + // by default, do not assume anything about the type + return 0; + } + + /// Compares two instances for equality. + bool equals(in void* p1, in void* p2) const { return p1 == p2; } + + /// Compares two instances for <, ==, or >. + int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); } + + /// Returns size of the type. + @property size_t tsize() nothrow pure const @safe @nogc { return 0; } + + /// Swaps two instances of the type. + void swap(void* p1, void* p2) const + { + size_t remaining = tsize; + // If the type might contain pointers perform the swap in pointer-sized + // chunks in case a garbage collection pass interrupts this function. + if ((cast(size_t) p1 | cast(size_t) p2) % (void*).alignof == 0) + { + while (remaining >= (void*).sizeof) + { + void* tmp = *cast(void**) p1; + *cast(void**) p1 = *cast(void**) p2; + *cast(void**) p2 = tmp; + p1 += (void*).sizeof; + p2 += (void*).sizeof; + remaining -= (void*).sizeof; + } + } + for (size_t i = 0; i < remaining; i++) + { + byte t = (cast(byte *)p1)[i]; + (cast(byte*)p1)[i] = (cast(byte*)p2)[i]; + (cast(byte*)p2)[i] = t; + } + } + + @system unittest + { + class _TypeInfo_Dummy : TypeInfo + { + override const(void)[] initializer() const { return []; } + @property override size_t tsize() nothrow pure const @safe @nogc { return tsize_val; } + + size_t tsize_val; + } + auto dummy = new _TypeInfo_Dummy(); + cast(void)dummy.initializer(); // For coverage completeness + + int a = 2, b = -2; + dummy.swap(&a, &b); + // does nothing because tsize is 0 + assert(a == 2); + assert(b == -2); + + dummy.tsize_val = int.sizeof; + dummy.swap(&a, &b); + assert(a == -2); + assert(b == 2); + + void* ptr_a = null, ptr_b = cast(void*)1; + dummy.tsize_val = (void*).sizeof; + dummy.swap(&ptr_a, &ptr_b); + assert(ptr_a is cast(void*)1); + assert(ptr_b is null); + } + + /** Get TypeInfo for 'next' type, as defined by what kind of type this is, + null if none. */ + @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; } + + /** + * Return default initializer. If the type should be initialized to all + * zeros, an array with a null ptr and a length equal to the type size will + * be returned. For static arrays, this returns the default initializer for + * a single element of the array, use `tsize` to get the correct size. + */ +version (LDC) +{ + // LDC uses TypeInfo's vtable for the typeof(null) type: + // %"typeid(typeof(null))" = type { %object.TypeInfo.__vtbl*, i8* } + // Therefore this class cannot be abstract, and all methods need implementations. + // Tested by test14754() in runnable/inline.d, and a unittest below. + const(void)[] initializer() nothrow pure const @trusted @nogc + { + return (cast(const(void)*) null)[0 .. typeof(null).sizeof]; + } +} +else +{ + abstract const(void)[] initializer() nothrow pure const @safe @nogc; +} + + /** Get flags for type: 1 means GC should scan for pointers, + 2 means arg of this type is passed in SIMD register(s) if available */ + @property uint flags() nothrow pure const @safe @nogc { return 0; } + + /// Get type information on the contents of the type; null if not available + const(OffsetTypeInfo)[] offTi() const { return null; } + /// Run the destructor on the object and all its sub-objects void destroy(void* p) const {} /// Run the postblit on the object and all its sub-objects void postblit(void* p) const {} - @property size_t talign() nothrow pure const { return size; } -} + /// Return alignment of type + @property size_t talign() nothrow pure const @safe @nogc { return tsize; } + + /** Return internal info on arguments fitting into 8byte. + * See X86-64 ABI 3.2.3 + */ + version (WithArgTypes) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow + { + arg1 = this; + return 0; + } + + /** Return info used by the garbage collector to do precise collection. + */ + @property immutable(void)* rtInfo() nothrow pure const @trusted @nogc { return rtinfoHasPointers; } // better safe than sorry +} class TypeInfo_Class : TypeInfo { - ubyte[] m_init; /// class static initializer (length gives class size) - string name; /// name of class - void*[] vtbl; // virtual function pointer table - Interface[] interfaces; - TypeInfo_Class base; - void* destructor; - void function(Object) classInvariant; - uint flags; - void* deallocator; - void*[] offTi; - void function(Object) defaultConstructor; - immutable(void)* rtInfo; + override string toString() const pure { return name; } - override @property size_t size() nothrow pure const - { return Object.sizeof; } + override bool opEquals(const TypeInfo o) const + { + if (this is o) + return true; + auto c = cast(const TypeInfo_Class)o; + return c && this.name == c.name; + } override size_t getHash(scope const void* p) @trusted const { @@ -589,7 +764,7 @@ class TypeInfo_Class : TypeInfo return o ? o.toHash() : 0; } - override bool equals(in void* p1, in void* p2) const + override bool equals(in void* p1, in void* p2) const { Object o1 = *cast(Object*)p1; Object o2 = *cast(Object*)p2; @@ -597,10 +772,163 @@ class TypeInfo_Class : TypeInfo return (o1 is o2) || (o1 && o1.opEquals(o2)); } - override const(void)[] initializer() nothrow pure const @safe + override int compare(in void* p1, in void* p2) const + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + int c = 0; + + // Regard null references as always being "less than" + if (o1 !is o2) + { + if (o1) + { + if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + override @property size_t tsize() nothrow pure const + { + return Object.sizeof; + } + + override const(void)[] initializer() nothrow pure const @safe { return m_init; } + + override @property uint flags() nothrow pure const { return 1; } + + override @property const(OffsetTypeInfo)[] offTi() nothrow pure const + { + return m_offTi; + } + + final @property auto info() @safe @nogc nothrow pure const return { return this; } + final @property auto typeinfo() @safe @nogc nothrow pure const return { return this; } + + byte[] m_init; /** class static initializer + * (init.length gives size in bytes of class) + */ + string name; /// class name + void*[] vtbl; /// virtual function pointer table + Interface[] interfaces; /// interfaces this class implements + TypeInfo_Class base; /// base class + void* destructor; + void function(Object) classInvariant; + enum ClassFlags : ushort + { + isCOMclass = 0x1, + noPointers = 0x2, + hasOffTi = 0x4, + hasCtor = 0x8, + hasGetMembers = 0x10, + hasTypeInfo = 0x20, + isAbstract = 0x40, + isCPPclass = 0x80, + hasDtor = 0x100, + hasNameSig = 0x200, + } + ClassFlags m_flags; + ushort depth; /// inheritance distance from Object + void* deallocator; + OffsetTypeInfo[] m_offTi; + void function(Object) defaultConstructor; // default Constructor + + immutable(void)* m_RTInfo; // data for precise GC + override @property immutable(void)* rtInfo() const { return m_RTInfo; } + + uint[4] nameSig; /// unique signature for `name` + + /** + * Search all modules for TypeInfo_Class corresponding to classname. + * Returns: null if not found + */ + static const(TypeInfo_Class) find(const scope char[] classname) + { + foreach (m; ModuleInfo) + { + if (m) + { + //writefln("module %s, %d", m.name, m.localClasses.length); + foreach (c; m.localClasses) + { + if (c is null) + continue; + //writefln("\tclass %s", c.name); + if (c.name == classname) + return c; + } + } + } + return null; + } + + /** + * Create instance of Object represented by 'this'. + */ + Object create() const + { + if (m_flags & 8 && !defaultConstructor) + return null; + if (m_flags & 64) // abstract + return null; + Object o = _d_newclass(this); + if (m_flags & 8 && defaultConstructor) + { + defaultConstructor(o); + } + return o; + } + + /** + * Returns true if the class described by `child` derives from or is + * the class described by this `TypeInfo_Class`. Always returns false + * if the argument is null. + * + * Params: + * child = TypeInfo for some class + * Returns: + * true if the class described by `child` derives from or is the + * class described by this `TypeInfo_Class`. + */ + final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted + { + if (m_init.length) + { + // If this TypeInfo_Class represents an actual class we only need + // to check the child and its direct ancestors. + for (auto ti = cast() child; ti !is null; ti = ti.base) + if (ti is this) + return true; + return false; + } + else + { + // If this TypeInfo_Class is the .info field of a TypeInfo_Interface + // we also need to recursively check the child's interfaces. + return child !is null && _d_isbaseof(cast() child, this); + } + } +} + +alias ClassInfo = TypeInfo_Class; + + +extern (C) Object _d_newclass(const ClassInfo ci) nothrow +{ + const initializer = ci.initializer; + + auto p = AllocPtr(initializer.length); + memcpy(p, initializer.ptr, initializer.length); + return cast(Object) p; } void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct)) @@ -683,33 +1011,84 @@ void destroy(bool initialize = true, T)(ref T obj) class TypeInfo_Pointer : TypeInfo { - TypeInfo m_next; + override string toString() const + { + return MakeString(m_next.toString(), "*"); + } + + override bool opEquals(Object o) + { + if (this is o) + return true; + auto c = cast(const TypeInfo_Pointer)o; + return c && this.m_next == c.m_next; + } - override bool equals(in void* p1, in void* p2) const { return *cast(void**)p1 == *cast(void**)p2; } override size_t getHash(scope const void* p) @trusted const { size_t addr = cast(size_t) *cast(const void**)p; return addr ^ (addr >> 4); } - override @property size_t size() nothrow pure const { return (void*).sizeof; } - override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void*).sizeof]; } + override bool equals(in void* p1, in void* p2) const + { + return *cast(void**)p1 == *cast(void**)p2; + } - override const (TypeInfo) next() const { return m_next; } + override int compare(in void* p1, in void* p2) const + { + const v1 = *cast(void**) p1, v2 = *cast(void**) p2; + return (v1 > v2) - (v1 < v2); + } + + override @property size_t tsize() nothrow pure const + { + return (void*).sizeof; + } + + override const(void)[] initializer() const @trusted + { + return (cast(void *)null)[0 .. (void*).sizeof]; + } + + override void swap(void* p1, void* p2) const + { + void* tmp = *cast(void**)p1; + *cast(void**)p1 = *cast(void**)p2; + *cast(void**)p2 = tmp; + } + + override @property inout(TypeInfo) next() nothrow pure inout { return m_next; } + override @property uint flags() nothrow pure const { return 1; } + + TypeInfo m_next; } -class TypeInfo_Array : TypeInfo { - TypeInfo value; - override size_t size() const { return (void[]).sizeof; } - override const(TypeInfo) next() const { return value; } +class TypeInfo_Array : TypeInfo +{ + override string toString() const { return MakeString(value.toString(), "[]"); } - override bool equals(in void* p1, in void* p2) const + override bool opEquals(Object o) + { + if (this is o) + return true; + auto c = cast(const TypeInfo_Array)o; + return c && this.value == c.value; + } + + override size_t getHash(scope const void* p) @trusted const + { + void[] a = *cast(void[]*)p; + return getArrayHash(value, a.ptr, a.length); + } + + override bool equals(in void* p1, in void* p2) const { void[] a1 = *cast(void[]*)p1; void[] a2 = *cast(void[]*)p2; if (a1.length != a2.length) return false; - size_t sz = value.size; + size_t sz = value.tsize; for (size_t i = 0; i < a1.length; i++) { if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) @@ -717,46 +1096,222 @@ class TypeInfo_Array : TypeInfo { } return true; } - override @property size_t talign() nothrow pure const + + override int compare(in void* p1, in void* p2) const + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + size_t sz = value.tsize; + size_t len = a1.length; + + if (a2.length < len) + len = a2.length; + for (size_t u = 0; u < len; u++) + { + immutable int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); + if (result) + return result; + } + return (a1.length > a2.length) - (a1.length < a2.length); + } + + override @property size_t tsize() nothrow pure const + { + return (void[]).sizeof; + } + + override const(void)[] initializer() const @trusted + { + return (cast(void *)null)[0 .. (void[]).sizeof]; + } + + override void swap(void* p1, void* p2) const + { + void[] tmp = *cast(void[]*)p1; + *cast(void[]*)p1 = *cast(void[]*)p2; + *cast(void[]*)p2 = tmp; + } + + TypeInfo value; + + override @property inout(TypeInfo) next() nothrow pure inout + { + return value; + } + + override @property uint flags() nothrow pure const { return 1; } + + override @property size_t talign() nothrow pure const { return (void[]).alignof; } - override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. (void[]).sizeof]; } + + version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + arg1 = typeid(size_t); + arg2 = typeid(void*); + return 0; + } + + override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(void[]); } } -class TypeInfo_StaticArray : TypeInfo { - TypeInfo value; - size_t len; - override size_t size() const { return value.size * len; } - override const(TypeInfo) next() const { return value; } +string +MakeString(Args...)(Args args) nothrow @trusted +{ + uint length; - override bool equals(in void* p1, in void* p2) const { - size_t sz = value.size; + static foreach(i; 0 .. Args.length) + { + static assert(is(Args[i] == char[]) || is(Args[i] == const(char)[]) || is(Args[i] == string), "Only string parameters are supported for MakeString"); - for (size_t u = 0; u < len; u++) - { - if (!value.equals(p1 + u * sz, p2 + u * sz)) - { - return false; - } - } - return true; + length += args[i].length; } - override @property size_t talign() nothrow pure const + + char[] str_array = AllocTypeArray!(char)(length); + + uint pos; + static foreach(arg; args) + { + str_array[pos .. pos+arg.length] = arg[0 .. $]; + pos += arg.length; + } + + return cast(string)str_array; +} + +class TypeInfo_StaticArray : TypeInfo +{ + override string toString() const + { + import core.internal.string : unsignedToTempString; + + char[20] tmpBuff = void; + + const length_string = unsignedToTempString(len, tmpBuff); + const value_string = value.toString(); + + // return (() @trusted => cast(string) (value.toString() ~ "[" ~ lenString ~ "]"))(); + + return MakeString(value_string, "[", length_string, "]"); + } + + override bool opEquals(Object o) + { + if (this is o) + return true; + auto c = cast(const TypeInfo_StaticArray)o; + return c && this.len == c.len && + this.value == c.value; + } + + override size_t getHash(scope const void* p) @trusted const + { + return getArrayHash(value, p, len); + } + + override bool equals(in void* p1, in void* p2) const + { + size_t sz = value.tsize; + + for (size_t u = 0; u < len; u++) + { + if (!value.equals(p1 + u * sz, p2 + u * sz)) + return false; + } + return true; + } + + override int compare(in void* p1, in void* p2) const + { + size_t sz = value.tsize; + + for (size_t u = 0; u < len; u++) + { + immutable int result = value.compare(p1 + u * sz, p2 + u * sz); + if (result) + return result; + } + return 0; + } + + override @property size_t tsize() nothrow pure const + { + return len * value.tsize; + } + + override void swap(void* p1, void* p2) const + { + import core.stdc.string : memcpy; + + size_t remaining = value.tsize * len; + void[size_t.sizeof * 4] buffer = void; + while (remaining > buffer.length) + { + memcpy(buffer.ptr, p1, buffer.length); + memcpy(p1, p2, buffer.length); + memcpy(p2, buffer.ptr, buffer.length); + p1 += buffer.length; + p2 += buffer.length; + remaining -= buffer.length; + } + memcpy(buffer.ptr, p1, remaining); + memcpy(p1, p2, remaining); + memcpy(p2, buffer.ptr, remaining); + } + + override const(void)[] initializer() nothrow pure const + { + return value.initializer(); + } + + override @property inout(TypeInfo) next() nothrow pure inout { return value; } + override @property uint flags() nothrow pure const { return value.flags; } + + override void destroy(void* p) const + { + immutable sz = value.tsize; + p += sz * len; + foreach (i; 0 .. len) + { + p -= sz; + value.destroy(p); + } + } + + override void postblit(void* p) const + { + immutable sz = value.tsize; + foreach (i; 0 .. len) + { + value.postblit(p); + p += sz; + } + } + + TypeInfo value; + size_t len; + + override @property size_t talign() nothrow pure const { return value.talign; } + version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + arg1 = typeid(void*); + return 0; + } + + // just return the rtInfo of the element, we have no generic type T to run RTInfo!T on + override @property immutable(void)* rtInfo() nothrow pure const @safe { return value.rtInfo(); } } +/* import core.arsd.aa; alias AARange = core.arsd.aa.Range; extern (C) { - // from druntime/src/rt/aaA.d - /* The real type is (non-importable) `rt.aaA.Impl*`; - * the compiler uses `void*` for its prototypes. - */ private alias AA = void*; // size_t _aaLen(in AA aa) pure nothrow @nogc; @@ -783,12 +1338,6 @@ extern (C) int _aaEqual(scope const TypeInfo tiRaw, scope const AA aa1, scope const AA aa2); size_t _aaGetHash(scope const AA* aa, scope const TypeInfo tiRaw) nothrow; - /* - _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code. - This is a typesystem hole, however this is existing hole. - Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus - copiler allowed to create AA literal with keys, which have impure unsafe toHash methods. - */ void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values); } @@ -823,7 +1372,6 @@ auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe return Result(_aaToRange(aa)); } -/** ditto */ auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byKey(); @@ -852,7 +1400,6 @@ auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe return Result(_aaToRange(aa)); } -/** ditto */ auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc { return (*aa).byValue(); @@ -874,20 +1421,11 @@ Key[] keys(T : Value[Key], Value, Key)(T aa) @property return res; } -/** ditto */ Key[] keys(T : Value[Key], Value, Key)(T *aa) @property { return (*aa).keys; } -/*********************************** - * Returns a newly allocated dynamic array containing a copy of the values from - * the associative array. - * Params: - * aa = The associative array. - * Returns: - * A dynamic array containing a copy of the values. - */ Value[] values(T : Value[Key], Value, Key)(T aa) @property { // ensure we are dealing with a genuine AA. @@ -904,7 +1442,6 @@ Value[] values(T : Value[Key], Value, Key)(T aa) @property return res; } -/** ditto */ Value[] values(T : Value[Key], Value, Key)(T *aa) @property { return (*aa).values; @@ -915,23 +1452,14 @@ inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue) return p ? *p : defaultValue; } -/** ditto */ inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue) { return (*aa).get(key, defaultValue); } + // Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test. private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); })); -/*********************************** - * Looks up key; if it exists applies the update callable else evaluates the - * create callable and adds it to the associative array - * Params: - * aa = The associative array. - * key = The key. - * create = The callable to apply on create. - * update = The callable to apply on update. - */ void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update) if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void))) { @@ -983,23 +1511,16 @@ ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init) } } - - -/*********************************** - * Removes all remaining keys and values from an associative array. - * Params: - * aa = The associative array. - */ void clear(Value, Key)(Value[Key] aa) { _aaClear(*cast(AA *) &aa); } -/** ditto */ void clear(Value, Key)(Value[Key]* aa) { _aaClear(*cast(AA *) aa); } + void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure { return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values); @@ -1025,17 +1546,17 @@ class TypeInfo_AssociativeArray : TypeInfo override bool equals(in void* p1, in void* p2) @trusted const { - return !!_aaEqual(this, *cast(const AA*) p1, *cast(const AA*) p2); + return xopEquals(p1, p2); } - override size_t getHash(scope const void* p) nothrow @trusted const + override hash_t getHash(scope const void* p) nothrow @trusted const { - return _aaGetHash(cast(AA*)p, this); + return xtoHash(p); } // BUG: need to add the rest of the functions - override @property size_t size() nothrow pure const + override @property size_t tsize() nothrow pure const { return (char[int]).sizeof; } @@ -1048,9 +1569,19 @@ class TypeInfo_AssociativeArray : TypeInfo override @property inout(TypeInfo) next() nothrow pure inout { return value; } override @property uint flags() nothrow pure const { return 1; } + // TypeInfo entry is generated from the type of this template to help rt/aaA.d + private static import core.internal.newaa; + alias Entry(K, V) = core.internal.newaa.Entry!(K, V); TypeInfo value; TypeInfo key; + TypeInfo entry; + + bool function(scope const void* p1, scope const void* p2) nothrow @safe xopEquals; + hash_t function(scope const void*) nothrow @safe xtoHash; + + alias aaOpEqual(K, V) = core.internal.newaa._aaOpEqual!(K, V); + alias aaGetHash(K, V) = core.internal.newaa._aaGetHash!(K, V); override @property size_t talign() nothrow pure const { @@ -1064,17 +1595,129 @@ class TypeInfo_AssociativeArray : TypeInfo } } +*/ +class TypeInfo_Enum : TypeInfo +{ + override string toString() const pure { return name; } -class TypeInfo_Enum : TypeInfo { - TypeInfo base; - string name; - void[] m_init; + override bool opEquals(Object o) + { + if (this is o) + return true; + auto c = cast(const TypeInfo_Enum)o; + return c && this.name == c.name && + this.base == c.base; + } + + @system unittest + { + enum E { A, B, C } + enum EE { A, B, C } + + assert(typeid(E).opEquals(typeid(E))); + assert(!typeid(E).opEquals(typeid(EE))); + } + + override size_t getHash(scope const void* p) const { return base.getHash(p); } + + @system unittest + { + enum E { A, B, C } + E e1 = E.A; + E e2 = E.B; + + assert(typeid(E).getHash(&e1) == hashOf(E.A)); + assert(typeid(E).getHash(&e2) == hashOf(E.B)); + + enum ES : string { A = "foo", B = "bar" } + ES es1 = ES.A; + ES es2 = ES.B; + + assert(typeid(ES).getHash(&es1) == hashOf("foo")); + assert(typeid(ES).getHash(&es2) == hashOf("bar")); + } - override size_t size() const { return base.size; } - override const(TypeInfo) next() const { return base.next; } override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } - override @property size_t talign() const { return base.talign; } + + @system unittest + { + enum E { A, B, C } + + E e1 = E.A; + E e2 = E.B; + + assert(typeid(E).equals(&e1, &e1)); + assert(!typeid(E).equals(&e1, &e2)); + } + + override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); } + + @system unittest + { + enum E { A, B, C } + + E e1 = E.A; + E e2 = E.B; + + assert(typeid(E).compare(&e1, &e1) == 0); + assert(typeid(E).compare(&e1, &e2) < 0); + assert(typeid(E).compare(&e2, &e1) > 0); + } + + override @property size_t tsize() nothrow pure const { return base.tsize; } + + @safe unittest + { + enum E { A, B, C } + enum ES : string { A = "a", B = "b", C = "c"} + + assert(typeid(E).tsize == E.sizeof); + assert(typeid(ES).tsize == ES.sizeof); + assert(typeid(E).tsize != ES.sizeof); + } + + override void swap(void* p1, void* p2) const { return base.swap(p1, p2); } + + @system unittest + { + enum E { A, B, C } + + E e1 = E.A; + E e2 = E.B; + + typeid(E).swap(&e1, &e2); + assert(e1 == E.B); + assert(e2 == E.A); + } + + override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } + + @system unittest + { + enum E { A, B, C } + + assert(typeid(E).next is null); + } + + override @property uint flags() nothrow pure const { return base.flags; } + + @safe unittest + { + enum E { A, B, C } + + assert(typeid(E).flags == 0); + } + + override const(OffsetTypeInfo)[] offTi() const { return base.offTi; } + + @system unittest + { + enum E { A, B, C } + + assert(typeid(E).offTi is null); + } + override void destroy(void* p) const { return base.destroy(p); } override void postblit(void* p) const { return base.postblit(p); } @@ -1082,11 +1725,247 @@ class TypeInfo_Enum : TypeInfo { { return m_init.length ? m_init : base.initializer(); } + + override @property size_t talign() nothrow pure const { return base.talign; } + + version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + return base.argTypes(arg1, arg2); + } + + override @property immutable(void)* rtInfo() const { return base.rtInfo; } + + TypeInfo base; + string name; + void[] m_init; +} + +enum +{ + MIctorstart = 0x1, // we've started constructing it + MIctordone = 0x2, // finished construction + MIstandalone = 0x4, // module ctor does not depend on other module + // ctors being done first + MItlsctor = 8, + MItlsdtor = 0x10, + MIctor = 0x20, + MIdtor = 0x40, + MIxgetMembers = 0x80, + MIictor = 0x100, + MIunitTest = 0x200, + MIimportedModules = 0x400, + MIlocalClasses = 0x800, + MIname = 0x1000, +} + +struct ModuleInfo +{ + uint _flags; // MIxxxx + uint _index; // index into _moduleinfo_array[] + + version (all) + { + deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.") + void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; } + } + else + { + @disable this(); + } + +const: + private void* addrOf(int flag) return nothrow pure @nogc + in + { + assert(flag >= MItlsctor && flag <= MIname); + assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1)); + } + do + { + import core.stdc.string : strlen; + + void* p = cast(void*)&this + ModuleInfo.sizeof; + + if (flags & MItlsctor) + { + if (flag == MItlsctor) return p; + p += typeof(tlsctor).sizeof; + } + if (flags & MItlsdtor) + { + if (flag == MItlsdtor) return p; + p += typeof(tlsdtor).sizeof; + } + if (flags & MIctor) + { + if (flag == MIctor) return p; + p += typeof(ctor).sizeof; + } + if (flags & MIdtor) + { + if (flag == MIdtor) return p; + p += typeof(dtor).sizeof; + } + if (flags & MIxgetMembers) + { + if (flag == MIxgetMembers) return p; + p += typeof(xgetMembers).sizeof; + } + if (flags & MIictor) + { + if (flag == MIictor) return p; + p += typeof(ictor).sizeof; + } + if (flags & MIunitTest) + { + if (flag == MIunitTest) return p; + p += typeof(unitTest).sizeof; + } + if (flags & MIimportedModules) + { + if (flag == MIimportedModules) return p; + p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof; + } + if (flags & MIlocalClasses) + { + if (flag == MIlocalClasses) return p; + p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof; + } + if (true || flags & MIname) // always available for now + { + if (flag == MIname) return p; + p += strlen(cast(immutable char*)p); + } + assert(0); + } + + @property uint index() nothrow pure @nogc { return _index; } + + @property uint flags() nothrow pure @nogc { return _flags; } + + /************************ + * Returns: + * module constructor for thread locals, `null` if there isn't one + */ + @property void function() tlsctor() nothrow pure @nogc + { + return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null; + } + + /************************ + * Returns: + * module destructor for thread locals, `null` if there isn't one + */ + @property void function() tlsdtor() nothrow pure @nogc + { + return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null; + } + + /***************************** + * Returns: + * address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one + */ + @property void* xgetMembers() nothrow pure @nogc + { + return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null; + } + + /************************ + * Returns: + * module constructor, `null` if there isn't one + */ + @property void function() ctor() nothrow pure @nogc + { + return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null; + } + + /************************ + * Returns: + * module destructor, `null` if there isn't one + */ + @property void function() dtor() nothrow pure @nogc + { + return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null; + } + + /************************ + * Returns: + * module order independent constructor, `null` if there isn't one + */ + @property void function() ictor() nothrow pure @nogc + { + return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null; + } + + /************* + * Returns: + * address of function that runs the module's unittests, `null` if there isn't one + */ + @property void function() unitTest() nothrow pure @nogc + { + return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null; + } + + /**************** + * Returns: + * array of pointers to the ModuleInfo's of modules imported by this one + */ + @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc + { + if (flags & MIimportedModules) + { + auto p = cast(size_t*)addrOf(MIimportedModules); + return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p]; + } + return null; + } + + /**************** + * Returns: + * array of TypeInfo_Class references for classes defined in this module + */ + @property TypeInfo_Class[] localClasses() return nothrow pure @nogc + { + if (flags & MIlocalClasses) + { + auto p = cast(size_t*)addrOf(MIlocalClasses); + return (cast(TypeInfo_Class*)(p + 1))[0 .. *p]; + } + return null; + } + + /******************** + * Returns: + * name of module, `null` if no name + */ + @property string name() return nothrow pure @nogc + { + import core.stdc.string : strlen; + + auto p = cast(immutable char*) addrOf(MIname); + return p[0 .. cast(size_t)strlen(p)]; + } + + static int opApply(scope int delegate(ModuleInfo*) dg) + { + /* + import core.internal.traits : externDFunc; + alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply", + int function(scope int delegate(immutable(ModuleInfo*)))); + // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code + return moduleinfos_apply( + (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m)); + */ + + assert(false, "Not implemented for platform"); + + return 0; + } } extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) { - return malloc(length * ti.next.size); + return AllocTypeArray!(ubyte)(length * ti.next.tsize); } extern(C) void[] _d_newarrayT(const TypeInfo ti, size_t length) @@ -1100,8 +1979,8 @@ extern(C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) { auto result = _d_newarrayU(ti, length); auto tinext = ti.next; - auto size = tinext.size; - auto init = tinext.initializer(); + auto size = tinext.tsize; + auto init = tinext.initializer(); switch (init.length) { foreach (T; AliasSeq!(ubyte, ushort, uint, ulong)) @@ -1129,31 +2008,27 @@ extern(C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) extern (C) void* _d_newitemU(scope const TypeInfo _ti) { - import core.arsd.objectutils; - auto ti = cast()_ti; - immutable tiSize = structTypeInfoSize(ti); - immutable itemSize = ti.size; - immutable size = itemSize + tiSize; - auto p = malloc(size); - - return p.ptr; + auto ti = unqualify(_ti); + return malloc(ti.tsize); } /// ditto -extern (C) void* _d_newitemT(in TypeInfo _ti) +extern (C) T* _d_newitemT(T)() @trusted { - auto p = _d_newitemU(_ti); - memset(p, 0, _ti.size); - return p; + T* p = cast(T*)malloc(T.sizeof); + memset(p, 0, T.sizeof); + + emplaceInitializer(*p); + + return p; } /// Same as above, for item with non-zero initializer. -extern (C) void* _d_newitemiT(in TypeInfo _ti) +extern (C) void* _d_newitemiT(TypeInfo ti) { - auto p = _d_newitemU(_ti); - auto init = _ti.initializer(); - assert(init.length <= _ti.size); - memcpy(p, init.ptr, init.length); + auto p = _d_newitemU(ti); + const initializer = ti.initializer; + memcpy(p, initializer.ptr, initializer.length); return p; } @@ -1170,16 +2045,19 @@ private void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dimensions) if (dimensions.length == 1) { - auto r = op(ti, count); - return (*cast(void[]*)(&r))[0..count]; + auto r = op(ti, count); + return (*cast(void[]*)(&r))[0..count]; } - void[] p = malloc((void[]).sizeof * count); - foreach (i; 0..count) + size_t size = (void[]).sizeof*count; + void[] p = malloc(size)[0 .. size]; + + foreach (i; 0 .. count) { - (cast(void[]*)p.ptr)[i] = foo(ti.next, dimensions[1..$]); + (cast(void[]*)p.ptr)[i] = foo(ti.next, dimensions[1 .. $]); } - return p[0..count]; + + return p[0 .. count]; } return foo(ti, dimensions); @@ -1205,7 +2083,7 @@ extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) - +/* AllocatedBlock* getAllocatedBlock(void* ptr) { auto block = (cast(AllocatedBlock*) ptr) - 1; if(!block.checkChecksum()) @@ -1213,15 +2091,13 @@ AllocatedBlock* getAllocatedBlock(void* ptr) { return block; } -/++ - Marks the memory block as OK to append in-place if possible. -+/ void assumeSafeAppend(T)(T[] arr) { auto block = getAllocatedBlock(arr.ptr); if(block is null) assert(0); block.used = arr.length; } + */ /++ Marks the memory block associated with this array as unique, meaning @@ -1257,6 +2133,7 @@ template _d_arraysetlengthTImpl(Tarr : T[], T) { } } +/* extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) @trusted { auto elemSize = ti.next.size; auto newLength = n + px.length; @@ -1278,38 +2155,13 @@ extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref byte[] px, size_t n) (cast(void **)(&px))[1] = ns.ptr; return px; } - - -version(inline_concat) -extern(C) void[] _d_arraycatnTX(const TypeInfo ti, scope byte[][] arrs) @trusted -{ - auto elemSize = ti.next.size; - size_t length; - foreach (b; arrs) - length += b.length; - if(!length) - return null; - ubyte* ptr = cast(ubyte*)malloc(length * elemSize); - - //Copy data - { - ubyte* nPtr = ptr; - foreach(b; arrs) - { - byte* bPtr = b.ptr; - size_t copySize = b.length*elemSize; - nPtr[0..copySize] = cast(ubyte[])bPtr[0..copySize]; - nPtr+= copySize; - } - } - return cast(void[])ptr[0..length]; -} +*/ version(inline_concat) extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) { import core.arsd.objectutils; - auto sizeelem = ti.next.size; // array element size + auto sizeelem = ti.next.tsize; // array element size size_t xlen = x.length * sizeelem; size_t ylen = y.length * sizeelem; size_t len = xlen + ylen; @@ -1317,7 +2169,7 @@ extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) if (!len) return null; - byte[] p = cast(byte[])malloc(len); + byte[] p = AllocTypeArray!(byte)(len); memcpy(p.ptr, x.ptr, xlen); memcpy(p.ptr + xlen, y.ptr, ylen); // do postblit processing @@ -1369,7 +2221,7 @@ extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c) - +/* TODO: see if needed alias AliasSeq(T...) = T; static foreach(type; AliasSeq!(byte, char, dchar, double, float, int, long, short, ubyte, uint, ulong, ushort, void, wchar)) { mixin(q{ @@ -1427,16 +2279,7 @@ static foreach(type; AliasSeq!(byte, char, dchar, double, float, int, long, shor } }); } -// typeof(null) -class TypeInfo_n : TypeInfo -{ - const: pure: @nogc: nothrow: @safe: - override string toString() { return "typeof(null)"; } - override size_t getHash(scope const void*) { return 0; } - override bool equals(in void*, in void*) { return true; } - override @property size_t size() { return typeof(null).sizeof; } - override const(void)[] initializer() @trusted { return (cast(void *)null)[0 .. size_t.sizeof]; } -} +*/ struct Interface { TypeInfo_Class classinfo; @@ -1454,16 +2297,24 @@ struct OffsetTypeInfo TypeInfo ti; /// TypeInfo for this member } -class TypeInfo_Axa : TypeInfo_Aa { - -} -class TypeInfo_Aya : TypeInfo_Aa { - -} - class TypeInfo_Function : TypeInfo { - override string toString() const pure @trusted{return deco;} + override string toString() const pure @trusted + { + /* + import core.demangle : demangleType; + + alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure; + SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType; + + return cast(string) demangle(deco); + */ + + assert(false, "Not implemented for platform"); + + return null; + } + override bool opEquals(Object o) { if (this is o) @@ -1474,13 +2325,19 @@ class TypeInfo_Function : TypeInfo // BUG: need to add the rest of the functions - override @property size_t size() nothrow pure const + override @property size_t tsize() nothrow pure const { return 0; // no size for functions } - override const(void)[] initializer() const @safe{return null;} - TypeInfo _next; - override const(TypeInfo) next()nothrow pure inout @nogc { return _next; } + + override const(void)[] initializer() const @safe + { + return null; + } + + override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; } + + TypeInfo next; /** * Mangled function type string @@ -1488,52 +2345,135 @@ class TypeInfo_Function : TypeInfo string deco; } +class TypeInfo_Delegate : TypeInfo +{ + override string toString() const pure @trusted + { + /* + import core.demangle : demangleType; -class TypeInfo_Delegate : TypeInfo { - TypeInfo next; - string deco; - override @property size_t size() nothrow pure const - { - alias dg = int delegate(); - return dg.sizeof; + alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure; + SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType; + + return cast(string) demangle(deco); + */ + + assert(false, "Not implemented for platform"); + + return null; } - override bool equals(in void* p1, in void* p2) const + + @safe unittest { - auto dg1 = *cast(void delegate()*)p1; - auto dg2 = *cast(void delegate()*)p2; - return dg1 == dg2; + double sqr(double x) { return x * x; } + sqr(double.init); // for coverage completeness + + auto delegate_str = "double delegate(double) pure nothrow @nogc @safe"; + + assert(typeid(typeof(&sqr)).toString() == delegate_str); + assert(delegate_str.hashOf() == typeid(typeof(&sqr)).hashOf()); + assert(typeid(typeof(&sqr)).toHash() == typeid(typeof(&sqr)).hashOf()); + + int g; + + alias delegate_type = typeof((int a, int b) => a + b + g); + delegate_str = "int delegate(int, int) pure nothrow @nogc @safe"; + + assert(typeid(delegate_type).toString() == delegate_str); + assert(delegate_str.hashOf() == typeid(delegate_type).hashOf()); + assert(typeid(delegate_type).toHash() == typeid(delegate_type).hashOf()); } - override const(void)[] initializer() const @trusted + + override bool opEquals(Object o) { - return (cast(void *)null)[0 .. (int delegate()).sizeof]; + if (this is o) + return true; + auto c = cast(const TypeInfo_Delegate)o; + return c && this.deco == c.deco; } + + @system unittest + { + double sqr(double x) { return x * x; } + int dbl(int x) { return x + x; } + sqr(double.init); // for coverage completeness + dbl(int.init); // for coverage completeness + + Object obj = typeid(typeof(&sqr)); + assert(obj.opEquals(typeid(typeof(&sqr)))); + assert(typeid(typeof(&sqr)) == typeid(typeof(&sqr))); + assert(typeid(typeof(&dbl)) != typeid(typeof(&sqr))); + } + override size_t getHash(scope const void* p) @trusted const { return hashOf(*cast(const void delegate() *)p); } - override @property size_t talign() nothrow pure const + override bool equals(in void* p1, in void* p2) const + { + auto dg1 = *cast(void delegate()*)p1; + auto dg2 = *cast(void delegate()*)p2; + return dg1 == dg2; + } + + override int compare(in void* p1, in void* p2) const + { + auto dg1 = *cast(void delegate()*)p1; + auto dg2 = *cast(void delegate()*)p2; + + if (dg1 < dg2) + return -1; + else if (dg1 > dg2) + return 1; + else + return 0; + } + + override @property size_t tsize() nothrow pure const + { + alias dg = int delegate(); + return dg.sizeof; + } + + override const(void)[] initializer() const @trusted + { + return (cast(void *)null)[0 .. (int delegate()).sizeof]; + } + + override @property uint flags() nothrow pure const { return 1; } + + TypeInfo next; + string deco; + + override @property size_t talign() nothrow pure const { alias dg = int delegate(); return dg.alignof; } + + version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + arg1 = typeid(void*); + arg2 = typeid(void*); + return 0; + } + + override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(int delegate()); } } - -//Directly copied from LWDR source. class TypeInfo_Interface : TypeInfo { - TypeInfo_Class info; + override string toString() const pure { return info.name; } - override bool equals(in void* p1, in void* p2) const + override bool opEquals(Object o) { - Interface* pi = **cast(Interface ***)*cast(void**)p1; - Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); - pi = **cast(Interface ***)*cast(void**)p2; - Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); - - return o1 == o2 || (o1 && o1.opCmp(o2) == 0); + if (this is o) + return true; + auto c = cast(const TypeInfo_Interface)o; + return c && this.info.name == typeid(c).name; } + override size_t getHash(scope const void* p) @trusted const { if (!*cast(void**)p) @@ -1546,27 +2486,130 @@ class TypeInfo_Interface : TypeInfo return o.toHash(); } - override const(void)[] initializer() const @trusted + override bool equals(in void* p1, in void* p2) const + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + + return o1 == o2 || (o1 && o1.opCmp(o2) == 0); + } + + override int compare(in void* p1, in void* p2) const + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + int c = 0; + + // Regard null references as always being "less than" + if (o1 != o2) + { + if (o1) + { + if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + override @property size_t tsize() nothrow pure const + { + return Object.sizeof; + } + + override const(void)[] initializer() const @trusted { return (cast(void *)null)[0 .. Object.sizeof]; } - override @property size_t size() nothrow pure const + override @property uint flags() nothrow pure const { return 1; } + + TypeInfo_Class info; + + /** + * Returns true if the class described by `child` derives from the + * interface described by this `TypeInfo_Interface`. Always returns + * false if the argument is null. + * + * Params: + * child = TypeInfo for some class + * Returns: + * true if the class described by `child` derives from the + * interface described by this `TypeInfo_Interface`. + */ + final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted { - return Object.sizeof; + return child !is null && _d_isbaseof(cast() child, this.info); + } + + /** + * Returns true if the interface described by `child` derives from + * or is the interface described by this `TypeInfo_Interface`. + * Always returns false if the argument is null. + * + * Params: + * child = TypeInfo for some interface + * Returns: + * true if the interface described by `child` derives from or is + * the interface described by this `TypeInfo_Interface`. + */ + final bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted + { + return child !is null && _d_isbaseof(cast() child.info, this.info); } } -class TypeInfo_Const : TypeInfo { - override size_t getHash(scope const(void*) p) @trusted const nothrow { return base.getHash(p); } - TypeInfo base; - override size_t size() const { return base.size; } - override const(TypeInfo) next() const { return base.next; } - override const(void)[] initializer() nothrow pure const{return base.initializer();} - override @property size_t talign() nothrow pure const { return base.talign; } - override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } -} +class TypeInfo_Const : TypeInfo +{ + override string toString() const + { + return MakeString("const(", base.toString(), ")"); + } + //override bool opEquals(Object o) { return base.opEquals(o); } + override bool opEquals(Object o) + { + if (this is o) + return true; + + if (typeid(this) != typeid(o)) + return false; + + auto t = cast(TypeInfo_Const)o; + return base.opEquals(t.base); + } + + override size_t getHash(scope const void *p) const { return base.getHash(p); } + override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); } + override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); } + override @property size_t tsize() nothrow pure const { return base.tsize; } + override void swap(void *p1, void *p2) const { return base.swap(p1, p2); } + + override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } + override @property uint flags() nothrow pure const { return base.flags; } + + override const(void)[] initializer() nothrow pure const + { + return base.initializer(); + } + + override @property size_t talign() nothrow pure const { return base.talign; } + + version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + return base.argTypes(arg1, arg2); + } + + TypeInfo base; +} ///For some reason, getHash for interfaces wanted that pragma(mangle, "_D9invariant12_d_invariantFC6ObjectZv") @@ -1596,79 +2639,47 @@ class TypeInfo_Immutable : TypeInfo { TypeInfo base; } +/ -class TypeInfo_Invariant : TypeInfo { - TypeInfo base; - override size_t getHash(scope const (void*) p) @trusted const nothrow { return base.getHash(p); } - override size_t size() const { return base.size; } - override const(TypeInfo) next() const { return base; } -} -class TypeInfo_Shared : TypeInfo { - override size_t getHash(scope const (void*) p) @trusted const nothrow { return base.getHash(p); } - TypeInfo base; - override size_t size() const { return base.size; } - override const(TypeInfo) next() const { return base; } -} -class TypeInfo_Inout : TypeInfo { - override size_t getHash(scope const (void*) p) @trusted const nothrow { return base.getHash(p); } - TypeInfo base; - override size_t size() const { return base.size; } - override const(TypeInfo) next() const { return base; } -} - -class TypeInfo_Struct : TypeInfo { - string name; - void[] m_init; - @safe pure nothrow - { - size_t function(in void*) xtoHash; - bool function(in void*, in void*) xopEquals; - int function(in void*, in void*) xopCmp; - string function(in void*) xtoString; - } - uint m_flags; - union { - void function(void*) xdtor; - void function(void*, const TypeInfo_Struct) xdtorti; - } - void function(void*) xpostblit; - uint align_; - immutable(void)* rtinfo; - // private struct _memberFunc //? Is it necessary - // { - // union - // { - // struct // delegate - // { - // const void* ptr; - // const void* funcptr; - // } - // @safe pure nothrow - // { - // bool delegate(in void*) xopEquals; - // int delegate(in void*) xopCmp; - // } - // } - // } - - enum StructFlags : uint +class TypeInfo_Invariant : TypeInfo_Const +{ + override string toString() const { - hasPointers = 0x1, - isDynamicType = 0x2, // built at runtime, needs type info in xdtor + return MakeString("immutable(", base.toString(), ")"); } - override size_t size() const { return m_init.length; } - override @property uint flags() nothrow pure const @safe @nogc { return m_flags; } +} + +class TypeInfo_Shared : TypeInfo_Const +{ + override string toString() const + { + return MakeString("shared(", base.toString(), ")"); + } +} + +class TypeInfo_Inout : TypeInfo_Const +{ + override string toString() const + { + return MakeString("inout(", base.toString(), ")"); + } +} + +class TypeInfo_Struct : TypeInfo +{ + override string toString() const { return name; } override size_t toHash() const { - return hashOf(this.name); + return hashOf(this.mangledName); } + override bool opEquals(Object o) { if (this is o) return true; auto s = cast(const TypeInfo_Struct)o; - return s && this.name == s.name; + return s && this.mangledName == s.mangledName; } + override size_t getHash(scope const void* p) @trusted pure nothrow const { assert(p); @@ -1682,21 +2693,65 @@ class TypeInfo_Struct : TypeInfo { } } - - override bool equals(in void* p1, in void* p2) @trusted const + override bool equals(in void* p1, in void* p2) @trusted pure nothrow const { + import core.stdc.string : memcmp; + if (!p1 || !p2) return false; else if (xopEquals) - return (*xopEquals)(p1, p2); + { + const dg = _memberFunc(p1, xopEquals); + return dg.xopEquals(p2); + } else if (p1 == p2) return true; else // BUG: relies on the GC not moving objects - return memcmp(p1, p2, m_init.length) == 0; + return memcmp(p1, p2, initializer().length) == 0; } - override @property size_t talign() nothrow pure const { return align_; } - final override void destroy(void* p) const + + override int compare(in void* p1, in void* p2) @trusted pure nothrow const + { + import core.stdc.string : memcmp; + + // Regard null references as always being "less than" + if (p1 != p2) + { + if (p1) + { + if (!p2) + return true; + else if (xopCmp) + { + const dg = _memberFunc(p1, xopCmp); + return dg.xopCmp(p2); + } + else + // BUG: relies on the GC not moving objects + return memcmp(p1, p2, initializer().length); + } + else + return -1; + } + return 0; + } + + override @property size_t tsize() nothrow pure const + { + return initializer().length; + } + + override const(void)[] initializer() nothrow pure const @safe + { + return m_init; + } + + override @property uint flags() nothrow pure const { return m_flags; } + + override @property size_t talign() nothrow pure const { return m_align; } + + final override void destroy(void* p) const { if (xdtor) { @@ -1713,14 +2768,107 @@ class TypeInfo_Struct : TypeInfo { (*xpostblit)(p); } - override const(void)[] initializer() nothrow pure const @safe - { - return m_init; - } + string mangledName; + final @property string name() nothrow const @trusted + { + /* + import core.demangle : demangleType; + + if (mangledName is null) // e.g., opaque structs + return null; + + const key = cast(const void*) this; // faster lookup than TypeInfo_Struct, at the cost of potential duplicates per binary + static string[typeof(key)] demangledNamesCache; // per thread + + // not nothrow: + //return demangledNamesCache.require(key, cast(string) demangleType(mangledName)); + + if (auto pDemangled = key in demangledNamesCache) + return *pDemangled; + + const demangled = cast(string) demangleType(mangledName); + demangledNamesCache[key] = demangled; + return demangled; + */ + + assert(false, "Not implemented for platform"); + + return null; + } + + void[] m_init; // initializer; m_init.ptr == null if 0 initialize + + @safe pure nothrow + { + size_t function(in void*) xtoHash; + bool function(in void*, in void*) xopEquals; + int function(in void*, in void*) xopCmp; + string function(in void*) xtoString; + + enum StructFlags : uint + { + hasPointers = 0x1, + isDynamicType = 0x2, // built at runtime, needs type info in xdtor + } + StructFlags m_flags; + } + union + { + void function(void*) xdtor; + void function(void*, const TypeInfo_Struct ti) xdtorti; + } + void function(void*) xpostblit; + + uint m_align; + + override @property immutable(void)* rtInfo() nothrow pure const @safe { return m_RTInfo; } + + version (WithArgTypes) + { + override int argTypes(out TypeInfo arg1, out TypeInfo arg2) + { + arg1 = m_arg1; + arg2 = m_arg2; + return 0; + } + TypeInfo m_arg1; + TypeInfo m_arg2; + } + immutable(void)* m_RTInfo; // data for precise GC + + // The xopEquals and xopCmp members are function pointers to member + // functions, which is not guaranteed to share the same ABI, as it is not + // known whether the `this` parameter is the first or second argument. + // This wrapper is to convert it to a delegate which will always pass the + // `this` parameter in the correct way. + private struct _memberFunc + { + union + { + struct // delegate + { + const void* ptr; + const void* funcptr; + } + @safe pure nothrow + { + bool delegate(in void*) xopEquals; + int delegate(in void*) xopCmp; + } + } + } } -extern(C) bool _xopCmp(in void*, in void*) { return false; } +bool _xopEquals(in void*, in void*) +{ + assert(false, "TypeInfo.equals is not implemented"); +} + +bool _xopCmp(in void*, in void*) +{ + assert(false, "TypeInfo.compare is not implemented"); +} // } @@ -1754,15 +2902,20 @@ TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) nothrow extern (C) void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) { - auto length = x.length; - auto tinext = ti.next; - auto sizeelem = tinext./*t*/size; // array element size - _d_arrayappendcTX(ti, x, y.length); - memcpy(x.ptr + length * sizeelem, y.ptr, y.length * sizeelem); + /* + auto length = x.length; + auto tinext = ti.next; + auto sizeelem = tinext.tsize; // array element size + _d_arrayappendcTX(ti, x, y.length); + memcpy(x.ptr + length * sizeelem, y.ptr, y.length * sizeelem); - // do postblit - //__doPostblit(x.ptr + length * sizeelem, y.length * sizeelem, tinext); - return x; + // do postblit + //__doPostblit(x.ptr + length * sizeelem, y.length * sizeelem, tinext); + */ + + assert(false, "Not implemented for platform"); + + return x; } extern (C) int _adEq2(void[] a1, void[] a2, TypeInfo ti) @@ -1981,9 +3134,10 @@ class Throwable : Object */ override string toString() { - string s; - toString((in buf) { s ~= buf; }); - return s; + string s; + assert(false, "Not implemented for platform"); + // toString((in buf) { s ~= buf; }); + return s; } /** @@ -2007,6 +3161,7 @@ class Throwable : Object return this.msg; } } + class Exception : Throwable { @@ -2027,5 +3182,91 @@ class Exception : Throwable } } +inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc +{ + TypeInfo ti = cast() cti; + while (ti) + { + // avoid dynamic type casts + auto tti = typeid(ti); + if (tti is typeid(TypeInfo_Const)) + ti = (cast(TypeInfo_Const)cast(void*)ti).base; + else if (tti is typeid(TypeInfo_Invariant)) + ti = (cast(TypeInfo_Invariant)cast(void*)ti).base; + else if (tti is typeid(TypeInfo_Shared)) + ti = (cast(TypeInfo_Shared)cast(void*)ti).base; + else if (tti is typeid(TypeInfo_Inout)) + ti = (cast(TypeInfo_Inout)cast(void*)ti).base; + else + break; + } + return ti; +} + +private void _doPostblit(T)(T[] arr) +{ + // infer static postblit type, run postblit if any + static if (__traits(hasPostblit, T)) + { + static if (__traits(isStaticArray, T) && is(T : E[], E)) + _doPostblit(cast(E[]) arr); + else static if (!is(typeof(arr[0].__xpostblit())) && is(immutable T == immutable U, U)) + foreach (ref elem; (() @trusted => cast(U[]) arr)()) + elem.__xpostblit(); + else + foreach (ref elem; arr) + elem.__xpostblit(); + } +} + +private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow +{ + TypeInfo element = cast() value; + for (;;) + { + if (auto qualified = cast(TypeInfo_Const) element) + element = qualified.base; + else if (auto redefined = cast(TypeInfo_Enum) element) + element = redefined.base; + else if (auto staticArray = cast(TypeInfo_StaticArray) element) + element = staticArray.value; + //else if (auto vector = cast(TypeInfo_Vector) element) + // element = vector.base; + else + break; + } + return cast(inout) element; +} + +private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, const size_t count) @trusted nothrow +{ + if (!count) + return 0; + + const size_t elementSize = element.tsize; + if (!elementSize) + return 0; + + static bool hasCustomToHash(const scope TypeInfo value) @trusted pure nothrow + { + const element = getElement(value); + + if (const struct_ = cast(const TypeInfo_Struct) element) + return !!struct_.xtoHash; + + return cast(const TypeInfo_Array) element + //|| cast(const TypeInfo_AssociativeArray) element + || cast(const ClassInfo) element + || cast(const TypeInfo_Interface) element; + } + + if (!hasCustomToHash(element)) + return hashOf(ptr[0 .. elementSize * count]); + + size_t hash = 0; + foreach (size_t i; 0 .. count) + hash = hashOf(element.getHash(ptr + i * elementSize), hash); + return hash; +} import core.internal.hash; diff --git a/external/arsd-webassembly/std/math/rounding.d b/external/arsd-webassembly/std/math/rounding.d new file mode 100644 index 0000000..72a6e6f --- /dev/null +++ b/external/arsd-webassembly/std/math/rounding.d @@ -0,0 +1,8 @@ +module std.math.rounding; + +pragma(LDC_intrinsic, "llvm.round.f#") +T llvm_round(T)(T val) +if (__traits(isFloating, T)); + +float round(float x) => llvm_round(x); +double round(double x) => llvm_round(x); diff --git a/external/cglm/aabb2d.h b/external/cglm/aabb2d.h deleted file mode 100644 index 6369d08..0000000 --- a/external/cglm/aabb2d.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_aabb2d_h -#define cglm_aabb2d_h - -#include "common.h" -#include "vec2.h" -#include "util.h" - -/* DEPRECATED! use _diag */ -#define glm_aabb2d_size(aabb) glm_aabb2d_diag(aabb) - -/*! - * @brief make [aabb] zero - * - * @param[in, out] aabb aabb - */ -CGLM_INLINE -void -glm_aabb2d_zero(vec2 aabb[2]) { - glm_vec2_zero(aabb[0]); - glm_vec2_zero(aabb[1]); -} - -/*! - * @brief copy all members of [aabb] to [dest] - * - * @param[in] aabb source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_aabb2d_copy(vec2 aabb[2], vec2 dest[2]) { - glm_vec2_copy(aabb[0], dest[0]); - glm_vec2_copy(aabb[1], dest[1]); -} - -/*! - * @brief apply transform to Axis-Aligned Bounding aabb - * - * @param[in] aabb bounding aabb - * @param[in] m transform matrix - * @param[out] dest transformed bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]) { - vec2 v[2], xa, xb, ya, yb; - - glm_vec2_scale(m[0], aabb[0][0], xa); - glm_vec2_scale(m[0], aabb[1][0], xb); - - glm_vec2_scale(m[1], aabb[0][1], ya); - glm_vec2_scale(m[1], aabb[1][1], yb); - - /* translation + min(xa, xb) + min(ya, yb) */ - glm_vec2(m[2], v[0]); - glm_vec2_minadd(xa, xb, v[0]); - glm_vec2_minadd(ya, yb, v[0]); - - /* translation + max(xa, xb) + max(ya, yb) */ - glm_vec2(m[2], v[1]); - glm_vec2_maxadd(xa, xb, v[1]); - glm_vec2_maxadd(ya, yb, v[1]); - - glm_vec2_copy(v[0], dest[0]); - glm_vec2_copy(v[1], dest[1]); -} - -/*! - * @brief merges two AABB bounding aabb and creates new one - * - * two aabb must be in same space, if one of aabb is in different space then - * you should consider to convert it's space by glm_aabb_space - * - * @param[in] aabb1 bounding aabb 1 - * @param[in] aabb2 bounding aabb 2 - * @param[out] dest merged bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]) { - dest[0][0] = glm_min(aabb1[0][0], aabb2[0][0]); - dest[0][1] = glm_min(aabb1[0][1], aabb2[0][1]); - - dest[1][0] = glm_max(aabb1[1][0], aabb2[1][0]); - dest[1][1] = glm_max(aabb1[1][1], aabb2[1][1]); -} - -/*! - * @brief crops a bounding aabb with another one. - * - * this could be useful for getting a baabb which fits with view frustum and - * object bounding aabbes. In this case you crop view frustum aabb with objects - * aabb - * - * @param[in] aabb bounding aabb 1 - * @param[in] cropAabb crop aabb - * @param[out] dest cropped bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]) { - dest[0][0] = glm_max(aabb[0][0], cropAabb[0][0]); - dest[0][1] = glm_max(aabb[0][1], cropAabb[0][1]); - - dest[1][0] = glm_min(aabb[1][0], cropAabb[1][0]); - dest[1][1] = glm_min(aabb[1][1], cropAabb[1][1]); -} - -/*! - * @brief crops a bounding aabb with another one. - * - * this could be useful for getting a baabb which fits with view frustum and - * object bounding aabbes. In this case you crop view frustum aabb with objects - * aabb - * - * @param[in] aabb bounding aabb - * @param[in] cropAabb crop aabb - * @param[in] clampAabb minimum aabb - * @param[out] dest cropped bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_crop_until(vec2 aabb[2], - vec2 cropAabb[2], - vec2 clampAabb[2], - vec2 dest[2]) { - glm_aabb2d_crop(aabb, cropAabb, dest); - glm_aabb2d_merge(clampAabb, dest, dest); -} - -/*! - * @brief invalidate AABB min and max values - * - * @param[in, out] aabb bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_invalidate(vec2 aabb[2]) { - glm_vec2_fill(aabb[0], FLT_MAX); - glm_vec2_fill(aabb[1], -FLT_MAX); -} - -/*! - * @brief check if AABB is valid or not - * - * @param[in] aabb bounding aabb - */ -CGLM_INLINE -bool -glm_aabb2d_isvalid(vec2 aabb[2]) { - return glm_vec2_max(aabb[0]) != FLT_MAX - && glm_vec2_min(aabb[1]) != -FLT_MAX; -} - -/*! - * @brief distance between of min and max - * - * @param[in] aabb bounding aabb - */ -CGLM_INLINE -float -glm_aabb2d_diag(vec2 aabb[2]) { - return glm_vec2_distance(aabb[0], aabb[1]); -} - -/*! - * @brief size of aabb - * - * @param[in] aabb bounding aabb - * @param[out] dest size - */ -CGLM_INLINE -void -glm_aabb2d_sizev(vec2 aabb[2], vec2 dest) { - glm_vec2_sub(aabb[1], aabb[0], dest); -} - -/*! - * @brief radius of sphere which surrounds AABB - * - * @param[in] aabb bounding aabb - */ -CGLM_INLINE -float -glm_aabb2d_radius(vec2 aabb[2]) { - return glm_aabb2d_diag(aabb) * 0.5f; -} - -/*! - * @brief computes center point of AABB - * - * @param[in] aabb bounding aabb - * @param[out] dest center of bounding aabb - */ -CGLM_INLINE -void -glm_aabb2d_center(vec2 aabb[2], vec2 dest) { - glm_vec2_center(aabb[0], aabb[1], dest); -} - -/*! - * @brief check if two AABB intersects - * - * @param[in] aabb bounding aabb - * @param[in] other other bounding aabb - */ -CGLM_INLINE -bool -glm_aabb2d_aabb(vec2 aabb[2], vec2 other[2]) { - return (aabb[0][0] <= other[1][0] && aabb[1][0] >= other[0][0]) - && (aabb[0][1] <= other[1][1] && aabb[1][1] >= other[0][1]); -} - -/*! - * @brief check if AABB intersects with a circle - * - * Circle Representation in cglm: [center.x, center.y, radii] - * - * @param[in] aabb solid bounding aabb - * @param[in] c solid circle - */ -CGLM_INLINE -bool -glm_aabb2d_circle(vec2 aabb[2], vec3 c) { - float dmin; - int a, b; - - a = (c[0] < aabb[0][0]) + (c[0] > aabb[1][0]); - b = (c[1] < aabb[0][1]) + (c[1] > aabb[1][1]); - - dmin = glm_pow2((c[0] - aabb[!(a - 1)][0]) * (a != 0)) - + glm_pow2((c[1] - aabb[!(b - 1)][1]) * (b != 0)); - - return dmin <= glm_pow2(c[2]); -} - -/*! - * @brief check if point is inside of AABB - * - * @param[in] aabb bounding aabb - * @param[in] point point - */ -CGLM_INLINE -bool -glm_aabb2d_point(vec2 aabb[2], vec2 point) { - return (point[0] >= aabb[0][0] && point[0] <= aabb[1][0]) - && (point[1] >= aabb[0][1] && point[1] <= aabb[1][1]); -} - -/*! - * @brief check if AABB contains other AABB - * - * @param[in] aabb bounding aabb - * @param[in] other other bounding aabb - */ -CGLM_INLINE -bool -glm_aabb2d_contains(vec2 aabb[2], vec2 other[2]) { - return (aabb[0][0] <= other[0][0] && aabb[1][0] >= other[1][0]) - && (aabb[0][1] <= other[0][1] && aabb[1][1] >= other[1][1]); -} - -#endif /* cglm_aabb2d_h */ diff --git a/external/cglm/affine-mat.h b/external/cglm/affine-mat.h deleted file mode 100644 index c22c0e0..0000000 --- a/external/cglm/affine-mat.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_mul(mat4 m1, mat4 m2, mat4 dest); - CGLM_INLINE void glm_mul_rot(mat4 m1, mat4 m2, mat4 dest); - CGLM_INLINE void glm_inv_tr(mat4 mat); - */ - -#ifndef cglm_affine_mat_h -#define cglm_affine_mat_h - -#include "common.h" -#include "mat4.h" -#include "mat3.h" - -#ifdef CGLM_SSE_FP -# include "simd/sse2/affine.h" -#endif - -#ifdef CGLM_AVX_FP -# include "simd/avx/affine.h" -#endif - -#ifdef CGLM_NEON_FP -# include "simd/neon/affine.h" -#endif - -#ifdef CGLM_SIMD_WASM -# include "simd/wasm/affine.h" -#endif - -/*! - * @brief this is similar to glm_mat4_mul but specialized to affine transform - * - * Matrix format should be: - * R R R X - * R R R Y - * R R R Z - * 0 0 0 W - * - * this reduces some multiplications. It should be faster than mat4_mul. - * if you are not sure about matrix format then DON'T use this! use mat4_mul - * - * @param[in] m1 affine matrix 1 - * @param[in] m2 affine matrix 2 - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_mul(mat4 m1, mat4 m2, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mul_wasm(m1, m2, dest); -#elif defined(__AVX__) - glm_mul_avx(m1, m2, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mul_sse2(m1, m2, dest); -#elif defined(CGLM_NEON_FP) - glm_mul_neon(m1, m2, dest); -#else - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], - a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], - b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; - dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; - dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; - - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; - dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; - - dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; - dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; - dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; - dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; -#endif -} - -/*! - * @brief this is similar to glm_mat4_mul but specialized to affine transform - * - * Right Matrix format should be: - * R R R 0 - * R R R 0 - * R R R 0 - * 0 0 0 1 - * - * this reduces some multiplications. It should be faster than mat4_mul. - * if you are not sure about matrix format then DON'T use this! use mat4_mul - * - * @param[in] m1 affine matrix 1 - * @param[in] m2 affine matrix 2 - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_mul_rot(mat4 m1, mat4 m2, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mul_rot_wasm(m1, m2, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mul_rot_sse2(m1, m2, dest); -#elif defined(CGLM_NEON_FP) - glm_mul_rot_neon(m1, m2, dest); -#else - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], - a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; - dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; - dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; - - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; - dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; - - dest[3][0] = a30; - dest[3][1] = a31; - dest[3][2] = a32; - dest[3][3] = a33; -#endif -} - -/*! - * @brief inverse orthonormal rotation + translation matrix (ridig-body) - * - * @code - * X = | R T | X' = | R' -R'T | - * | 0 1 | | 0 1 | - * @endcode - * - * @param[in,out] mat matrix - */ -CGLM_INLINE -void -glm_inv_tr(mat4 mat) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_inv_tr_wasm(mat); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_inv_tr_sse2(mat); -#elif defined(CGLM_NEON_FP) - glm_inv_tr_neon(mat); -#else - CGLM_ALIGN_MAT mat3 r; - CGLM_ALIGN(8) vec3 t; - - /* rotate */ - glm_mat4_pick3t(mat, r); - glm_mat4_ins3(r, mat); - - /* translate */ - glm_mat3_mulv(r, mat[3], t); - glm_vec3_negate(t); - glm_vec3_copy(t, mat[3]); -#endif -} - -#endif /* cglm_affine_mat_h */ diff --git a/external/cglm/affine-post.h b/external/cglm/affine-post.h deleted file mode 100644 index 3e297e6..0000000 --- a/external/cglm/affine-post.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_post_h -#define cglm_affine_post_h - -/* - Functions: - CGLM_INLINE void glm_translated_to(mat4 m, vec3 v, mat4 dest); - CGLM_INLINE void glm_translated(mat4 m, vec3 v); - CGLM_INLINE void glm_translated_x(mat4 m, float to); - CGLM_INLINE void glm_translated_y(mat4 m, float to); - CGLM_INLINE void glm_translated_z(mat4 m, float to); - CGLM_INLINE void glm_rotated_x(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotated_y(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotated_z(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotated(mat4 m, float angle, vec3 axis); - CGLM_INLINE void glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); - CGLM_INLINE void glm_spinned(mat4 m, float angle, vec3 axis); - */ - -#include "common.h" -#include "util.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" -#include "affine-mat.h" - -/*! - * @brief translate existing transform matrix by v vector - * and stores result in same matrix - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] v translate vector [x, y, z] - */ -CGLM_INLINE -void -glm_translated(mat4 m, vec3 v) { - glm_vec3_add(m[3], v, m[3]); -} - -/*! - * @brief translate existing transform matrix by v vector - * and store result in dest - * - * source matrix will remain same - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y, z] - * @param[out] dest translated matrix - */ -CGLM_INLINE -void -glm_translated_to(mat4 m, vec3 v, mat4 dest) { - glm_mat4_copy(m, dest); - glm_translated(dest, v); -} - -/*! - * @brief translate existing transform matrix by x factor - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] x x factor - */ -CGLM_INLINE -void -glm_translated_x(mat4 m, float x) { - m[3][0] += x; -} - -/*! - * @brief translate existing transform matrix by y factor - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] y y factor - */ -CGLM_INLINE -void -glm_translated_y(mat4 m, float y) { - m[3][1] += y; -} - -/*! - * @brief translate existing transform matrix by z factor - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] z z factor - */ -CGLM_INLINE -void -glm_translated_z(mat4 m, float z) { - m[3][2] += z; -} - -/*! - * @brief rotate existing transform matrix around X axis by angle - * and store result in dest - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotated_x(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[1][1] = c; - t[1][2] = s; - t[2][1] = -s; - t[2][2] = c; - - glm_mul_rot(t, m, dest); -} - -/*! - * @brief rotate existing transform matrix around Y axis by angle - * and store result in dest - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotated_y(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[0][0] = c; - t[0][2] = -s; - t[2][0] = s; - t[2][2] = c; - - glm_mul_rot(t, m, dest); -} - -/*! - * @brief rotate existing transform matrix around Z axis by angle - * and store result in dest - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotated_z(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[0][0] = c; - t[0][1] = s; - t[1][0] = -s; - t[1][1] = c; - - glm_mul_rot(t, m, dest); -} - -/*! - * @brief rotate existing transform matrix around given axis by angle - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotated(mat4 m, float angle, vec3 axis) { - CGLM_ALIGN_MAT mat4 rot; - glm_rotate_make(rot, angle, axis); - glm_mul_rot(rot, m, m); -} - -/*! - * @brief rotate existing transform - * around given axis by angle at given pivot point (rotation center) - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis) { - CGLM_ALIGN(8) vec3 pivotInv; - - glm_vec3_negate_to(pivot, pivotInv); - - glm_translated(m, pivot); - glm_rotated(m, angle, axis); - glm_translated(m, pivotInv); -} - -/*! - * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_spinned(mat4 m, float angle, vec3 axis) { - CGLM_ALIGN_MAT mat4 rot; - glm_rotate_atm(rot, m[3], angle, axis); - glm_mat4_mul(rot, m, m); -} - -#endif /* cglm_affine_post_h */ diff --git a/external/cglm/affine-pre.h b/external/cglm/affine-pre.h deleted file mode 100644 index 2fa77f7..0000000 --- a/external/cglm/affine-pre.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_pre_h -#define cglm_affine_pre_h - -/* - Functions: - CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); - CGLM_INLINE void glm_translate(mat4 m, vec3 v); - CGLM_INLINE void glm_translate_x(mat4 m, float to); - CGLM_INLINE void glm_translate_y(mat4 m, float to); - CGLM_INLINE void glm_translate_z(mat4 m, float to); - CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); - CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); - CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); - CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); - */ - -#include "common.h" -#include "util.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" -#include "affine-mat.h" - -/*! - * @brief translate existing transform matrix by v vector - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] v translate vector [x, y, z] - */ -CGLM_INLINE -void -glm_translate(mat4 m, vec3 v) { -#if defined(CGLM_SIMD) - glmm_128 m0, m1, m2, m3; - - m0 = glmm_load(m[0]); - m1 = glmm_load(m[1]); - m2 = glmm_load(m[2]); - m3 = glmm_load(m[3]); - - glmm_store(m[3], - glmm_fmadd(m0, glmm_set1(v[0]), - glmm_fmadd(m1, glmm_set1(v[1]), - glmm_fmadd(m2, glmm_set1(v[2]), m3)))); -#else - glm_vec4_muladds(m[0], v[0], m[3]); - glm_vec4_muladds(m[1], v[1], m[3]); - glm_vec4_muladds(m[2], v[2], m[3]); -#endif -} - -/*! - * @brief translate existing transform matrix by v vector - * and store result in dest - * - * source matrix will remain same - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y, z] - * @param[out] dest translated matrix - */ -CGLM_INLINE -void -glm_translate_to(mat4 m, vec3 v, mat4 dest) { - glm_mat4_copy(m, dest); - glm_translate(dest, v); -} - -/*! - * @brief translate existing transform matrix by x factor - * - * @param[in, out] m affine transform - * @param[in] x x factor - */ -CGLM_INLINE -void -glm_translate_x(mat4 m, float x) { -#if defined(CGLM_SIMD) - glmm_store(m[3], glmm_fmadd(glmm_load(m[0]), glmm_set1(x), glmm_load(m[3]))); -#else - vec4 v1; - glm_vec4_scale(m[0], x, v1); - glm_vec4_add(v1, m[3], m[3]); -#endif -} - -/*! - * @brief translate existing transform matrix by y factor - * - * @param[in, out] m affine transform - * @param[in] y y factor - */ -CGLM_INLINE -void -glm_translate_y(mat4 m, float y) { -#if defined(CGLM_SIMD) - glmm_store(m[3], glmm_fmadd(glmm_load(m[1]), glmm_set1(y), glmm_load(m[3]))); -#else - vec4 v1; - glm_vec4_scale(m[1], y, v1); - glm_vec4_add(v1, m[3], m[3]); -#endif -} - -/*! - * @brief translate existing transform matrix by z factor - * - * @param[in, out] m affine transform - * @param[in] z z factor - */ -CGLM_INLINE -void -glm_translate_z(mat4 m, float z) { -#if defined(CGLM_SIMD) - glmm_store(m[3], glmm_fmadd(glmm_load(m[2]), glmm_set1(z), glmm_load(m[3]))); -#else - vec4 v1; - glm_vec4_scale(m[2], z, v1); - glm_vec4_add(v1, m[3], m[3]); -#endif -} - -/*! - * @brief rotate existing transform matrix around X axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotate_x(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[1][1] = c; - t[1][2] = s; - t[2][1] = -s; - t[2][2] = c; - - glm_mul_rot(m, t, dest); -} - -/*! - * @brief rotate existing transform matrix around Y axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotate_y(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[0][0] = c; - t[0][2] = -s; - t[2][0] = s; - t[2][2] = c; - - glm_mul_rot(m, t, dest); -} - -/*! - * @brief rotate existing transform matrix around Z axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest rotated matrix - */ -CGLM_INLINE -void -glm_rotate_z(mat4 m, float angle, mat4 dest) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - t[0][0] = c; - t[0][1] = s; - t[1][0] = -s; - t[1][1] = c; - - glm_mul_rot(m, t, dest); -} - -/*! - * @brief rotate existing transform matrix - * around given axis by angle at ORIGIN (0,0,0) - * - * **❗️IMPORTANT ❗️** - * - * If you need to rotate object around itself e.g. center of object or at - * some point [of object] then `glm_rotate_at()` would be better choice to do so. - * - * Even if object's model transform is identity, rotation may not be around - * center of object if object does not lay out at ORIGIN perfectly. - * - * Using `glm_rotate_at()` with center of bounding shape ( AABB, Sphere ... ) - * would be an easy option to rotate around object if object is not at origin. - * - * One another option to rotate around itself at any point is `glm_spin()` - * which is perfect if only rotating around model position is desired e.g. not - * specific point on model for instance center of geometry or center of mass, - * again if geometry is not perfectly centered at origin at identity transform, - * rotation may not be around geometry. - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotate(mat4 m, float angle, vec3 axis) { - CGLM_ALIGN_MAT mat4 rot; - glm_rotate_make(rot, angle, axis); - glm_mul_rot(m, rot, m); -} - -/*! - * @brief rotate existing transform - * around given axis by angle at given pivot point (rotation center) - * - * @param[in, out] m affine transform - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) { - CGLM_ALIGN(8) vec3 pivotInv; - - glm_vec3_negate_to(pivot, pivotInv); - - glm_translate(m, pivot); - glm_rotate(m, angle, axis); - glm_translate(m, pivotInv); -} - -/*! - * @brief creates NEW rotation matrix by angle and axis at given point - * - * this creates rotation matrix, it assumes you don't have a matrix - * - * this should work faster than glm_rotate_at because it reduces - * one glm_translate. - * - * @param[out] m affine transform - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) { - CGLM_ALIGN(8) vec3 pivotInv; - - glm_vec3_negate_to(pivot, pivotInv); - - glm_translate_make(m, pivot); - glm_rotate(m, angle, axis); - glm_translate(m, pivotInv); -} - -/*! - * @brief rotate existing transform matrix - * around given axis by angle around self (doesn't affected by position) - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_spin(mat4 m, float angle, vec3 axis) { - CGLM_ALIGN_MAT mat4 rot; - glm_rotate_atm(rot, m[3], angle, axis); - glm_mat4_mul(m, rot, m); -} - -#endif /* cglm_affine_pre_h */ diff --git a/external/cglm/affine.h b/external/cglm/affine.h deleted file mode 100644 index 2c608f7..0000000 --- a/external/cglm/affine.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_translate_to(mat4 m, vec3 v, mat4 dest); - CGLM_INLINE void glm_translate(mat4 m, vec3 v); - CGLM_INLINE void glm_translate_x(mat4 m, float to); - CGLM_INLINE void glm_translate_y(mat4 m, float to); - CGLM_INLINE void glm_translate_z(mat4 m, float to); - CGLM_INLINE void glm_translate_make(mat4 m, vec3 v); - CGLM_INLINE void glm_scale_to(mat4 m, vec3 v, mat4 dest); - CGLM_INLINE void glm_scale_make(mat4 m, vec3 v); - CGLM_INLINE void glm_scale(mat4 m, vec3 v); - CGLM_INLINE void glm_scale_uni(mat4 m, float s); - CGLM_INLINE void glm_rotate_x(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate_y(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate_z(mat4 m, float angle, mat4 dest); - CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis); - CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); - CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); - CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); - CGLM_INLINE void glm_spin(mat4 m, float angle, vec3 axis); - CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s); - CGLM_INLINE bool glm_uniscaled(mat4 m); - CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s); - CGLM_INLINE void glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s); - */ - -#ifndef cglm_affine_h -#define cglm_affine_h - -#include "common.h" -#include "util.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" -#include "affine-mat.h" - -/*! - * @brief creates NEW translate transform matrix by v vector - * - * @param[out] m affine transform - * @param[in] v translate vector [x, y, z] - */ -CGLM_INLINE -void -glm_translate_make(mat4 m, vec3 v) { - glm_mat4_identity(m); - glm_vec3_copy(v, m[3]); -} - -/*! - * @brief scale existing transform matrix by v vector - * and store result in dest - * - * @param[in] m affine transform - * @param[in] v scale vector [x, y, z] - * @param[out] dest scaled matrix - */ -CGLM_INLINE -void -glm_scale_to(mat4 m, vec3 v, mat4 dest) { - glm_vec4_scale(m[0], v[0], dest[0]); - glm_vec4_scale(m[1], v[1], dest[1]); - glm_vec4_scale(m[2], v[2], dest[2]); - - glm_vec4_copy(m[3], dest[3]); -} - -/*! - * @brief creates NEW scale matrix by v vector - * - * @param[out] m affine transform - * @param[in] v scale vector [x, y, z] - */ -CGLM_INLINE -void -glm_scale_make(mat4 m, vec3 v) { - glm_mat4_identity(m); - m[0][0] = v[0]; - m[1][1] = v[1]; - m[2][2] = v[2]; -} - -/*! - * @brief scales existing transform matrix by v vector - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] v scale vector [x, y, z] - */ -CGLM_INLINE -void -glm_scale(mat4 m, vec3 v) { - glm_scale_to(m, v, m); -} - -/*! - * @brief applies uniform scale to existing transform matrix v = [s, s, s] - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] s scale factor - */ -CGLM_INLINE -void -glm_scale_uni(mat4 m, float s) { - CGLM_ALIGN(8) vec3 v = { s, s, s }; - glm_scale_to(m, v, m); -} - -/*! - * @brief creates NEW rotation matrix by angle and axis - * - * axis will be normalized so you don't need to normalize it - * - * @param[out] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_rotate_make(mat4 m, float angle, vec3 axis) { - CGLM_ALIGN(8) vec3 axisn, v, vs; - float c; - - c = cosf(angle); - - glm_vec3_normalize_to(axis, axisn); - glm_vec3_scale(axisn, 1.0f - c, v); - glm_vec3_scale(axisn, sinf(angle), vs); - - glm_vec3_scale(axisn, v[0], m[0]); - glm_vec3_scale(axisn, v[1], m[1]); - glm_vec3_scale(axisn, v[2], m[2]); - - m[0][0] += c; m[1][0] -= vs[2]; m[2][0] += vs[1]; - m[0][1] += vs[2]; m[1][1] += c; m[2][1] -= vs[0]; - m[0][2] -= vs[1]; m[1][2] += vs[0]; m[2][2] += c; - - m[0][3] = m[1][3] = m[2][3] = m[3][0] = m[3][1] = m[3][2] = 0.0f; - m[3][3] = 1.0f; -} - -/*! - * @brief decompose scale vector - * - * @param[in] m affine transform - * @param[out] s scale vector (Sx, Sy, Sz) - */ -CGLM_INLINE -void -glm_decompose_scalev(mat4 m, vec3 s) { - s[0] = glm_vec3_norm(m[0]); - s[1] = glm_vec3_norm(m[1]); - s[2] = glm_vec3_norm(m[2]); -} - -/*! - * @brief returns true if matrix is uniform scaled. This is helpful for - * creating normal matrix. - * - * @param[in] m m - * - * @return boolean - */ -CGLM_INLINE -bool -glm_uniscaled(mat4 m) { - CGLM_ALIGN(8) vec3 s; - glm_decompose_scalev(m, s); - return glm_vec3_eq_all(s); -} - -/*! - * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] - * DON'T pass projected matrix here - * - * @param[in] m affine transform - * @param[out] r rotation matrix - * @param[out] s scale matrix - */ -CGLM_INLINE -void -glm_decompose_rs(mat4 m, mat4 r, vec3 s) { - CGLM_ALIGN(16) vec4 t = {0.0f, 0.0f, 0.0f, 1.0f}; - CGLM_ALIGN(8) vec3 v; - - glm_vec4_copy(m[0], r[0]); - glm_vec4_copy(m[1], r[1]); - glm_vec4_copy(m[2], r[2]); - glm_vec4_copy(t, r[3]); - - s[0] = glm_vec3_norm(m[0]); - s[1] = glm_vec3_norm(m[1]); - s[2] = glm_vec3_norm(m[2]); - - glm_vec4_scale(r[0], 1.0f/s[0], r[0]); - glm_vec4_scale(r[1], 1.0f/s[1], r[1]); - glm_vec4_scale(r[2], 1.0f/s[2], r[2]); - - /* Note from Apple Open Source (assume that the matrix is orthonormal): - check for a coordinate system flip. If the determinant - is -1, then negate the matrix and the scaling factors. */ - glm_vec3_cross(m[0], m[1], v); - if (glm_vec3_dot(v, m[2]) < 0.0f) { - glm_vec4_negate(r[0]); - glm_vec4_negate(r[1]); - glm_vec4_negate(r[2]); - glm_vec3_negate(s); - } -} - -/*! - * @brief decompose affine transform, TODO: extract shear factors. - * DON'T pass projected matrix here - * - * @param[in] m affine transform - * @param[out] t translation vector - * @param[out] r rotation matrix (mat4) - * @param[out] s scaling vector [X, Y, Z] - */ -CGLM_INLINE -void -glm_decompose(mat4 m, vec4 t, mat4 r, vec3 s) { - glm_vec4_copy(m[3], t); - glm_decompose_rs(m, r, s); -} - -#include "affine-pre.h" -#include "affine-post.h" - -#endif /* cglm_affine_h */ diff --git a/external/cglm/affine2d-post.h b/external/cglm/affine2d-post.h deleted file mode 100644 index c6605a8..0000000 --- a/external/cglm/affine2d-post.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine2d_post_h -#define cglm_affine2d_post_h - -/* - Functions: - CGLM_INLINE void glm_translated2d(mat3 m, vec2 v); - CGLM_INLINE void glm_translated2d_x(mat3 m, float to); - CGLM_INLINE void glm_translated2d_y(mat3 m, float to); - CGLM_INLINE void glm_rotated2d(mat3 m, float angle); - CGLM_INLINE void glm_scaled2d(mat3 m, vec2 v); - CGLM_INLINE void glm_scaled2d_uni(mat3 m, float s); - */ - -#include "vec2.h" - -/*! - * @brief translate existing transform matrix by v vector - * and store result in same matrix - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] v translate vector [x, y] - */ -CGLM_INLINE -void -glm_translated2d(mat3 m, vec2 v) { - glm_vec2_add(m[2], v, m[2]); -} - -/*! - * @brief translate existing transform matrix by x factor - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] x x factor - */ -CGLM_INLINE -void -glm_translated2d_x(mat3 m, float x) { - m[2][0] += x; -} - -/*! - * @brief translate existing transform matrix by y factor - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] y y factor - */ -CGLM_INLINE -void -glm_translated2d_y(mat3 m, float y) { - m[2][1] += y; -} - -/*! - * @brief rotate existing transform matrix by angle - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - */ -CGLM_INLINE -void -glm_rotated2d(mat3 m, float angle) { - float c = cosf(angle), - s = sinf(angle), - - m00 = m[0][0], m10 = m[1][0], m20 = m[2][0], - m01 = m[0][1], m11 = m[1][1], m21 = m[2][1]; - - m[0][0] = c * m00 - s * m01; - m[1][0] = c * m10 - s * m11; - m[2][0] = c * m20 - s * m21; - - m[0][1] = s * m00 + c * m01; - m[1][1] = s * m10 + c * m11; - m[2][1] = s * m20 + c * m21; -} - -/*! - * @brief scale existing 2d transform matrix by v vector - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] v scale vector [x, y] - */ -CGLM_INLINE -void -glm_scaled2d(mat3 m, vec2 v) { - m[0][0] *= v[0]; - m[1][0] *= v[0]; - m[2][0] *= v[0]; - - m[0][1] *= v[1]; - m[1][1] *= v[1]; - m[2][1] *= v[1]; -} - -/*! - * @brief applies uniform scale to existing 2d transform matrix v = [s, s] - * - * this is POST transform, applies to existing transform as last transform - * - * @param[in, out] m affine transform - * @param[in] s scale factor - */ -CGLM_INLINE -void -glm_scaled2d_uni(mat3 m, float s) { - m[0][0] *= s; - m[1][0] *= s; - m[2][0] *= s; - - m[0][1] *= s; - m[1][1] *= s; - m[2][1] *= s; -} - -#endif /* cglm_affine2d_post_h */ diff --git a/external/cglm/affine2d.h b/external/cglm/affine2d.h deleted file mode 100644 index 0dcf50a..0000000 --- a/external/cglm/affine2d.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_translate2d(mat3 m, vec2 v) - CGLM_INLINE void glm_translate2d_to(mat3 m, vec2 v, mat3 dest) - CGLM_INLINE void glm_translate2d_x(mat3 m, float x) - CGLM_INLINE void glm_translate2d_y(mat3 m, float y) - CGLM_INLINE void glm_translate2d_make(mat3 m, vec2 v) - CGLM_INLINE void glm_scale2d_to(mat3 m, vec2 v, mat3 dest) - CGLM_INLINE void glm_scale2d_make(mat3 m, vec2 v) - CGLM_INLINE void glm_scale2d(mat3 m, vec2 v) - CGLM_INLINE void glm_scale2d_uni(mat3 m, float s) - CGLM_INLINE void glm_rotate2d_make(mat3 m, float angle) - CGLM_INLINE void glm_rotate2d(mat3 m, float angle) - CGLM_INLINE void glm_rotate2d_to(mat3 m, float angle, mat3 dest) - */ - -#ifndef cglm_affine2d_h -#define cglm_affine2d_h - -#include "common.h" -#include "util.h" -#include "vec2.h" -#include "mat3.h" - -/*! - * @brief translate existing 2d transform matrix by v vector - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] v translate vector [x, y] - */ -CGLM_INLINE -void -glm_translate2d(mat3 m, vec2 v) { - m[2][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0]; - m[2][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1]; - m[2][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2]; -} - -/*! - * @brief translate existing 2d transform matrix by v vector - * and store result in dest - * - * source matrix will remain same - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y] - * @param[out] dest translated matrix - */ -CGLM_INLINE -void -glm_translate2d_to(mat3 m, vec2 v, mat3 dest) { - glm_mat3_copy(m, dest); - glm_translate2d(dest, v); -} - -/*! - * @brief translate existing 2d transform matrix by x factor - * - * @param[in, out] m affine transform - * @param[in] x x factor - */ -CGLM_INLINE -void -glm_translate2d_x(mat3 m, float x) { - m[2][0] = m[0][0] * x + m[2][0]; - m[2][1] = m[0][1] * x + m[2][1]; - m[2][2] = m[0][2] * x + m[2][2]; -} - -/*! - * @brief translate existing 2d transform matrix by y factor - * - * @param[in, out] m affine transform - * @param[in] y y factor - */ -CGLM_INLINE -void -glm_translate2d_y(mat3 m, float y) { - m[2][0] = m[1][0] * y + m[2][0]; - m[2][1] = m[1][1] * y + m[2][1]; - m[2][2] = m[1][2] * y + m[2][2]; -} - -/*! - * @brief creates NEW translate 2d transform matrix by v vector - * - * @param[out] m affine transform - * @param[in] v translate vector [x, y] - */ -CGLM_INLINE -void -glm_translate2d_make(mat3 m, vec2 v) { - glm_mat3_identity(m); - m[2][0] = v[0]; - m[2][1] = v[1]; -} - -/*! - * @brief scale existing 2d transform matrix by v vector - * and store result in dest - * - * @param[in] m affine transform - * @param[in] v scale vector [x, y] - * @param[out] dest scaled matrix - */ -CGLM_INLINE -void -glm_scale2d_to(mat3 m, vec2 v, mat3 dest) { - dest[0][0] = m[0][0] * v[0]; - dest[0][1] = m[0][1] * v[0]; - dest[0][2] = m[0][2] * v[0]; - - dest[1][0] = m[1][0] * v[1]; - dest[1][1] = m[1][1] * v[1]; - dest[1][2] = m[1][2] * v[1]; - - dest[2][0] = m[2][0]; - dest[2][1] = m[2][1]; - dest[2][2] = m[2][2]; -} - -/*! - * @brief creates NEW 2d scale matrix by v vector - * - * @param[out] m affine transform - * @param[in] v scale vector [x, y] - */ -CGLM_INLINE -void -glm_scale2d_make(mat3 m, vec2 v) { - glm_mat3_identity(m); - m[0][0] = v[0]; - m[1][1] = v[1]; -} - -/*! - * @brief scales existing 2d transform matrix by v vector - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] v scale vector [x, y] - */ -CGLM_INLINE -void -glm_scale2d(mat3 m, vec2 v) { - m[0][0] = m[0][0] * v[0]; - m[0][1] = m[0][1] * v[0]; - m[0][2] = m[0][2] * v[0]; - - m[1][0] = m[1][0] * v[1]; - m[1][1] = m[1][1] * v[1]; - m[1][2] = m[1][2] * v[1]; -} - -/*! - * @brief applies uniform scale to existing 2d transform matrix v = [s, s] - * and stores result in same matrix - * - * @param[in, out] m affine transform - * @param[in] s scale factor - */ -CGLM_INLINE -void -glm_scale2d_uni(mat3 m, float s) { - m[0][0] = m[0][0] * s; - m[0][1] = m[0][1] * s; - m[0][2] = m[0][2] * s; - - m[1][0] = m[1][0] * s; - m[1][1] = m[1][1] * s; - m[1][2] = m[1][2] * s; -} - -/*! - * @brief creates NEW rotation matrix by angle around Z axis - * - * @param[out] m affine transform - * @param[in] angle angle (radians) - */ -CGLM_INLINE -void -glm_rotate2d_make(mat3 m, float angle) { - float c, s; - - s = sinf(angle); - c = cosf(angle); - - m[0][0] = c; - m[0][1] = s; - m[0][2] = 0; - - m[1][0] = -s; - m[1][1] = c; - m[1][2] = 0; - - m[2][0] = 0.0f; - m[2][1] = 0.0f; - m[2][2] = 1.0f; -} - -/*! - * @brief rotate existing 2d transform matrix around Z axis by angle - * and store result in same matrix - * - * @param[in, out] m affine transform - * @param[in] angle angle (radians) - */ -CGLM_INLINE -void -glm_rotate2d(mat3 m, float angle) { - float m00 = m[0][0], m10 = m[1][0], - m01 = m[0][1], m11 = m[1][1], - m02 = m[0][2], m12 = m[1][2]; - float c, s; - - s = sinf(angle); - c = cosf(angle); - - m[0][0] = m00 * c + m10 * s; - m[0][1] = m01 * c + m11 * s; - m[0][2] = m02 * c + m12 * s; - - m[1][0] = m00 * -s + m10 * c; - m[1][1] = m01 * -s + m11 * c; - m[1][2] = m02 * -s + m12 * c; -} - -/*! - * @brief rotate existing 2d transform matrix around Z axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_rotate2d_to(mat3 m, float angle, mat3 dest) { - float m00 = m[0][0], m10 = m[1][0], - m01 = m[0][1], m11 = m[1][1], - m02 = m[0][2], m12 = m[1][2]; - float c, s; - - s = sinf(angle); - c = cosf(angle); - - dest[0][0] = m00 * c + m10 * s; - dest[0][1] = m01 * c + m11 * s; - dest[0][2] = m02 * c + m12 * s; - - dest[1][0] = m00 * -s + m10 * c; - dest[1][1] = m01 * -s + m11 * c; - dest[1][2] = m02 * -s + m12 * c; - - dest[2][0] = m[2][0]; - dest[2][1] = m[2][1]; - dest[2][2] = m[2][2]; -} - -#endif /* cglm_affine2d_h */ diff --git a/external/cglm/applesimd.h b/external/cglm/applesimd.h deleted file mode 100644 index 479ada6..0000000 --- a/external/cglm/applesimd.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_applesimd_h -#define cglm_applesimd_h -#if defined(__APPLE__) \ - && defined(SIMD_COMPILER_HAS_REQUIRED_FEATURES) \ - && defined(SIMD_BASE) \ - && defined(SIMD_TYPES) \ - && defined(SIMD_VECTOR_TYPES) - -#include "common.h" -#include "struct.h" - -/*! - * @brief converts mat4 to Apple's simd type simd_float4x4 - * @return simd_float4x4 - */ -CGLM_INLINE -simd_float4x4 -glm_mat4_applesimd(mat4 m) { - simd_float4x4 t; - - t.columns[0][0] = m[0][0]; - t.columns[0][1] = m[0][1]; - t.columns[0][2] = m[0][2]; - t.columns[0][3] = m[0][3]; - - t.columns[1][0] = m[1][0]; - t.columns[1][1] = m[1][1]; - t.columns[1][2] = m[1][2]; - t.columns[1][3] = m[1][3]; - - t.columns[2][0] = m[2][0]; - t.columns[2][1] = m[2][1]; - t.columns[2][2] = m[2][2]; - t.columns[2][3] = m[2][3]; - - t.columns[3][0] = m[3][0]; - t.columns[3][1] = m[3][1]; - t.columns[3][2] = m[3][2]; - t.columns[3][3] = m[3][3]; - - return t; -} - -/*! -* @brief converts mat3 to Apple's simd type simd_float3x3 -* @return simd_float3x3 -*/ -CGLM_INLINE -simd_float3x3 -glm_mat3_applesimd(mat3 m) { - simd_float3x3 t; - - t.columns[0][0] = m[0][0]; - t.columns[0][1] = m[0][1]; - t.columns[0][2] = m[0][2]; - - t.columns[1][0] = m[1][0]; - t.columns[1][1] = m[1][1]; - t.columns[1][2] = m[1][2]; - - t.columns[2][0] = m[2][0]; - t.columns[2][1] = m[2][1]; - t.columns[2][2] = m[2][2]; - - return t; -} - -/*! -* @brief converts vec4 to Apple's simd type simd_float4 -* @return simd_float4 -*/ -CGLM_INLINE -simd_float4 -glm_vec4_applesimd(vec4 v) { - return (simd_float4){v[0], v[1], v[2], v[3]}; -} - -/*! -* @brief converts vec3 to Apple's simd type simd_float3 -* @return simd_float3 -*/ -CGLM_INLINE -simd_float3 -glm_vec3_applesimd(vec3 v) { - return (simd_float3){v[0], v[1], v[2]}; -} - -/*! - * @brief generic function to convert cglm types to Apple's simd types - * - * Example usage: - * simd_float4x4 m = applesimd(mat4_value); - * simd_float3 v = applesimd(vec3_value); - * - * @param x cglm type (mat4, mat3, vec4, vec3) - * @return corresponding Apple simd type - */ -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -# define applesimd(x) _Generic((x), \ - mat4: glm_mat4_applesimd, \ - mat3: glm_mat3_applesimd, \ - vec4: glm_vec4_applesimd, \ - vec3: glm_vec3_applesimd \ - )((x)) -#endif - -#ifdef cglm_types_struct_h -CGLM_INLINE simd_float4x4 glms_mat4_(applesimd)(mat4s m) { return glm_mat4_applesimd(m.raw); } -CGLM_INLINE simd_float3x3 glms_mat3_(applesimd)(mat3s m) { return glm_mat3_applesimd(m.raw); } -CGLM_INLINE simd_float4 glms_vec4_(applesimd)(vec4s v) { return glm_vec4_applesimd(v.raw); } -CGLM_INLINE simd_float3 glms_vec3_(applesimd)(vec3s v) { return glm_vec3_applesimd(v.raw); } - -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -# undef applesimd -# define applesimd(x) _Generic((x), \ - mat4: glm_mat4_applesimd, \ - mat3: glm_mat3_applesimd, \ - vec4: glm_vec4_applesimd, \ - vec3: glm_vec3_applesimd, \ - mat4s: glms_mat4_(applesimd), \ - mat3s: glms_mat3_(applesimd), \ - vec4s: glms_vec4_(applesimd), \ - vec3s: glms_vec3_(applesimd) \ - )((x)) -#endif -#endif - -#endif -#endif /* cglm_applesimd_h */ diff --git a/external/cglm/bezier.h b/external/cglm/bezier.h deleted file mode 100644 index a6e5f8a..0000000 --- a/external/cglm/bezier.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_bezier_h -#define cglm_bezier_h - -#include "common.h" - -#define GLM_BEZIER_MAT_INIT {{-1.0f, 3.0f, -3.0f, 1.0f}, \ - { 3.0f, -6.0f, 3.0f, 0.0f}, \ - {-3.0f, 3.0f, 0.0f, 0.0f}, \ - { 1.0f, 0.0f, 0.0f, 0.0f}} -#define GLM_HERMITE_MAT_INIT {{ 2.0f, -3.0f, 0.0f, 1.0f}, \ - {-2.0f, 3.0f, 0.0f, 0.0f}, \ - { 1.0f, -2.0f, 1.0f, 0.0f}, \ - { 1.0f, -1.0f, 0.0f, 0.0f}} -/* for C only */ -#define GLM_BEZIER_MAT ((mat4)GLM_BEZIER_MAT_INIT) -#define GLM_HERMITE_MAT ((mat4)GLM_HERMITE_MAT_INIT) - -#define CGLM_DECASTEL_EPS 1e-9f -#define CGLM_DECASTEL_MAX 1000 -#define CGLM_DECASTEL_SMALL 1e-20f - -/*! - * @brief cubic bezier interpolation - * - * Formula: - * B(s) = P0*(1-s)^3 + 3*C0*s*(1-s)^2 + 3*C1*s^2*(1-s) + P1*s^3 - * - * similar result using matrix: - * B(s) = glm_smc(t, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) - * - * glm_eq(glm_smc(...), glm_bezier(...)) should return TRUE - * - * @param[in] s parameter between 0 and 1 - * @param[in] p0 begin point - * @param[in] c0 control point 1 - * @param[in] c1 control point 2 - * @param[in] p1 end point - * - * @return B(s) - */ -CGLM_INLINE -float -glm_bezier(float s, float p0, float c0, float c1, float p1) { - float x, xx, ss, xs3, a; - - x = 1.0f - s; - xx = x * x; - ss = s * s; - xs3 = (s - ss) * 3.0f; - a = p0 * xx + c0 * xs3; - - return a + s * (c1 * xs3 + p1 * ss - a); -} - -/*! - * @brief cubic hermite interpolation - * - * Formula: - * H(s) = P0*(2*s^3 - 3*s^2 + 1) + T0*(s^3 - 2*s^2 + s) - * + P1*(-2*s^3 + 3*s^2) + T1*(s^3 - s^2) - * - * similar result using matrix: - * H(s) = glm_smc(t, GLM_HERMITE_MAT, (vec4){p0, p1, c0, c1}) - * - * glm_eq(glm_smc(...), glm_hermite(...)) should return TRUE - * - * @param[in] s parameter between 0 and 1 - * @param[in] p0 begin point - * @param[in] t0 tangent 1 - * @param[in] t1 tangent 2 - * @param[in] p1 end point - * - * @return H(s) - */ -CGLM_INLINE -float -glm_hermite(float s, float p0, float t0, float t1, float p1) { - float ss, d, a, b, c, e, f; - - ss = s * s; - a = ss + ss; - c = a + ss; - b = a * s; - d = s * ss; - f = d - ss; - e = b - c; - - return p0 * (e + 1.0f) + t0 * (f - ss + s) + t1 * f - p1 * e; -} - -/*! - * @brief iterative way to solve cubic equation - * - * @param[in] prm parameter between 0 and 1 - * @param[in] p0 begin point - * @param[in] c0 control point 1 - * @param[in] c1 control point 2 - * @param[in] p1 end point - * - * @return parameter to use in cubic equation - */ -CGLM_INLINE -float -glm_decasteljau(float prm, float p0, float c0, float c1, float p1) { - float u, v, a, b, c, d, e, f; - int i; - - if (prm - p0 < CGLM_DECASTEL_SMALL) - return 0.0f; - - if (p1 - prm < CGLM_DECASTEL_SMALL) - return 1.0f; - - u = 0.0f; - v = 1.0f; - - for (i = 0; i < CGLM_DECASTEL_MAX; i++) { - /* de Casteljau Subdivision */ - a = (p0 + c0) * 0.5f; - b = (c0 + c1) * 0.5f; - c = (c1 + p1) * 0.5f; - d = (a + b) * 0.5f; - e = (b + c) * 0.5f; - f = (d + e) * 0.5f; /* this one is on the curve! */ - - /* The curve point is close enough to our wanted t */ - if (fabsf(f - prm) < CGLM_DECASTEL_EPS) - return glm_clamp_zo((u + v) * 0.5f); - - /* dichotomy */ - if (f < prm) { - p0 = f; - c0 = e; - c1 = c; - u = (u + v) * 0.5f; - } else { - c0 = a; - c1 = d; - p1 = f; - v = (u + v) * 0.5f; - } - } - - return glm_clamp_zo((u + v) * 0.5f); -} - -#endif /* cglm_bezier_h */ diff --git a/external/cglm/box.h b/external/cglm/box.h deleted file mode 100644 index 8bba678..0000000 --- a/external/cglm/box.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_box_h -#define cglm_box_h - -#include "common.h" -#include "vec3.h" -#include "vec4.h" -#include "util.h" - -/*! - * @brief apply transform to Axis-Aligned Bounding Box - * - * @param[in] box bounding box - * @param[in] m transform matrix - * @param[out] dest transformed bounding box - */ -CGLM_INLINE -void -glm_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]) { - vec3 v[2], xa, xb, ya, yb, za, zb; - - glm_vec3_scale(m[0], box[0][0], xa); - glm_vec3_scale(m[0], box[1][0], xb); - - glm_vec3_scale(m[1], box[0][1], ya); - glm_vec3_scale(m[1], box[1][1], yb); - - glm_vec3_scale(m[2], box[0][2], za); - glm_vec3_scale(m[2], box[1][2], zb); - - /* translation + min(xa, xb) + min(ya, yb) + min(za, zb) */ - glm_vec3(m[3], v[0]); - glm_vec3_minadd(xa, xb, v[0]); - glm_vec3_minadd(ya, yb, v[0]); - glm_vec3_minadd(za, zb, v[0]); - - /* translation + max(xa, xb) + max(ya, yb) + max(za, zb) */ - glm_vec3(m[3], v[1]); - glm_vec3_maxadd(xa, xb, v[1]); - glm_vec3_maxadd(ya, yb, v[1]); - glm_vec3_maxadd(za, zb, v[1]); - - glm_vec3_copy(v[0], dest[0]); - glm_vec3_copy(v[1], dest[1]); -} - -/*! - * @brief merges two AABB bounding box and creates new one - * - * two box must be in same space, if one of box is in different space then - * you should consider to convert it's space by glm_box_space - * - * @param[in] box1 bounding box 1 - * @param[in] box2 bounding box 2 - * @param[out] dest merged bounding box - */ -CGLM_INLINE -void -glm_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]) { - dest[0][0] = glm_min(box1[0][0], box2[0][0]); - dest[0][1] = glm_min(box1[0][1], box2[0][1]); - dest[0][2] = glm_min(box1[0][2], box2[0][2]); - - dest[1][0] = glm_max(box1[1][0], box2[1][0]); - dest[1][1] = glm_max(box1[1][1], box2[1][1]); - dest[1][2] = glm_max(box1[1][2], box2[1][2]); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] box bounding box 1 - * @param[in] cropBox crop box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glm_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]) { - dest[0][0] = glm_max(box[0][0], cropBox[0][0]); - dest[0][1] = glm_max(box[0][1], cropBox[0][1]); - dest[0][2] = glm_max(box[0][2], cropBox[0][2]); - - dest[1][0] = glm_min(box[1][0], cropBox[1][0]); - dest[1][1] = glm_min(box[1][1], cropBox[1][1]); - dest[1][2] = glm_min(box[1][2], cropBox[1][2]); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] box bounding box - * @param[in] cropBox crop box - * @param[in] clampBox minimum box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glm_aabb_crop_until(vec3 box[2], - vec3 cropBox[2], - vec3 clampBox[2], - vec3 dest[2]) { - glm_aabb_crop(box, cropBox, dest); - glm_aabb_merge(clampBox, dest, dest); -} - -/*! - * @brief check if AABB intersects with frustum planes - * - * this could be useful for frustum culling using AABB. - * - * OPTIMIZATION HINT: - * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR - * then this method should run even faster because it would only use two - * planes if object is not inside the two planes - * fortunately cglm extracts planes as this order! just pass what you got! - * - * @param[in] box bounding box - * @param[in] planes frustum planes - */ -CGLM_INLINE -bool -glm_aabb_frustum(vec3 box[2], vec4 planes[6]) { - float *p, dp; - int i; - - for (i = 0; i < 6; i++) { - p = planes[i]; - dp = p[0] * box[p[0] > 0.0f][0] - + p[1] * box[p[1] > 0.0f][1] - + p[2] * box[p[2] > 0.0f][2]; - - if (dp < -p[3]) - return false; - } - - return true; -} - -/*! - * @brief invalidate AABB min and max values - * - * @param[in, out] box bounding box - */ -CGLM_INLINE -void -glm_aabb_invalidate(vec3 box[2]) { - glm_vec3_broadcast(FLT_MAX, box[0]); - glm_vec3_broadcast(-FLT_MAX, box[1]); -} - -/*! - * @brief check if AABB is valid or not - * - * @param[in] box bounding box - */ -CGLM_INLINE -bool -glm_aabb_isvalid(vec3 box[2]) { - return glm_vec3_max(box[0]) != FLT_MAX - && glm_vec3_min(box[1]) != -FLT_MAX; -} - -/*! - * @brief distance between of min and max - * - * @param[in] box bounding box - */ -CGLM_INLINE -float -glm_aabb_size(vec3 box[2]) { - return glm_vec3_distance(box[0], box[1]); -} - -/*! - * @brief radius of sphere which surrounds AABB - * - * @param[in] box bounding box - */ -CGLM_INLINE -float -glm_aabb_radius(vec3 box[2]) { - return glm_aabb_size(box) * 0.5f; -} - -/*! - * @brief computes center point of AABB - * - * @param[in] box bounding box - * @param[out] dest center of bounding box - */ -CGLM_INLINE -void -glm_aabb_center(vec3 box[2], vec3 dest) { - glm_vec3_center(box[0], box[1], dest); -} - -/*! - * @brief check if two AABB intersects - * - * @param[in] box bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glm_aabb_aabb(vec3 box[2], vec3 other[2]) { - return (box[0][0] <= other[1][0] && box[1][0] >= other[0][0]) - && (box[0][1] <= other[1][1] && box[1][1] >= other[0][1]) - && (box[0][2] <= other[1][2] && box[1][2] >= other[0][2]); -} - -/*! - * @brief check if AABB intersects with sphere - * - * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c - * Solid Box - Solid Sphere test. - * - * Sphere Representation in cglm: [center.x, center.y, center.z, radii] - * - * @param[in] box solid bounding box - * @param[in] s solid sphere - */ -CGLM_INLINE -bool -glm_aabb_sphere(vec3 box[2], vec4 s) { - float dmin; - int a, b, c; - - a = (s[0] < box[0][0]) + (s[0] > box[1][0]); - b = (s[1] < box[0][1]) + (s[1] > box[1][1]); - c = (s[2] < box[0][2]) + (s[2] > box[1][2]); - - dmin = glm_pow2((s[0] - box[!(a - 1)][0]) * (a != 0)) - + glm_pow2((s[1] - box[!(b - 1)][1]) * (b != 0)) - + glm_pow2((s[2] - box[!(c - 1)][2]) * (c != 0)); - - return dmin <= glm_pow2(s[3]); -} - -/*! - * @brief check if point is inside of AABB - * - * @param[in] box bounding box - * @param[in] point point - */ -CGLM_INLINE -bool -glm_aabb_point(vec3 box[2], vec3 point) { - return (point[0] >= box[0][0] && point[0] <= box[1][0]) - && (point[1] >= box[0][1] && point[1] <= box[1][1]) - && (point[2] >= box[0][2] && point[2] <= box[1][2]); -} - -/*! - * @brief check if AABB contains other AABB - * - * @param[in] box bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glm_aabb_contains(vec3 box[2], vec3 other[2]) { - return (box[0][0] <= other[0][0] && box[1][0] >= other[1][0]) - && (box[0][1] <= other[0][1] && box[1][1] >= other[1][1]) - && (box[0][2] <= other[0][2] && box[1][2] >= other[1][2]); -} - -#endif /* cglm_box_h */ diff --git a/external/cglm/call.h b/external/cglm/call.h deleted file mode 100644 index 165f502..0000000 --- a/external/cglm/call.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_call_h -#define cglm_call_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "cglm.h" -#include "call/vec2.h" -#include "call/vec3.h" -#include "call/vec4.h" -#include "call/ivec2.h" -#include "call/ivec3.h" -#include "call/ivec4.h" -#include "call/mat2.h" -#include "call/mat2x3.h" -#include "call/mat2x4.h" -#include "call/mat3.h" -#include "call/mat3x2.h" -#include "call/mat3x4.h" -#include "call/mat4.h" -#include "call/mat4x2.h" -#include "call/mat4x3.h" -#include "call/affine.h" -#include "call/cam.h" -#include "call/quat.h" -#include "call/euler.h" -#include "call/plane.h" -#include "call/noise.h" -#include "call/frustum.h" -#include "call/aabb2d.h" -#include "call/box.h" -#include "call/io.h" -#include "call/project.h" -#include "call/sphere.h" -#include "call/ease.h" -#include "call/curve.h" -#include "call/bezier.h" -#include "call/ray.h" -#include "call/affine2d.h" - -#ifdef __cplusplus -} -#endif -#endif /* cglm_call_h */ diff --git a/external/cglm/call/aabb2d.h b/external/cglm/call/aabb2d.h deleted file mode 100644 index e6f36a0..0000000 --- a/external/cglm/call/aabb2d.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_aabb2d_h -#define cglmc_aabb2d_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -/* DEPRECATED! use _diag */ -#define glmc_aabb2d_size(aabb) glmc_aabb2d_diag(aabb) - -CGLM_EXPORT -void -glmc_aabb2d_zero(vec2 aabb[2]); - -CGLM_EXPORT -void -glmc_aabb2d_copy(vec2 aabb[2], vec2 dest[2]); - -CGLM_EXPORT -void -glmc_aabb2d_transform(vec2 aabb[2], mat3 m, vec2 dest[2]); - -CGLM_EXPORT -void -glmc_aabb2d_merge(vec2 aabb1[2], vec2 aabb2[2], vec2 dest[2]); - -CGLM_EXPORT -void -glmc_aabb2d_crop(vec2 aabb[2], vec2 cropAabb[2], vec2 dest[2]); - -CGLM_EXPORT -void -glmc_aabb2d_crop_until(vec2 aabb[2], - vec2 cropAabb[2], - vec2 clampAabb[2], - vec2 dest[2]); - -CGLM_EXPORT -void -glmc_aabb2d_invalidate(vec2 aabb[2]); - -CGLM_EXPORT -bool -glmc_aabb2d_isvalid(vec2 aabb[2]); - -CGLM_EXPORT -float -glmc_aabb2d_diag(vec2 aabb[2]); - -CGLM_EXPORT -void -glmc_aabb2d_sizev(vec2 aabb[2], vec2 dest); - -CGLM_EXPORT -float -glmc_aabb2d_radius(vec2 aabb[2]); - -CGLM_EXPORT -void -glmc_aabb2d_center(vec2 aabb[2], vec2 dest); - -CGLM_EXPORT -bool -glmc_aabb2d_aabb(vec2 aabb[2], vec2 other[2]); - -CGLM_EXPORT -bool -glmc_aabb2d_point(vec2 aabb[2], vec2 point); - -CGLM_EXPORT -bool -glmc_aabb2d_contains(vec2 aabb[2], vec2 other[2]); - -CGLM_EXPORT -bool -glmc_aabb2d_circle(vec2 aabb[2], vec3 s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_aabb2d_h */ diff --git a/external/cglm/call/affine.h b/external/cglm/call/affine.h deleted file mode 100644 index 52b8501..0000000 --- a/external/cglm/call/affine.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_affine_h -#define cglmc_affine_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_translate_make(mat4 m, vec3 v); - -CGLM_EXPORT -void -glmc_translate_to(mat4 m, vec3 v, mat4 dest); - -CGLM_EXPORT -void -glmc_translate(mat4 m, vec3 v); - -CGLM_EXPORT -void -glmc_translate_x(mat4 m, float to); - -CGLM_EXPORT -void -glmc_translate_y(mat4 m, float to); - -CGLM_EXPORT -void -glmc_translate_z(mat4 m, float to); - -CGLM_EXPORT -void -glmc_scale_make(mat4 m, vec3 v); - -CGLM_EXPORT -void -glmc_scale_to(mat4 m, vec3 v, mat4 dest); - -CGLM_EXPORT -void -glmc_scale(mat4 m, vec3 v); - -CGLM_EXPORT -void -glmc_scale_uni(mat4 m, float s); - -CGLM_EXPORT -void -glmc_rotate_x(mat4 m, float rad, mat4 dest); - -CGLM_EXPORT -void -glmc_rotate_y(mat4 m, float rad, mat4 dest); - -CGLM_EXPORT -void -glmc_rotate_z(mat4 m, float rad, mat4 dest); - -CGLM_EXPORT -void -glmc_rotate_make(mat4 m, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_rotate(mat4 m, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_spin(mat4 m, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_decompose_scalev(mat4 m, vec3 s); - -CGLM_EXPORT -bool -glmc_uniscaled(mat4 m); - -CGLM_EXPORT -void -glmc_decompose_rs(mat4 m, mat4 r, vec3 s); - -CGLM_EXPORT -void -glmc_decompose(mat4 m, vec4 t, mat4 r, vec3 s); - -/* affine-post */ - -CGLM_EXPORT -void -glmc_translated(mat4 m, vec3 v); - -CGLM_EXPORT -void -glmc_translated_to(mat4 m, vec3 v, mat4 dest); - -CGLM_EXPORT -void -glmc_translated_x(mat4 m, float x); - -CGLM_EXPORT -void -glmc_translated_y(mat4 m, float y); - -CGLM_EXPORT -void -glmc_translated_z(mat4 m, float z); - -CGLM_EXPORT -void -glmc_rotated_x(mat4 m, float angle, mat4 dest); - -CGLM_EXPORT -void -glmc_rotated_y(mat4 m, float angle, mat4 dest); - -CGLM_EXPORT -void -glmc_rotated_z(mat4 m, float angle, mat4 dest); - -CGLM_EXPORT -void -glmc_rotated(mat4 m, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_rotated_at(mat4 m, vec3 pivot, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_spinned(mat4 m, float angle, vec3 axis); - -/* affine-mat */ - -CGLM_EXPORT -void -glmc_mul(mat4 m1, mat4 m2, mat4 dest); - -CGLM_EXPORT -void -glmc_mul_rot(mat4 m1, mat4 m2, mat4 dest); - -CGLM_EXPORT -void -glmc_inv_tr(mat4 mat); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_affine_h */ diff --git a/external/cglm/call/affine2d.h b/external/cglm/call/affine2d.h deleted file mode 100644 index e1b9462..0000000 --- a/external/cglm/call/affine2d.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_affine2d_h -#define cglmc_affine2d_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_translate2d_make(mat3 m, vec2 v); - -CGLM_EXPORT -void -glmc_translate2d_to(mat3 m, vec2 v, mat3 dest); - -CGLM_EXPORT -void -glmc_translate2d(mat3 m, vec2 v); - -CGLM_EXPORT -void -glmc_translate2d_x(mat3 m, float to); - -CGLM_EXPORT -void -glmc_translate2d_y(mat3 m, float to); - -CGLM_EXPORT -void -glmc_scale2d_to(mat3 m, vec2 v, mat3 dest); - -CGLM_EXPORT -void -glmc_scale2d_make(mat3 m, vec2 v); - -CGLM_EXPORT -void -glmc_scale2d(mat3 m, vec2 v); - -CGLM_EXPORT -void -glmc_scale2d_uni(mat3 m, float s); - -CGLM_EXPORT -void -glmc_rotate2d_make(mat3 m, float angle); - -CGLM_EXPORT -void -glmc_rotate2d(mat3 m, float angle); - -CGLM_EXPORT -void -glmc_rotate2d_to(mat3 m, float angle, mat3 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_affine2d_h */ diff --git a/external/cglm/call/bezier.h b/external/cglm/call/bezier.h deleted file mode 100644 index a6a0eb4..0000000 --- a/external/cglm/call/bezier.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_bezier_h -#define cglmc_bezier_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -float -glmc_bezier(float s, float p0, float c0, float c1, float p1); - -CGLM_EXPORT -float -glmc_hermite(float s, float p0, float t0, float t1, float p1); - -CGLM_EXPORT -float -glmc_decasteljau(float prm, float p0, float c0, float c1, float p1); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_bezier_h */ diff --git a/external/cglm/call/box.h b/external/cglm/call/box.h deleted file mode 100644 index 3617eed..0000000 --- a/external/cglm/call/box.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_box_h -#define cglmc_box_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_aabb_transform(vec3 box[2], mat4 m, vec3 dest[2]); - -CGLM_EXPORT -void -glmc_aabb_merge(vec3 box1[2], vec3 box2[2], vec3 dest[2]); - -CGLM_EXPORT -void -glmc_aabb_crop(vec3 box[2], vec3 cropBox[2], vec3 dest[2]); - -CGLM_EXPORT -void -glmc_aabb_crop_until(vec3 box[2], - vec3 cropBox[2], - vec3 clampBox[2], - vec3 dest[2]); - -CGLM_EXPORT -bool -glmc_aabb_frustum(vec3 box[2], vec4 planes[6]); - -CGLM_EXPORT -void -glmc_aabb_invalidate(vec3 box[2]); - -CGLM_EXPORT -bool -glmc_aabb_isvalid(vec3 box[2]); - -CGLM_EXPORT -float -glmc_aabb_size(vec3 box[2]); - -CGLM_EXPORT -float -glmc_aabb_radius(vec3 box[2]); - -CGLM_EXPORT -void -glmc_aabb_center(vec3 box[2], vec3 dest); - -CGLM_EXPORT -bool -glmc_aabb_aabb(vec3 box[2], vec3 other[2]); - -CGLM_EXPORT -bool -glmc_aabb_point(vec3 box[2], vec3 point); - -CGLM_EXPORT -bool -glmc_aabb_contains(vec3 box[2], vec3 other[2]); - -CGLM_EXPORT -bool -glmc_aabb_sphere(vec3 box[2], vec4 s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_box_h */ diff --git a/external/cglm/call/cam.h b/external/cglm/call/cam.h deleted file mode 100644 index d9567ec..0000000 --- a/external/cglm/call/cam.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_cam_h -#define cglmc_cam_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_frustum(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb(vec3 box[2], mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_p(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_s(float aspect, float size, mat4 dest); - -CGLM_EXPORT -void -glmc_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest); - -CGLM_EXPORT -void -glmc_persp_move_far(mat4 proj, float deltaFar); - -CGLM_EXPORT -void -glmc_perspective_default(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_perspective_resize(float aspect, mat4 proj); - -CGLM_EXPORT -void -glmc_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look(vec3 eye, vec3 dir, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_anyup(vec3 eye, vec3 dir, mat4 dest); - -CGLM_EXPORT -void -glmc_persp_decomp(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ, - float * __restrict top, - float * __restrict bottom, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decompv(mat4 proj, float dest[6]); - -CGLM_EXPORT -void -glmc_persp_decomp_x(mat4 proj, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decomp_y(mat4 proj, - float * __restrict top, - float * __restrict bottom); - -CGLM_EXPORT -void -glmc_persp_decomp_z(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_far(mat4 proj, float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_near(mat4 proj, float * __restrict nearZ); - -CGLM_EXPORT -float -glmc_persp_fovy(mat4 proj); - -CGLM_EXPORT -float -glmc_persp_aspect(mat4 proj); - -CGLM_EXPORT -void -glmc_persp_sizes(mat4 proj, float fovy, vec4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_cam_h */ diff --git a/external/cglm/call/clipspace/ortho_lh_no.h b/external/cglm/call/clipspace/ortho_lh_no.h deleted file mode 100644 index 3e26fa9..0000000 --- a/external/cglm/call/clipspace/ortho_lh_no.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ortho_lh_no_h -#define cglmc_ortho_lh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_ortho_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_lh_no(vec3 box[2], mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_lh_no(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_s_lh_no(float aspect, float size, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ortho_lh_no_h */ diff --git a/external/cglm/call/clipspace/ortho_lh_zo.h b/external/cglm/call/clipspace/ortho_lh_zo.h deleted file mode 100644 index dc4c610..0000000 --- a/external/cglm/call/clipspace/ortho_lh_zo.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ortho_lh_zo_h -#define cglmc_ortho_lh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_ortho_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_lh_zo(vec3 box[2], mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_lh_zo(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_s_lh_zo(float aspect, float size, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ortho_lh_zo_h */ diff --git a/external/cglm/call/clipspace/ortho_rh_no.h b/external/cglm/call/clipspace/ortho_rh_no.h deleted file mode 100644 index dbba497..0000000 --- a/external/cglm/call/clipspace/ortho_rh_no.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ortho_rh_no_h -#define cglmc_ortho_rh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_ortho_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_rh_no(vec3 box[2], mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_rh_no(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_s_rh_no(float aspect, float size, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ortho_rh_no_h */ diff --git a/external/cglm/call/clipspace/ortho_rh_zo.h b/external/cglm/call/clipspace/ortho_rh_zo.h deleted file mode 100644 index e79ae83..0000000 --- a/external/cglm/call/clipspace/ortho_rh_zo.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ortho_rh_zo_h -#define cglmc_ortho_rh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_ortho_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_rh_zo(vec3 box[2], mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_rh_zo(float aspect, mat4 dest); - -CGLM_EXPORT -void -glmc_ortho_default_s_rh_zo(float aspect, float size, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ortho_rh_zo_h */ diff --git a/external/cglm/call/clipspace/persp_lh_no.h b/external/cglm/call/clipspace/persp_lh_no.h deleted file mode 100644 index 4bdbcfe..0000000 --- a/external/cglm/call/clipspace/persp_lh_no.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_persp_lh_no_h -#define cglmc_persp_lh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_frustum_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_perspective_lh_no(float fovy, - float aspect, - float nearVal, - float farVal, - mat4 dest); - -CGLM_EXPORT -void -glmc_persp_move_far_lh_no(mat4 proj, float deltaFar); - -CGLM_EXPORT -void -glmc_persp_decomp_lh_no(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decompv_lh_no(mat4 proj, float dest[6]); - -CGLM_EXPORT -void -glmc_persp_decomp_x_lh_no(mat4 proj, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decomp_y_lh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom); - -CGLM_EXPORT -void -glmc_persp_decomp_z_lh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ); - -CGLM_EXPORT -void -glmc_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest); - -CGLM_EXPORT -float -glmc_persp_fovy_lh_no(mat4 proj); - -CGLM_EXPORT -float -glmc_persp_aspect_lh_no(mat4 proj); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_persp_lh_no_h */ diff --git a/external/cglm/call/clipspace/persp_lh_zo.h b/external/cglm/call/clipspace/persp_lh_zo.h deleted file mode 100644 index 53c2c1c..0000000 --- a/external/cglm/call/clipspace/persp_lh_zo.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_persp_lh_zo_h -#define cglmc_persp_lh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_frustum_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_perspective_lh_zo(float fovy, - float aspect, - float nearVal, - float farVal, - mat4 dest); - -CGLM_EXPORT -void -glmc_persp_move_far_lh_zo(mat4 proj, float deltaFar); - -CGLM_EXPORT -void -glmc_persp_decomp_lh_zo(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decompv_lh_zo(mat4 proj, float dest[6]); - -CGLM_EXPORT -void -glmc_persp_decomp_x_lh_zo(mat4 proj, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decomp_y_lh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom); - -CGLM_EXPORT -void -glmc_persp_decomp_z_lh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ); - -CGLM_EXPORT -void -glmc_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest); - -CGLM_EXPORT -float -glmc_persp_fovy_lh_zo(mat4 proj); - -CGLM_EXPORT -float -glmc_persp_aspect_lh_zo(mat4 proj); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_persp_lh_zo_h */ diff --git a/external/cglm/call/clipspace/persp_rh_no.h b/external/cglm/call/clipspace/persp_rh_no.h deleted file mode 100644 index 9c0d65d..0000000 --- a/external/cglm/call/clipspace/persp_rh_no.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_persp_rh_no_h -#define cglmc_persp_rh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_frustum_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_perspective_rh_no(float fovy, - float aspect, - float nearVal, - float farVal, - mat4 dest); - -CGLM_EXPORT -void -glmc_persp_move_far_rh_no(mat4 proj, float deltaFar); - -CGLM_EXPORT -void -glmc_persp_decomp_rh_no(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decompv_rh_no(mat4 proj, float dest[6]); - -CGLM_EXPORT -void -glmc_persp_decomp_x_rh_no(mat4 proj, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decomp_y_rh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom); - -CGLM_EXPORT -void -glmc_persp_decomp_z_rh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ); - -CGLM_EXPORT -void -glmc_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest); - -CGLM_EXPORT -float -glmc_persp_fovy_rh_no(mat4 proj); - -CGLM_EXPORT -float -glmc_persp_aspect_rh_no(mat4 proj); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_persp_rh_no_h */ diff --git a/external/cglm/call/clipspace/persp_rh_zo.h b/external/cglm/call/clipspace/persp_rh_zo.h deleted file mode 100644 index 718d4ad..0000000 --- a/external/cglm/call/clipspace/persp_rh_zo.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_persp_rh_zo_h -#define cglmc_persp_rh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_frustum_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest); - -CGLM_EXPORT -void -glmc_perspective_rh_zo(float fovy, - float aspect, - float nearVal, - float farVal, - mat4 dest); - -CGLM_EXPORT -void -glmc_persp_move_far_rh_zo(mat4 proj, float deltaFar); - -CGLM_EXPORT -void -glmc_persp_decomp_rh_zo(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decompv_rh_zo(mat4 proj, float dest[6]); - -CGLM_EXPORT -void -glmc_persp_decomp_x_rh_zo(mat4 proj, - float * __restrict left, - float * __restrict right); - -CGLM_EXPORT -void -glmc_persp_decomp_y_rh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom); - -CGLM_EXPORT -void -glmc_persp_decomp_z_rh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ); - -CGLM_EXPORT -void -glmc_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ); - -CGLM_EXPORT -void -glmc_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest); - -CGLM_EXPORT -float -glmc_persp_fovy_rh_zo(mat4 proj); - -CGLM_EXPORT -float -glmc_persp_aspect_rh_zo(mat4 proj); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_persp_rh_zo_h */ diff --git a/external/cglm/call/clipspace/project_no.h b/external/cglm/call/clipspace/project_no.h deleted file mode 100644 index 3cba860..0000000 --- a/external/cglm/call/clipspace/project_no.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_project_no_h -#define cglmc_project_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); - -CGLM_EXPORT -void -glmc_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest); - -CGLM_EXPORT -float -glmc_project_z_no(vec3 pos, mat4 m); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_project_no_h */ diff --git a/external/cglm/call/clipspace/project_zo.h b/external/cglm/call/clipspace/project_zo.h deleted file mode 100644 index d2a6c62..0000000 --- a/external/cglm/call/clipspace/project_zo.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_project_zo_h -#define cglmc_project_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); - -CGLM_EXPORT -void -glmc_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest); - -CGLM_EXPORT -float -glmc_project_z_zo(vec3 pos, mat4 m); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_project_zo_h */ diff --git a/external/cglm/call/clipspace/view_lh_no.h b/external/cglm/call/clipspace/view_lh_no.h deleted file mode 100644 index 3b58c84..0000000 --- a/external/cglm/call/clipspace/view_lh_no.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_view_lh_no_h -#define cglmc_view_lh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_view_lh_no_h */ diff --git a/external/cglm/call/clipspace/view_lh_zo.h b/external/cglm/call/clipspace/view_lh_zo.h deleted file mode 100644 index c877367..0000000 --- a/external/cglm/call/clipspace/view_lh_zo.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_view_lh_zo_h -#define cglmc_view_lh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_view_lh_zo_h */ diff --git a/external/cglm/call/clipspace/view_rh_no.h b/external/cglm/call/clipspace/view_rh_no.h deleted file mode 100644 index 6303dbf..0000000 --- a/external/cglm/call/clipspace/view_rh_no.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_view_rh_no_h -#define cglmc_view_rh_no_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_view_rh_no_h */ diff --git a/external/cglm/call/clipspace/view_rh_zo.h b/external/cglm/call/clipspace/view_rh_zo.h deleted file mode 100644 index 00b8707..0000000 --- a/external/cglm/call/clipspace/view_rh_zo.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_view_rh_zo_h -#define cglmc_view_rh_zo_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../../cglm.h" - -CGLM_EXPORT -void -glmc_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest); - -CGLM_EXPORT -void -glmc_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_view_rh_zo_h */ diff --git a/external/cglm/call/curve.h b/external/cglm/call/curve.h deleted file mode 100644 index 061fdb9..0000000 --- a/external/cglm/call/curve.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_curve_h -#define cglmc_curve_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -float -glmc_smc(float s, mat4 m, vec4 c); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_curve_h */ diff --git a/external/cglm/call/ease.h b/external/cglm/call/ease.h deleted file mode 100644 index 87e39ca..0000000 --- a/external/cglm/call/ease.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ease_h -#define cglmc_ease_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -float -glmc_ease_linear(float t); - -CGLM_EXPORT -float -glmc_ease_sine_in(float t); - -CGLM_EXPORT -float -glmc_ease_sine_out(float t); - -CGLM_EXPORT -float -glmc_ease_sine_inout(float t); - -CGLM_EXPORT -float -glmc_ease_quad_in(float t); - -CGLM_EXPORT -float -glmc_ease_quad_out(float t); - -CGLM_EXPORT -float -glmc_ease_quad_inout(float t); - -CGLM_EXPORT -float -glmc_ease_cubic_in(float t); - -CGLM_EXPORT -float -glmc_ease_cubic_out(float t); - -CGLM_EXPORT -float -glmc_ease_cubic_inout(float t); - -CGLM_EXPORT -float -glmc_ease_quart_in(float t); - -CGLM_EXPORT -float -glmc_ease_quart_out(float t); - -CGLM_EXPORT -float -glmc_ease_quart_inout(float t); - -CGLM_EXPORT -float -glmc_ease_quint_in(float t); - -CGLM_EXPORT -float -glmc_ease_quint_out(float t); - -CGLM_EXPORT -float -glmc_ease_quint_inout(float t); - -CGLM_EXPORT -float -glmc_ease_exp_in(float t); - -CGLM_EXPORT -float -glmc_ease_exp_out(float t); - -CGLM_EXPORT -float -glmc_ease_exp_inout(float t); - -CGLM_EXPORT -float -glmc_ease_circ_in(float t); - -CGLM_EXPORT -float -glmc_ease_circ_out(float t); - -CGLM_EXPORT -float -glmc_ease_circ_inout(float t); - -CGLM_EXPORT -float -glmc_ease_back_in(float t); - -CGLM_EXPORT -float -glmc_ease_back_out(float t); - -CGLM_EXPORT -float -glmc_ease_back_inout(float t); - -CGLM_EXPORT -float -glmc_ease_elast_in(float t); - -CGLM_EXPORT -float -glmc_ease_elast_out(float t); - -CGLM_EXPORT -float -glmc_ease_elast_inout(float t); - -CGLM_EXPORT -float -glmc_ease_bounce_out(float t); - -CGLM_EXPORT -float -glmc_ease_bounce_in(float t); - -CGLM_EXPORT -float -glmc_ease_bounce_inout(float t); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ease_h */ diff --git a/external/cglm/call/euler.h b/external/cglm/call/euler.h deleted file mode 100644 index 182bcbb..0000000 --- a/external/cglm/call/euler.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_euler_h -#define cglmc_euler_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_euler_angles(mat4 m, vec3 dest); - -CGLM_EXPORT -void -glmc_euler(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_xyz(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_zyx(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_zxy(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_xzy(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_yzx(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_yxz(vec3 angles, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_by_order(vec3 angles, glm_euler_seq axis, mat4 dest); - -CGLM_EXPORT -void -glmc_euler_xyz_quat(vec3 angles, versor dest); - -CGLM_EXPORT -void -glmc_euler_xzy_quat(vec3 angles, versor dest); - -CGLM_EXPORT -void -glmc_euler_yxz_quat(vec3 angles, versor dest); - -CGLM_EXPORT -void -glmc_euler_yzx_quat(vec3 angles, versor dest); - -CGLM_EXPORT -void -glmc_euler_zxy_quat(vec3 angles, versor dest); - -CGLM_EXPORT -void -glmc_euler_zyx_quat(vec3 angles, versor dest); - - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_euler_h */ diff --git a/external/cglm/call/frustum.h b/external/cglm/call/frustum.h deleted file mode 100644 index 6b4facb..0000000 --- a/external/cglm/call/frustum.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_frustum_h -#define cglmc_frustum_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_frustum_planes(mat4 m, vec4 dest[6]); - -CGLM_EXPORT -void -glmc_frustum_corners(mat4 invMat, vec4 dest[8]); - -CGLM_EXPORT -void -glmc_frustum_center(vec4 corners[8], vec4 dest); - -CGLM_EXPORT -void -glmc_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]); - -CGLM_EXPORT -void -glmc_frustum_corners_at(vec4 corners[8], - float splitDist, - float farDist, - vec4 planeCorners[4]); -#ifdef __cplusplus -} -#endif -#endif /* cglmc_frustum_h */ diff --git a/external/cglm/call/io.h b/external/cglm/call/io.h deleted file mode 100644 index 19ea06f..0000000 --- a/external/cglm/call/io.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_io_h -#define cglmc_io_h - -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat4_print(mat4 matrix, - FILE * __restrict ostream); - -CGLM_EXPORT -void -glmc_mat3_print(mat3 matrix, - FILE * __restrict ostream); - -CGLM_EXPORT -void -glmc_vec4_print(vec4 vec, - FILE * __restrict ostream); - -CGLM_EXPORT -void -glmc_vec3_print(vec3 vec, - FILE * __restrict ostream); - -CGLM_EXPORT -void -glmc_versor_print(versor vec, - FILE * __restrict ostream); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_io_h */ diff --git a/external/cglm/call/ivec2.h b/external/cglm/call/ivec2.h deleted file mode 100644 index 82f70eb..0000000 --- a/external/cglm/call/ivec2.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ivec2_h -#define cglmc_ivec2_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_ivec2(int * __restrict v, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_copy(ivec2 a, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_zero(ivec2 v); - -CGLM_EXPORT -void -glmc_ivec2_one(ivec2 v); - -CGLM_EXPORT -int -glmc_ivec2_dot(ivec2 a, ivec2 b); - -CGLM_EXPORT -int -glmc_ivec2_cross(ivec2 a, ivec2 b); - -CGLM_EXPORT -void -glmc_ivec2_add(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_adds(ivec2 v, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_subs(ivec2 v, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_scale(ivec2 v, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_div(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_divs(ivec2 v, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_addadds(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_subadds(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_muladds(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_subsubs(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_addsubs(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_mulsubs(ivec2 a, int s, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -int -glmc_ivec2_distance2(ivec2 a, ivec2 b); - -CGLM_EXPORT -float -glmc_ivec2_distance(ivec2 a, ivec2 b); - -CGLM_EXPORT -void -glmc_ivec2_fill(ivec2 v, int val); - -CGLM_EXPORT -bool -glmc_ivec2_eq(ivec2 v, int val); - -CGLM_EXPORT -bool -glmc_ivec2_eqv(ivec2 a, ivec2 b); - -CGLM_EXPORT -void -glmc_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest); - -CGLM_EXPORT -void -glmc_ivec2_clamp(ivec2 v, int minVal, int maxVal); - -CGLM_EXPORT -void -glmc_ivec2_abs(ivec2 v, ivec2 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ivec2_h */ diff --git a/external/cglm/call/ivec3.h b/external/cglm/call/ivec3.h deleted file mode 100644 index a6cec53..0000000 --- a/external/cglm/call/ivec3.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c);, Recep Aslantas. - * - * MIT License (MIT);, http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ivec3_h -#define cglmc_ivec3_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_ivec3(ivec4 v4, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_copy(ivec3 a, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_zero(ivec3 v); - -CGLM_EXPORT -void -glmc_ivec3_one(ivec3 v); - -CGLM_EXPORT -int -glmc_ivec3_dot(ivec3 a, ivec3 b); - -CGLM_EXPORT -int -glmc_ivec3_norm2(ivec3 v); - -CGLM_EXPORT -int -glmc_ivec3_norm(ivec3 v); - -CGLM_EXPORT -void -glmc_ivec3_add(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_adds(ivec3 v, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_subs(ivec3 v, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_scale(ivec3 v, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_div(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_divs(ivec3 v, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_addadds(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_subadds(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_muladds(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_subsubs(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_addsubs(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_mulsubs(ivec3 a, int s, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -int -glmc_ivec3_distance2(ivec3 a, ivec3 b); - -CGLM_EXPORT -float -glmc_ivec3_distance(ivec3 a, ivec3 b); - -CGLM_EXPORT -void -glmc_ivec3_fill(ivec3 v, int val); - -CGLM_EXPORT -bool -glmc_ivec3_eq(ivec3 v, int val); - -CGLM_EXPORT -bool -glmc_ivec3_eqv(ivec3 a, ivec3 b); - -CGLM_EXPORT -void -glmc_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest); - -CGLM_EXPORT -void -glmc_ivec3_clamp(ivec3 v, int minVal, int maxVal); - -CGLM_EXPORT -void -glmc_ivec3_abs(ivec3 v, ivec3 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ivec3_h */ diff --git a/external/cglm/call/ivec4.h b/external/cglm/call/ivec4.h deleted file mode 100644 index 0e6d721..0000000 --- a/external/cglm/call/ivec4.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ivec4_h -#define cglmc_ivec4_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_ivec4(ivec3 v3, int last, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_copy(ivec4 a, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_zero(ivec4 v); - -CGLM_EXPORT -void -glmc_ivec4_one(ivec4 v); - -CGLM_EXPORT -void -glmc_ivec4_add(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_adds(ivec4 v, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_subs(ivec4 v, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_scale(ivec4 v, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_addadds(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_subadds(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_muladds(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_subsubs(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_addsubs(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_mulsubs(ivec4 a, int s, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -int -glmc_ivec4_distance2(ivec4 a, ivec4 b); - -CGLM_EXPORT -float -glmc_ivec4_distance(ivec4 a, ivec4 b); - -CGLM_EXPORT -void -glmc_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest); - -CGLM_EXPORT -void -glmc_ivec4_clamp(ivec4 v, int minVal, int maxVal); - -CGLM_EXPORT -void -glmc_ivec4_abs(ivec4 v, ivec4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ivec4_h */ diff --git a/external/cglm/call/mat2.h b/external/cglm/call/mat2.h deleted file mode 100644 index c268938..0000000 --- a/external/cglm/call/mat2.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat2_h -#define cglmc_mat2_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat2_make(const float * __restrict src, mat2 dest); - -CGLM_EXPORT -void -glmc_mat2_copy(mat2 mat, mat2 dest); - -CGLM_EXPORT -void -glmc_mat2_identity(mat2 m); - -CGLM_EXPORT -void -glmc_mat2_identity_array(mat2 * __restrict mats, size_t count); - -CGLM_EXPORT -void -glmc_mat2_zero(mat2 m); - -CGLM_EXPORT -void -glmc_mat2_mul(mat2 m1, mat2 m2, mat2 dest); - -CGLM_EXPORT -void -glmc_mat2_mulv(mat2 m, vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_mat2_transpose_to(mat2 mat, mat2 dest); - -CGLM_EXPORT -void -glmc_mat2_transpose(mat2 m); - -CGLM_EXPORT -void -glmc_mat2_scale(mat2 m, float s); - -CGLM_EXPORT -void -glmc_mat2_inv(mat2 mat, mat2 dest); - -CGLM_EXPORT -void -glmc_mat2_swap_col(mat2 mat, int col1, int col2); - -CGLM_EXPORT -void -glmc_mat2_swap_row(mat2 mat, int row1, int row2); - -CGLM_EXPORT -float -glmc_mat2_trace(mat2 m); - -CGLM_EXPORT -float -glmc_mat2_det(mat2 m); - -CGLM_EXPORT -float -glmc_mat2_rmc(vec2 r, mat2 m, vec2 c); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat2_h */ diff --git a/external/cglm/call/mat2x3.h b/external/cglm/call/mat2x3.h deleted file mode 100644 index 215d9a4..0000000 --- a/external/cglm/call/mat2x3.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat2x3_h -#define cglmc_mat2x3_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat2x3_copy(mat2x3 src, mat2x3 dest); - -CGLM_EXPORT -void -glmc_mat2x3_zero(mat2x3 m); - -CGLM_EXPORT -void -glmc_mat2x3_make(const float * __restrict src, mat2x3 dest); - -CGLM_EXPORT -void -glmc_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest); - -CGLM_EXPORT -void -glmc_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest); - -CGLM_EXPORT -void -glmc_mat2x3_transpose(mat2x3 src, mat3x2 dest); - -CGLM_EXPORT -void -glmc_mat2x3_scale(mat2x3 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat2x3_h */ diff --git a/external/cglm/call/mat2x4.h b/external/cglm/call/mat2x4.h deleted file mode 100644 index e2775a4..0000000 --- a/external/cglm/call/mat2x4.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat2x4_h -#define cglmc_mat2x4_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat2x4_copy(mat2x4 src, mat2x4 dest); - -CGLM_EXPORT -void -glmc_mat2x4_zero(mat2x4 m); - -CGLM_EXPORT -void -glmc_mat2x4_make(const float * __restrict src, mat2x4 dest); - -CGLM_EXPORT -void -glmc_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest); - -CGLM_EXPORT -void -glmc_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest); - -CGLM_EXPORT -void -glmc_mat2x4_transpose(mat2x4 src, mat4x2 dest); - -CGLM_EXPORT -void -glmc_mat2x4_scale(mat2x4 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat2x4_h */ diff --git a/external/cglm/call/mat3.h b/external/cglm/call/mat3.h deleted file mode 100644 index 47820f9..0000000 --- a/external/cglm/call/mat3.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat3_h -#define cglmc_mat3_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glmc_mat3_dup(mat, dest) glmc_mat3_copy(mat, dest) - -CGLM_EXPORT -void -glmc_mat3_copy(mat3 mat, mat3 dest); - -CGLM_EXPORT -void -glmc_mat3_identity(mat3 mat); - -CGLM_EXPORT -void -glmc_mat3_zero(mat3 mat); - -CGLM_EXPORT -void -glmc_mat3_identity_array(mat3 * __restrict mat, size_t count); - -CGLM_EXPORT -void -glmc_mat3_mul(mat3 m1, mat3 m2, mat3 dest); - -CGLM_EXPORT -void -glmc_mat3_transpose_to(mat3 m, mat3 dest); - -CGLM_EXPORT -void -glmc_mat3_transpose(mat3 m); - -CGLM_EXPORT -void -glmc_mat3_mulv(mat3 m, vec3 v, vec3 dest); - -CGLM_EXPORT -float -glmc_mat3_trace(mat3 m); - -CGLM_EXPORT -void -glmc_mat3_quat(mat3 m, versor dest); - -CGLM_EXPORT -void -glmc_mat3_scale(mat3 m, float s); - -CGLM_EXPORT -float -glmc_mat3_det(mat3 mat); - -CGLM_EXPORT -void -glmc_mat3_inv(mat3 mat, mat3 dest); - -CGLM_EXPORT -void -glmc_mat3_swap_col(mat3 mat, int col1, int col2); - -CGLM_EXPORT -void -glmc_mat3_swap_row(mat3 mat, int row1, int row2); - -CGLM_EXPORT -float -glmc_mat3_rmc(vec3 r, mat3 m, vec3 c); - -CGLM_EXPORT -void -glmc_mat3_make(const float * __restrict src, mat3 dest); - -CGLM_EXPORT -void -glmc_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat3_h */ diff --git a/external/cglm/call/mat3x2.h b/external/cglm/call/mat3x2.h deleted file mode 100644 index 246a269..0000000 --- a/external/cglm/call/mat3x2.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat3x2_h -#define cglmc_mat3x2_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat3x2_copy(mat3x2 src, mat3x2 dest); - -CGLM_EXPORT -void -glmc_mat3x2_zero(mat3x2 m); - -CGLM_EXPORT -void -glmc_mat3x2_make(const float * __restrict src, mat3x2 dest); - -CGLM_EXPORT -void -glmc_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest); - -CGLM_EXPORT -void -glmc_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest); - -CGLM_EXPORT -void -glmc_mat3x2_transpose(mat3x2 src, mat2x3 dest); - -CGLM_EXPORT -void -glmc_mat3x2_scale(mat3x2 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat3x2_h */ diff --git a/external/cglm/call/mat3x4.h b/external/cglm/call/mat3x4.h deleted file mode 100644 index 5ead2f4..0000000 --- a/external/cglm/call/mat3x4.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat3x4_h -#define cglmc_mat3x4_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat3x4_copy(mat3x4 src, mat3x4 dest); - -CGLM_EXPORT -void -glmc_mat3x4_zero(mat3x4 m); - -CGLM_EXPORT -void -glmc_mat3x4_make(const float * __restrict src, mat3x4 dest); - -CGLM_EXPORT -void -glmc_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest); - -CGLM_EXPORT -void -glmc_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest); - -CGLM_EXPORT -void -glmc_mat3x4_transpose(mat3x4 src, mat4x3 dest); - -CGLM_EXPORT -void -glmc_mat3x4_scale(mat3x4 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat3x4_h */ diff --git a/external/cglm/call/mat4.h b/external/cglm/call/mat4.h deleted file mode 100644 index f8cd70a..0000000 --- a/external/cglm/call/mat4.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat_h -#define cglmc_mat_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glmc_mat4_udup(mat, dest) glmc_mat4_ucopy(mat, dest) -#define glmc_mat4_dup(mat, dest) glmc_mat4_copy(mat, dest) - -CGLM_EXPORT -void -glmc_mat4_ucopy(mat4 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_copy(mat4 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_identity(mat4 mat); - -CGLM_EXPORT -void -glmc_mat4_identity_array(mat4 * __restrict mat, size_t count); - -CGLM_EXPORT -void -glmc_mat4_zero(mat4 mat); - -CGLM_EXPORT -void -glmc_mat4_pick3(mat4 mat, mat3 dest); - -CGLM_EXPORT -void -glmc_mat4_pick3t(mat4 mat, mat3 dest); - -CGLM_EXPORT -void -glmc_mat4_ins3(mat3 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_mul(mat4 m1, mat4 m2, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_mulv(mat4 m, vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest); - -CGLM_EXPORT -float -glmc_mat4_trace(mat4 m); - -CGLM_EXPORT -float -glmc_mat4_trace3(mat4 m); - -CGLM_EXPORT -void -glmc_mat4_quat(mat4 m, versor dest); - -CGLM_EXPORT -void -glmc_mat4_transpose_to(mat4 m, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_transpose(mat4 m); - -CGLM_EXPORT -void -glmc_mat4_scale_p(mat4 m, float s); - -CGLM_EXPORT -void -glmc_mat4_scale(mat4 m, float s); - -CGLM_EXPORT -float -glmc_mat4_det(mat4 mat); - -CGLM_EXPORT -void -glmc_mat4_inv(mat4 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_inv_precise(mat4 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_inv_fast(mat4 mat, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_swap_col(mat4 mat, int col1, int col2); - -CGLM_EXPORT -void -glmc_mat4_swap_row(mat4 mat, int row1, int row2); - -CGLM_EXPORT -float -glmc_mat4_rmc(vec4 r, mat4 m, vec4 c); - -CGLM_EXPORT -void -glmc_mat4_make(const float * __restrict src, mat4 dest); - -CGLM_EXPORT -void -glmc_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat_h */ diff --git a/external/cglm/call/mat4x2.h b/external/cglm/call/mat4x2.h deleted file mode 100644 index 4711d2b..0000000 --- a/external/cglm/call/mat4x2.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat4x2_h -#define cglmc_mat4x2_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat4x2_copy(mat4x2 src, mat4x2 dest); - -CGLM_EXPORT -void -glmc_mat4x2_zero(mat4x2 m); - -CGLM_EXPORT -void -glmc_mat4x2_make(const float * __restrict src, mat4x2 dest); - -CGLM_EXPORT -void -glmc_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest); - -CGLM_EXPORT -void -glmc_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest); - -CGLM_EXPORT -void -glmc_mat4x2_transpose(mat4x2 src, mat2x4 dest); - -CGLM_EXPORT -void -glmc_mat4x2_scale(mat4x2 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat4x2_h */ diff --git a/external/cglm/call/mat4x3.h b/external/cglm/call/mat4x3.h deleted file mode 100644 index e06e102..0000000 --- a/external/cglm/call/mat4x3.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_mat4x3_h -#define cglmc_mat4x3_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_mat4x3_copy(mat4x3 src, mat4x3 dest); - -CGLM_EXPORT -void -glmc_mat4x3_zero(mat4x3 m); - -CGLM_EXPORT -void -glmc_mat4x3_make(const float * __restrict src, mat4x3 dest); - -CGLM_EXPORT -void -glmc_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest); - -CGLM_EXPORT -void -glmc_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest); - -CGLM_EXPORT -void -glmc_mat4x3_transpose(mat4x3 src, mat3x4 dest); - -CGLM_EXPORT -void -glmc_mat4x3_scale(mat4x3 m, float s); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_mat4x3_h */ diff --git a/external/cglm/call/noise.h b/external/cglm/call/noise.h deleted file mode 100644 index 6020c89..0000000 --- a/external/cglm/call/noise.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_noise_h -#define cglmc_noise_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -float -glmc_perlin_vec4(vec4 point); - -CGLM_EXPORT -float -glmc_perlin_vec3(vec3 point); - -CGLM_EXPORT -float -glmc_perlin_vec2(vec2 point); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_noise_h */ diff --git a/external/cglm/call/plane.h b/external/cglm/call/plane.h deleted file mode 100644 index f991121..0000000 --- a/external/cglm/call/plane.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_plane_h -#define cglmc_plane_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_plane_normalize(vec4 plane); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_plane_h */ diff --git a/external/cglm/call/project.h b/external/cglm/call/project.h deleted file mode 100644 index 8fa7172..0000000 --- a/external/cglm/call/project.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_project_h -#define cglmc_project_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest); - -CGLM_EXPORT -void -glmc_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest); - -CGLM_EXPORT -void -glmc_project(vec3 pos, mat4 m, vec4 vp, vec3 dest); - -CGLM_EXPORT -float -glmc_project_z(vec3 pos, mat4 m); - -CGLM_EXPORT -void -glmc_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_project_h */ diff --git a/external/cglm/call/quat.h b/external/cglm/call/quat.h deleted file mode 100644 index 4244d36..0000000 --- a/external/cglm/call/quat.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_quat_h -#define cglmc_quat_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_quat_identity(versor q); - -CGLM_EXPORT -void -glmc_quat_identity_array(versor * __restrict q, size_t count); - -CGLM_EXPORT -void -glmc_quat_init(versor q, float x, float y, float z, float w); - -CGLM_EXPORT -void -glmc_quat(versor q, float angle, float x, float y, float z); - -CGLM_EXPORT -void -glmc_quatv(versor q, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_quat_copy(versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_from_vecs(vec3 a, vec3 b, versor dest); - -CGLM_EXPORT -float -glmc_quat_norm(versor q); - -CGLM_EXPORT -void -glmc_quat_normalize_to(versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_normalize(versor q); - -CGLM_EXPORT -float -glmc_quat_dot(versor p, versor q); - -CGLM_EXPORT -void -glmc_quat_conjugate(versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_inv(versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_add(versor p, versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_sub(versor p, versor q, versor dest); - -CGLM_EXPORT -float -glmc_quat_real(versor q); - -CGLM_EXPORT -void -glmc_quat_imag(versor q, vec3 dest); - -CGLM_EXPORT -void -glmc_quat_imagn(versor q, vec3 dest); - -CGLM_EXPORT -float -glmc_quat_imaglen(versor q); - -CGLM_EXPORT -float -glmc_quat_angle(versor q); - -CGLM_EXPORT -void -glmc_quat_axis(versor q, vec3 dest); - -CGLM_EXPORT -void -glmc_quat_mul(versor p, versor q, versor dest); - -CGLM_EXPORT -void -glmc_quat_mat4(versor q, mat4 dest); - -CGLM_EXPORT -void -glmc_quat_mat4t(versor q, mat4 dest); - -CGLM_EXPORT -void -glmc_quat_mat3(versor q, mat3 dest); - -CGLM_EXPORT -void -glmc_quat_mat3t(versor q, mat3 dest); - -CGLM_EXPORT -void -glmc_quat_lerp(versor from, versor to, float t, versor dest); - -CGLM_EXPORT -void -glmc_quat_lerpc(versor from, versor to, float t, versor dest); - -CGLM_EXPORT -void -glmc_quat_nlerp(versor q, versor r, float t, versor dest); - -CGLM_EXPORT -void -glmc_quat_slerp(versor q, versor r, float t, versor dest); - -CGLM_EXPORT -void -glmc_quat_slerp_longest(versor q, versor r, float t, versor dest); - -CGLM_EXPORT -void -glmc_quat_look(vec3 eye, versor ori, mat4 dest); - -CGLM_EXPORT -void -glmc_quat_for(vec3 dir, vec3 up, versor dest); - -CGLM_EXPORT -void -glmc_quat_forp(vec3 from, vec3 to, vec3 up, versor dest); - -CGLM_EXPORT -void -glmc_quat_rotatev(versor from, vec3 to, vec3 dest); - -CGLM_EXPORT -void -glmc_quat_rotate(mat4 m, versor q, mat4 dest); - -CGLM_EXPORT -void -glmc_quat_rotate_at(mat4 model, versor q, vec3 pivot); - -CGLM_EXPORT -void -glmc_quat_rotate_atm(mat4 m, versor q, vec3 pivot); - -CGLM_EXPORT -void -glmc_quat_make(const float * __restrict src, versor dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_quat_h */ diff --git a/external/cglm/call/ray.h b/external/cglm/call/ray.h deleted file mode 100644 index e529fdf..0000000 --- a/external/cglm/call/ray.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_ray_h -#define cglmc_ray_h -#ifdef __cplusplus -extern "C" { -#endif -#include "../cglm.h" - -CGLM_EXPORT -bool -glmc_ray_triangle(vec3 origin, - vec3 direction, - vec3 v0, - vec3 v1, - vec3 v2, - float *d); - -CGLM_EXPORT -bool -glmc_ray_sphere(vec3 origin, - vec3 dir, - vec4 s, - float * __restrict t1, - float * __restrict t2); - -CGLM_EXPORT -void -glmc_ray_at(vec3 orig, vec3 dir, float t, vec3 point); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_ray_h */ diff --git a/external/cglm/call/sphere.h b/external/cglm/call/sphere.h deleted file mode 100644 index 9b96546..0000000 --- a/external/cglm/call/sphere.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_sphere_h -#define cglmc_sphere_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -float -glmc_sphere_radii(vec4 s); - -CGLM_EXPORT -void -glmc_sphere_transform(vec4 s, mat4 m, vec4 dest); - -CGLM_EXPORT -void -glmc_sphere_merge(vec4 s1, vec4 s2, vec4 dest); - -CGLM_EXPORT -bool -glmc_sphere_sphere(vec4 s1, vec4 s2); - -CGLM_EXPORT -bool -glmc_sphere_point(vec4 s, vec3 point); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_sphere_h */ diff --git a/external/cglm/call/vec2.h b/external/cglm/call/vec2.h deleted file mode 100644 index 0284a8c..0000000 --- a/external/cglm/call/vec2.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_vec2_h -#define cglmc_vec2_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -CGLM_EXPORT -void -glmc_vec2(float * __restrict v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_fill(vec2 v, float val); - -CGLM_EXPORT -bool -glmc_vec2_eq(vec2 v, float val); - -CGLM_EXPORT -bool -glmc_vec2_eqv(vec2 a, vec2 b); - -CGLM_EXPORT -void -glmc_vec2_copy(vec2 a, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_zero(vec2 v); - -CGLM_EXPORT -void -glmc_vec2_one(vec2 v); - -CGLM_EXPORT -float -glmc_vec2_dot(vec2 a, vec2 b); - -CGLM_EXPORT -float -glmc_vec2_cross(vec2 a, vec2 b); - -CGLM_EXPORT -float -glmc_vec2_norm2(vec2 v); - -CGLM_EXPORT -float -glmc_vec2_norm(vec2 v); - -CGLM_EXPORT -void -glmc_vec2_add(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_adds(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_sub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_subs(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_mul(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_scale(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_scale_as(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_div(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_divs(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_addadd(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_subadd(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_muladd(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_muladds(vec2 a, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_maxadd(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_minadd(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_subsub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_addsub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_mulsub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_mulsubs(vec2 a, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_maxsub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_minsub(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_negate_to(vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_negate(vec2 v); - -CGLM_EXPORT -void -glmc_vec2_normalize(vec2 v); - -CGLM_EXPORT -void -glmc_vec2_normalize_to(vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_rotate(vec2 v, float angle, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_center(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -float -glmc_vec2_distance2(vec2 a, vec2 b); - -CGLM_EXPORT -float -glmc_vec2_distance(vec2 a, vec2 b); - -CGLM_EXPORT -void -glmc_vec2_maxv(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_minv(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_clamp(vec2 v, float minval, float maxval); - -CGLM_EXPORT -void -glmc_vec2_abs(vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_fract(vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_floor(vec2 v, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_mods(vec2 v, float s, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_swizzle(vec2 v, int mask, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_step(vec2 edge, vec2 x, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_steps(float edge, vec2 x, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_stepr(vec2 edge, float x, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_complex_mul(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_complex_div(vec2 a, vec2 b, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_complex_conjugate(vec2 a, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_make(const float * __restrict src, vec2 dest); - -CGLM_EXPORT -void -glmc_vec2_reflect(vec2 v, vec2 n, vec2 dest); - -CGLM_EXPORT -bool -glmc_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_vec2_h */ diff --git a/external/cglm/call/vec3.h b/external/cglm/call/vec3.h deleted file mode 100644 index 640fac7..0000000 --- a/external/cglm/call/vec3.h +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_vec3_h -#define cglmc_vec3_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glmc_vec_dup(v, dest) glmc_vec3_copy(v, dest) -#define glmc_vec3_flipsign(v) glmc_vec3_negate(v) -#define glmc_vec3_flipsign_to(v, dest) glmc_vec3_negate_to(v, dest) -#define glmc_vec3_inv(v) glmc_vec3_negate(v) -#define glmc_vec3_inv_to(v, dest) glmc_vec3_negate_to(v, dest) -#define glmc_vec3_step_uni(edge, x, dest) glmc_vec3_steps(edge, x, dest); - -CGLM_EXPORT -void -glmc_vec3(vec4 v4, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_copy(vec3 a, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_zero(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_one(vec3 v); - -CGLM_EXPORT -float -glmc_vec3_dot(vec3 a, vec3 b); - -CGLM_EXPORT -void -glmc_vec3_cross(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_crossn(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -float -glmc_vec3_norm(vec3 v); - -CGLM_EXPORT -float -glmc_vec3_norm2(vec3 v); - -CGLM_EXPORT -float -glmc_vec3_norm_one(vec3 v); - -CGLM_EXPORT -float -glmc_vec3_norm_inf(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_normalize_to(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_normalize(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_add(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_adds(vec3 v, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_sub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_subs(vec3 v, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_mul(vec3 a, vec3 b, vec3 d); - -CGLM_EXPORT -void -glmc_vec3_scale(vec3 v, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_scale_as(vec3 v, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_div(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_divs(vec3 a, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_addadd(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_subadd(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_muladd(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_muladds(vec3 a, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_maxadd(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_minadd(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_subsub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_addsub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_mulsub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_mulsubs(vec3 a, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_maxsub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_minsub(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_negate(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_negate_to(vec3 v, vec3 dest); - -CGLM_EXPORT -float -glmc_vec3_angle(vec3 a, vec3 b); - -CGLM_EXPORT -void -glmc_vec3_rotate(vec3 v, float angle, vec3 axis); - -CGLM_EXPORT -void -glmc_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_proj(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_center(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -float -glmc_vec3_distance2(vec3 a, vec3 b); - -CGLM_EXPORT -float -glmc_vec3_distance(vec3 a, vec3 b); - -CGLM_EXPORT -void -glmc_vec3_maxv(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_minv(vec3 a, vec3 b, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_clamp(vec3 v, float minVal, float maxVal); - -CGLM_EXPORT -void -glmc_vec3_ortho(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); - -CGLM_INLINE -void -glmc_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { - glmc_vec3_lerp(from, to, t, dest); -} - -CGLM_INLINE -void -glmc_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { - glmc_vec3_lerpc(from, to, t, dest); -} - -CGLM_EXPORT -void -glmc_vec3_step(vec3 edge, vec3 x, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_swizzle(vec3 v, int mask, vec3 dest); - -/* ext */ - -CGLM_EXPORT -void -glmc_vec3_mulv(vec3 a, vec3 b, vec3 d); - -CGLM_EXPORT -void -glmc_vec3_broadcast(float val, vec3 d); - -CGLM_EXPORT -void -glmc_vec3_fill(vec3 v, float val); - -CGLM_EXPORT -bool -glmc_vec3_eq(vec3 v, float val); - -CGLM_EXPORT -bool -glmc_vec3_eq_eps(vec3 v, float val); - -CGLM_EXPORT -bool -glmc_vec3_eq_all(vec3 v); - -CGLM_EXPORT -bool -glmc_vec3_eqv(vec3 a, vec3 b); - -CGLM_EXPORT -bool -glmc_vec3_eqv_eps(vec3 a, vec3 b); - -CGLM_EXPORT -float -glmc_vec3_max(vec3 v); - -CGLM_EXPORT -float -glmc_vec3_min(vec3 v); - -CGLM_EXPORT -bool -glmc_vec3_isnan(vec3 v); - -CGLM_EXPORT -bool -glmc_vec3_isinf(vec3 v); - -CGLM_EXPORT -bool -glmc_vec3_isvalid(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_sign(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_abs(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_fract(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_floor(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_mods(vec3 v, float s, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_steps(float edge, vec3 x, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_stepr(vec3 edge, float x, vec3 dest); - -CGLM_EXPORT -float -glmc_vec3_hadd(vec3 v); - -CGLM_EXPORT -void -glmc_vec3_sqrt(vec3 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_make(const float * __restrict src, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest); - -CGLM_EXPORT -void -glmc_vec3_reflect(vec3 v, vec3 n, vec3 dest); - -CGLM_EXPORT -bool -glmc_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_vec3_h */ diff --git a/external/cglm/call/vec4.h b/external/cglm/call/vec4.h deleted file mode 100644 index 22eee24..0000000 --- a/external/cglm/call/vec4.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglmc_vec4_h -#define cglmc_vec4_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "../cglm.h" - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glmc_vec4_dup3(v, dest) glmc_vec4_copy3(v, dest) -#define glmc_vec4_dup(v, dest) glmc_vec4_copy(v, dest) -#define glmc_vec4_flipsign(v) glmc_vec4_negate(v) -#define glmc_vec4_flipsign_to(v, dest) glmc_vec4_negate_to(v, dest) -#define glmc_vec4_inv(v) glmc_vec4_negate(v) -#define glmc_vec4_inv_to(v, dest) glmc_vec4_negate_to(v, dest) -#define glmc_vec4_step_uni(edge, x, dest) glmc_vec4_steps(edge, x, dest) - -CGLM_EXPORT -void -glmc_vec4(vec3 v3, float last, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_zero(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_one(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_copy3(vec4 v, vec3 dest); - -CGLM_EXPORT -void -glmc_vec4_copy(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_ucopy(vec4 v, vec4 dest); - -CGLM_EXPORT -float -glmc_vec4_dot(vec4 a, vec4 b); - -CGLM_EXPORT -float -glmc_vec4_norm(vec4 v); - -CGLM_EXPORT -float -glmc_vec4_norm2(vec4 v); - -CGLM_EXPORT -float -glmc_vec4_norm_one(vec4 v); - -CGLM_EXPORT -float -glmc_vec4_norm_inf(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_normalize_to(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_normalize(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_add(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_adds(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_sub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_subs(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_mul(vec4 a, vec4 b, vec4 d); - -CGLM_EXPORT -void -glmc_vec4_scale(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_scale_as(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_div(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_divs(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_addadd(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_subadd(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_muladd(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_muladds(vec4 a, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_maxadd(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_minadd(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_subsub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_addsub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_mulsub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_mulsubs(vec4 a, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_maxsub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_minsub(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_negate(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_negate_to(vec4 v, vec4 dest); - -CGLM_EXPORT -float -glmc_vec4_distance(vec4 a, vec4 b); - -CGLM_EXPORT -float -glmc_vec4_distance2(vec4 a, vec4 b); - -CGLM_EXPORT -void -glmc_vec4_maxv(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_minv(vec4 a, vec4 b, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_clamp(vec4 v, float minVal, float maxVal); - -CGLM_EXPORT -void -glmc_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); - -CGLM_INLINE -void -glmc_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { - glmc_vec4_lerp(from, to, t, dest); -} - -CGLM_INLINE -void -glmc_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { - glmc_vec4_lerpc(from, to, t, dest); -} - -CGLM_EXPORT -void -glmc_vec4_step(vec4 edge, vec4 x, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_cubic(float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_swizzle(vec4 v, int mask, vec4 dest); - -/* ext */ - -CGLM_EXPORT -void -glmc_vec4_mulv(vec4 a, vec4 b, vec4 d); - -CGLM_EXPORT -void -glmc_vec4_broadcast(float val, vec4 d); - -CGLM_EXPORT -void -glmc_vec4_fill(vec4 v, float val); - -CGLM_EXPORT -bool -glmc_vec4_eq(vec4 v, float val); - -CGLM_EXPORT -bool -glmc_vec4_eq_eps(vec4 v, float val); - -CGLM_EXPORT -bool -glmc_vec4_eq_all(vec4 v); - -CGLM_EXPORT -bool -glmc_vec4_eqv(vec4 a, vec4 b); - -CGLM_EXPORT -bool -glmc_vec4_eqv_eps(vec4 a, vec4 b); - -CGLM_EXPORT -float -glmc_vec4_max(vec4 v); - -CGLM_EXPORT -float -glmc_vec4_min(vec4 v); - -CGLM_EXPORT -bool -glmc_vec4_isnan(vec4 v); - -CGLM_EXPORT -bool -glmc_vec4_isinf(vec4 v); - -CGLM_EXPORT -bool -glmc_vec4_isvalid(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_sign(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_abs(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_fract(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_floor(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_mods(vec4 v, float s, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_steps(float edge, vec4 x, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_stepr(vec4 edge, float x, vec4 dest); - -CGLM_EXPORT -float -glmc_vec4_hadd(vec4 v); - -CGLM_EXPORT -void -glmc_vec4_sqrt(vec4 v, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_make(const float * __restrict src, vec4 dest); - -CGLM_EXPORT -void -glmc_vec4_reflect(vec4 v, vec4 n, vec4 dest); - -CGLM_EXPORT -bool -glmc_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest); - -#ifdef __cplusplus -} -#endif -#endif /* cglmc_vec4_h */ diff --git a/external/cglm/cam.h b/external/cglm/cam.h deleted file mode 100644 index 816cb5e..0000000 --- a/external/cglm/cam.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_frustum(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb(vec3 box[2], mat4 dest) - CGLM_INLINE void glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) - CGLM_INLINE void glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) - CGLM_INLINE void glm_ortho_default(float aspect, mat4 dest) - CGLM_INLINE void glm_ortho_default_s(float aspect, float size, mat4 dest) - CGLM_INLINE void glm_perspective(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_default(float aspect, mat4 dest) - CGLM_INLINE void glm_perspective_resize(float aspect, mat4 proj) - CGLM_INLINE void glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) - CGLM_INLINE void glm_persp_decomp(mat4 proj, - float *nearZ, float *farZ, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glm_persp_decompv(mat4 proj, float dest[6]) - CGLM_INLINE void glm_persp_decomp_x(mat4 proj, float *left, float *right) - CGLM_INLINE void glm_persp_decomp_y(mat4 proj, float *top, float *bottom) - CGLM_INLINE void glm_persp_decomp_z(mat4 proj, float *nearv, float *farv) - CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) - CGLM_INLINE void glm_persp_decomp_near(mat4 proj, float *nearZ) - CGLM_INLINE float glm_persp_fovy(mat4 proj) - CGLM_INLINE float glm_persp_aspect(mat4 proj) - CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_cam_h -#define cglm_cam_h - -#include "common.h" -#include "plane.h" - -#include "clipspace/persp.h" - -#ifndef CGLM_CLIPSPACE_INCLUDE_ALL -# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/view_lh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/view_lh_no.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/view_rh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_rh_no.h" -# endif -#else -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_lh_zo.h" -# include "clipspace/view_lh_no.h" -# include "clipspace/view_rh_zo.h" -# include "clipspace/view_rh_no.h" -#endif - -/*! - * @brief set up perspective peprojection matrix - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_frustum(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest); -#endif -} - -/*! - * @brief set up orthographic projection matrix - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb(vec3 box[2], mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_aabb_lh_zo(box, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_aabb_lh_no(box, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_aabb_rh_zo(box, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_aabb_rh_no(box, dest); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_p(vec3 box[2], float padding, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_aabb_p_lh_zo(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_aabb_p_lh_no(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_aabb_p_rh_zo(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_aabb_p_rh_no(box, padding, dest); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_pz(vec3 box[2], float padding, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_aabb_pz_lh_zo(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_aabb_pz_lh_no(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_aabb_pz_rh_zo(box, padding, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_aabb_pz_rh_no(box, padding, dest); -#endif -} - -/*! - * @brief set up unit orthographic projection matrix - * - * @param[in] aspect aspect ration ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default(float aspect, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_default_lh_zo(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_default_lh_no(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_default_rh_zo(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_default_rh_no(aspect, dest); -#endif -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_s(float aspect, float size, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_ortho_default_s_lh_zo(aspect, size, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_ortho_default_s_lh_no(aspect, size, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_ortho_default_s_rh_zo(aspect, size, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_ortho_default_s_rh_no(aspect, size, dest); -#endif -} - -/*! - * @brief set up perspective projection matrix - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective(float fovy, float aspect, float nearZ, float farZ, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest); -#endif -} - -/*! - * @brief extend perspective projection matrix's far distance - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -void -glm_persp_move_far(mat4 proj, float deltaFar) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_move_far_lh_zo(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_move_far_lh_no(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_move_far_rh_zo(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_move_far_rh_no(proj, deltaFar); -#endif -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_default(float aspect, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_perspective_default_lh_zo(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_perspective_default_lh_no(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_perspective_default_rh_zo(aspect, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_perspective_default_rh_no(aspect, dest); -#endif -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in, out] proj perspective projection matrix - */ -CGLM_INLINE -void -glm_perspective_resize(float aspect, mat4 proj) { - if (proj[0][0] == 0.0f) - return; - - proj[0][0] = proj[1][1] / aspect; -} - -/*! - * @brief set up view matrix - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat(vec3 eye, vec3 center, vec3 up, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT - glm_lookat_lh(eye, center, up, dest); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT - glm_lookat_rh(eye, center, up, dest); -#endif -} - -/*! - * @brief set up view matrix - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look(vec3 eye, vec3 dir, vec3 up, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT - glm_look_lh(eye, dir, up, dest); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT - glm_look_rh(eye, dir, up, dest); -#endif -} - -/*! - * @brief set up view matrix - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup(vec3 eye, vec3 dir, mat4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_LH_BIT - glm_look_anyup_lh(eye, dir, dest); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_RH_BIT - glm_look_anyup_rh(eye, dir, dest); -#endif -} - -/*! - * @brief decomposes frustum values of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); -#endif -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glm_persp_decompv(mat4 proj, float dest[6]) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decompv_lh_zo(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decompv_lh_no(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decompv_rh_zo(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decompv_rh_no(proj, dest); -#endif -} - -/*! - * @brief decomposes left and right values of perspective projection. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_x(mat4 proj, - float * __restrict left, - float * __restrict right) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_x_lh_zo(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_x_lh_no(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_x_rh_zo(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_x_rh_no(proj, left, right); -#endif -} - -/*! - * @brief decomposes top and bottom values of perspective projection. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glm_persp_decomp_y(mat4 proj, - float * __restrict top, - float * __restrict bottom) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_y_lh_zo(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_y_lh_no(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_y_rh_zo(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_y_rh_no(proj, top, bottom); -#endif -} - -/*! - * @brief decomposes near and far values of perspective projection. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_z(mat4 proj, float * __restrict nearZ, float * __restrict farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_z_lh_zo(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_z_lh_no(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_z_rh_zo(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_z_rh_no(proj, nearZ, farZ); -#endif -} - -/*! - * @brief decomposes far value of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_far(mat4 proj, float * __restrict farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_far_lh_zo(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_far_lh_no(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_far_rh_zo(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_far_rh_no(proj, farZ); -#endif -} - -/*! - * @brief decomposes near value of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glm_persp_decomp_near(mat4 proj, float * __restrict nearZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_decomp_near_lh_zo(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_decomp_near_lh_no(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_decomp_near_rh_zo(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_decomp_near_rh_no(proj, nearZ); -#endif -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -void -glm_persp_sizes(mat4 proj, float fovy, vec4 dest) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glm_persp_sizes_lh_zo(proj, fovy, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glm_persp_sizes_lh_no(proj, fovy, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glm_persp_sizes_rh_zo(proj, fovy, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glm_persp_sizes_rh_no(proj, fovy, dest); -#endif -} - -#endif /* cglm_cam_h */ diff --git a/external/cglm/cglm.c b/external/cglm/cglm.c deleted file mode 100644 index 6fe88a7..0000000 --- a/external/cglm/cglm.c +++ /dev/null @@ -1,3 +0,0 @@ -#define CGLM_FORCE_DEPTH_ZERO_TO_ONE - -#include "cglm.h" diff --git a/external/cglm/cglm.h b/external/cglm/cglm.h deleted file mode 100644 index 3532830..0000000 --- a/external/cglm/cglm.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_h -#define cglm_h - -#include "common.h" -#include "vec2.h" -#include "vec3.h" -#include "vec4.h" -#include "ivec2.h" -#include "ivec3.h" -#include "ivec4.h" -#include "mat4.h" -#include "mat4x2.h" -#include "mat4x3.h" -#include "mat3.h" -#include "mat3x2.h" -#include "mat3x4.h" -#include "mat2.h" -#include "mat2x3.h" -#include "mat2x4.h" -#include "affine.h" -#include "cam.h" -#include "frustum.h" -#include "quat.h" -#include "euler.h" -#include "plane.h" -#include "noise.h" -#include "aabb2d.h" -#include "box.h" -#include "color.h" -#include "util.h" -#include "io.h" -#include "project.h" -#include "sphere.h" -#include "ease.h" -#include "curve.h" -#include "bezier.h" -#include "ray.h" -#include "affine2d.h" -#include "affine2d-post.h" - -#endif /* cglm_h */ diff --git a/external/cglm/clipspace/ortho_lh_no.h b/external/cglm/clipspace/ortho_lh_no.h deleted file mode 100644 index 76c7a94..0000000 --- a/external/cglm/clipspace/ortho_lh_no.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_ortho_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) - CGLM_INLINE void glm_ortho_aabb_p_lh_no(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_pz_lh_no(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_default_lh_no(float aspect, - mat4 dest) - CGLM_INLINE void glm_ortho_default_s_lh_no(float aspect, - float size, - mat4 dest) - */ - -#ifndef cglm_ortho_lh_no_h -#define cglm_ortho_lh_no_h - -#include "../common.h" -#include "../plane.h" -#include "../mat4.h" - -/*! - * @brief set up orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - - dest[0][0] = 2.0f * rl; - dest[1][1] = 2.0f * tb; - dest[2][2] =-2.0f * fn; - dest[3][0] =-(right + left) * rl; - dest[3][1] =-(top + bottom) * tb; - dest[3][2] = (farZ + nearZ) * fn; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_lh_no(vec3 box[2], mat4 dest) { - glm_ortho_lh_no(box[0][0], box[1][0], - box[0][1], box[1][1], - -box[1][2], -box[0][2], - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_p_lh_no(vec3 box[2], float padding, mat4 dest) { - glm_ortho_lh_no(box[0][0] - padding, box[1][0] + padding, - box[0][1] - padding, box[1][1] + padding, - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_pz_lh_no(vec3 box[2], float padding, mat4 dest) { - glm_ortho_lh_no(box[0][0], box[1][0], - box[0][1], box[1][1], - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up unit orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_lh_no(float aspect, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_lh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); - return; - } - - aspect = 1.0f / aspect; - - glm_ortho_lh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_s_lh_no(float aspect, float size, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_lh_no(-size * aspect, - size * aspect, - -size, - size, - -size - 100.0f, - size + 100.0f, - dest); - return; - } - - glm_ortho_lh_no(-size, - size, - -size / aspect, - size / aspect, - -size - 100.0f, - size + 100.0f, - dest); -} - -#endif /*cglm_ortho_lh_no_h*/ diff --git a/external/cglm/clipspace/ortho_lh_zo.h b/external/cglm/clipspace/ortho_lh_zo.h deleted file mode 100644 index e45530d..0000000 --- a/external/cglm/clipspace/ortho_lh_zo.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_ortho_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) - CGLM_INLINE void glm_ortho_aabb_p_lh_zo(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_pz_lh_zo(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_default_lh_zo(float aspect, - mat4 dest) - CGLM_INLINE void glm_ortho_default_s_lh_zo(float aspect, - float size, - mat4 dest) - */ - -#ifndef cglm_ortho_lh_zo_h -#define cglm_ortho_lh_zo_h - -#include "../common.h" -#include "../plane.h" -#include "../mat4.h" - -/*! - * @brief set up orthographic projection matrix with a left-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - - dest[0][0] = 2.0f * rl; - dest[1][1] = 2.0f * tb; - dest[2][2] =-fn; - dest[3][0] =-(right + left) * rl; - dest[3][1] =-(top + bottom) * tb; - dest[3][2] = nearZ * fn; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_lh_zo(vec3 box[2], mat4 dest) { - glm_ortho_lh_zo(box[0][0], box[1][0], - box[0][1], box[1][1], - -box[1][2], -box[0][2], - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_p_lh_zo(vec3 box[2], float padding, mat4 dest) { - glm_ortho_lh_zo(box[0][0] - padding, box[1][0] + padding, - box[0][1] - padding, box[1][1] + padding, - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_pz_lh_zo(vec3 box[2], float padding, mat4 dest) { - glm_ortho_lh_zo(box[0][0], box[1][0], - box[0][1], box[1][1], - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up unit orthographic projection matrix - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_lh_zo(float aspect, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_lh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); - return; - } - - aspect = 1.0f / aspect; - - glm_ortho_lh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_s_lh_zo(float aspect, float size, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_lh_zo(-size * aspect, - size * aspect, - -size, - size, - -size - 100.0f, - size + 100.0f, - dest); - return; - } - - glm_ortho_lh_zo(-size, - size, - -size / aspect, - size / aspect, - -size - 100.0f, - size + 100.0f, - dest); -} - -#endif /*cglm_ortho_lh_zo_h*/ diff --git a/external/cglm/clipspace/ortho_rh_no.h b/external/cglm/clipspace/ortho_rh_no.h deleted file mode 100644 index aa7a906..0000000 --- a/external/cglm/clipspace/ortho_rh_no.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_ortho_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) - CGLM_INLINE void glm_ortho_aabb_p_rh_no(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_pz_rh_no(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_default_rh_no(float aspect, - mat4 dest) - CGLM_INLINE void glm_ortho_default_s_rh_no(float aspect, - float size, - mat4 dest) - */ - -#ifndef cglm_ortho_rh_no_h -#define cglm_ortho_rh_no_h - -#include "../common.h" -#include "../plane.h" -#include "../mat4.h" - -/*! - * @brief set up orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - - dest[0][0] = 2.0f * rl; - dest[1][1] = 2.0f * tb; - dest[2][2] = 2.0f * fn; - dest[3][0] =-(right + left) * rl; - dest[3][1] =-(top + bottom) * tb; - dest[3][2] = (farZ + nearZ) * fn; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_rh_no(vec3 box[2], mat4 dest) { - glm_ortho_rh_no(box[0][0], box[1][0], - box[0][1], box[1][1], - -box[1][2], -box[0][2], - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_p_rh_no(vec3 box[2], float padding, mat4 dest) { - glm_ortho_rh_no(box[0][0] - padding, box[1][0] + padding, - box[0][1] - padding, box[1][1] + padding, - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_pz_rh_no(vec3 box[2], float padding, mat4 dest) { - glm_ortho_rh_no(box[0][0], box[1][0], - box[0][1], box[1][1], - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up unit orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_rh_no(float aspect, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_rh_no(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); - return; - } - - aspect = 1.0f / aspect; - - glm_ortho_rh_no(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_s_rh_no(float aspect, float size, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_rh_no(-size * aspect, - size * aspect, - -size, - size, - -size - 100.0f, - size + 100.0f, - dest); - return; - } - - glm_ortho_rh_no(-size, - size, - -size / aspect, - size / aspect, - -size - 100.0f, - size + 100.0f, - dest); -} - -#endif /*cglm_ortho_rh_no_h*/ diff --git a/external/cglm/clipspace/ortho_rh_zo.h b/external/cglm/clipspace/ortho_rh_zo.h deleted file mode 100644 index 7a0876c..0000000 --- a/external/cglm/clipspace/ortho_rh_zo.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_ortho_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) - CGLM_INLINE void glm_ortho_aabb_p_rh_zo(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_aabb_pz_rh_zo(vec3 box[2], - float padding, - mat4 dest) - CGLM_INLINE void glm_ortho_default_rh_zo(float aspect, - mat4 dest) - CGLM_INLINE void glm_ortho_default_s_rh_zo(float aspect, - float size, - mat4 dest) - */ - -#ifndef cglm_ortho_rh_zo_h -#define cglm_ortho_rh_zo_h - -#include "../common.h" -#include "../plane.h" -#include "../mat4.h" - -/*! - * @brief set up orthographic projection matrix with a right-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - - dest[0][0] = 2.0f * rl; - dest[1][1] = 2.0f * tb; - dest[2][2] = fn; - dest[3][0] =-(right + left) * rl; - dest[3][1] =-(top + bottom) * tb; - dest[3][2] = nearZ * fn; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a clip-space with depth - * values from zero to one. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_rh_zo(vec3 box[2], mat4 dest) { - glm_ortho_rh_zo(box[0][0], box[1][0], - box[0][1], box[1][1], - -box[1][2], -box[0][2], - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a clip-space with depth - * values from zero to one. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_p_rh_zo(vec3 box[2], float padding, mat4 dest) { - glm_ortho_rh_zo(box[0][0] - padding, box[1][0] + padding, - box[0][1] - padding, box[1][1] + padding, - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a clip-space with depth - * values from zero to one. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_aabb_pz_rh_zo(vec3 box[2], float padding, mat4 dest) { - glm_ortho_rh_zo(box[0][0], box[1][0], - box[0][1], box[1][1], - -(box[1][2] + padding), -(box[0][2] - padding), - dest); -} - -/*! - * @brief set up unit orthographic projection matrix with a right-hand - * coordinate system and a clip-space of [0, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_rh_zo(float aspect, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_rh_zo(-aspect, aspect, -1.0f, 1.0f, -100.0f, 100.0f, dest); - return; - } - - aspect = 1.0f / aspect; - - glm_ortho_rh_zo(-1.0f, 1.0f, -aspect, aspect, -100.0f, 100.0f, dest); -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a right-hand coordinate system and a clip-space with depth - * values from zero to one. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_ortho_default_s_rh_zo(float aspect, float size, mat4 dest) { - if (aspect >= 1.0f) { - glm_ortho_rh_zo(-size * aspect, - size * aspect, - -size, - size, - -size - 100.0f, - size + 100.0f, - dest); - return; - } - - glm_ortho_rh_zo(-size, - size, - -size / aspect, - size / aspect, - -size - 100.0f, - size + 100.0f, - dest); -} - -#endif /*cglm_ortho_rh_zo_h*/ diff --git a/external/cglm/clipspace/persp.h b/external/cglm/clipspace/persp.h deleted file mode 100644 index 15aa715..0000000 --- a/external/cglm/clipspace/persp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_persp_decomp_far(mat4 proj, float *farZ) - CGLM_INLINE float glm_persp_fovy(mat4 proj) - CGLM_INLINE float glm_persp_aspect(mat4 proj) - CGLM_INLINE void glm_persp_sizes(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_persp_h -#define cglm_persp_h - -#include "../common.h" -#include "../plane.h" -#include "../mat4.h" - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_fovy(mat4 proj) { - return 2.0f * atanf(1.0f / proj[1][1]); -} - -/*! - * @brief returns aspect ratio of perspective projection - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_aspect(mat4 proj) { - return proj[1][1] / proj[0][0]; -} - -#endif /* cglm_persp_h */ diff --git a/external/cglm/clipspace/persp_lh_no.h b/external/cglm/clipspace/persp_lh_no.h deleted file mode 100644 index d28923a..0000000 --- a/external/cglm/clipspace/persp_lh_no.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_frustum_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_lh_no(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_default_lh_no(float aspect, mat4 dest) - CGLM_INLINE void glm_perspective_resize_lh_no(float aspect, mat4 proj) - CGLM_INLINE void glm_persp_move_far_lh_no(mat4 proj, - float deltaFar) - CGLM_INLINE void glm_persp_decomp_lh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ, - float * __restrict top, - float * __restrict bottom, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decompv_lh_no(mat4 proj, - float dest[6]) - CGLM_INLINE void glm_persp_decomp_x_lh_no(mat4 proj, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decomp_y_lh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom) - CGLM_INLINE void glm_persp_decomp_z_lh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) - CGLM_INLINE void glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_persp_lh_no_h -#define cglm_persp_lh_no_h - -#include "../common.h" -#include "persp.h" - -/*! - * @brief set up perspective peprojection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_frustum_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn, nv; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - nv = 2.0f * nearZ; - - dest[0][0] = nv * rl; - dest[1][1] = nv * tb; - dest[2][0] = (right + left) * rl; - dest[2][1] = (top + bottom) * tb; - dest[2][2] =-(farZ + nearZ) * fn; - dest[2][3] = 1.0f; - dest[3][2] = farZ * nv * fn; -} - -/*! - * @brief set up perspective projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_lh_no(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) { - float f, fn; - - glm_mat4_zero(dest); - - f = 1.0f / tanf(fovy * 0.5f); - fn = 1.0f / (nearZ - farZ); - - dest[0][0] = f / aspect; - dest[1][1] = f; - dest[2][2] =-(nearZ + farZ) * fn; - dest[2][3] = 1.0f; - dest[3][2] = 2.0f * nearZ * farZ * fn; - -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_default_lh_no(float aspect, mat4 dest) { - glm_perspective_lh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * resized with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in, out] proj perspective projection matrix - */ -CGLM_INLINE -void -glm_perspective_resize_lh_no(float aspect, mat4 proj) { - if (proj[0][0] == 0.0f) - return; - - proj[0][0] = proj[1][1] / aspect; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -void -glm_persp_move_far_lh_no(mat4 proj, float deltaFar) { - float fn, farZ, nearZ, p22, p32; - - p22 = -proj[2][2]; - p32 = proj[3][2]; - - nearZ = p32 / (p22 - 1.0f); - farZ = p32 / (p22 + 1.0f) + deltaFar; - fn = 1.0f / (nearZ - farZ); - - proj[2][2] = -(farZ + nearZ) * fn; - proj[3][2] = 2.0f * nearZ * farZ * fn; -} - -/*! - * @brief decomposes frustum values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_lh_no(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - float m00, m11, m20, m21, m22, m32, n, f; - float n_m11, n_m00; - - m00 = proj[0][0]; - m11 = proj[1][1]; - m20 = proj[2][0]; - m21 = proj[2][1]; - m22 =-proj[2][2]; - m32 = proj[3][2]; - - n = m32 / (m22 - 1.0f); - f = m32 / (m22 + 1.0f); - - n_m11 = n / m11; - n_m00 = n / m00; - - *nearZ = n; - *farZ = f; - *bottom = n_m11 * (m21 - 1.0f); - *top = n_m11 * (m21 + 1.0f); - *left = n_m00 * (m20 - 1.0f); - *right = n_m00 * (m20 + 1.0f); -} - -/*! - * @brief decomposes frustum values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glm_persp_decompv_lh_no(mat4 proj, float dest[6]) { - glm_persp_decomp_lh_no(proj, &dest[0], &dest[1], &dest[2], - &dest[3], &dest[4], &dest[5]); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_x_lh_no(mat4 proj, - float * __restrict left, - float * __restrict right) { - float nearZ, m20, m00, m22; - - m00 = proj[0][0]; - m20 = proj[2][0]; - m22 =-proj[2][2]; - - nearZ = proj[3][2] / (m22 - 1.0f); - *left = nearZ * (m20 - 1.0f) / m00; - *right = nearZ * (m20 + 1.0f) / m00; -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glm_persp_decomp_y_lh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom) { - float nearZ, m21, m11, m22; - - m21 = proj[2][1]; - m11 = proj[1][1]; - m22 =-proj[2][2]; - - nearZ = proj[3][2] / (m22 - 1.0f); - *bottom = nearZ * (m21 - 1.0f) / m11; - *top = nearZ * (m21 + 1.0f) / m11; -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_z_lh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) { - float m32, m22; - - m32 = proj[3][2]; - m22 =-proj[2][2]; - - *nearZ = m32 / (m22 - 1.0f); - *farZ = m32 / (m22 + 1.0f); -} - -/*! - * @brief decomposes far value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_far_lh_no(mat4 proj, float * __restrict farZ) { - *farZ = proj[3][2] / (-proj[2][2] + 1.0f); -} - -/*! - * @brief decomposes near value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glm_persp_decomp_near_lh_no(mat4 proj, float * __restrict nearZ) { - *nearZ = proj[3][2] / (-proj[2][2] - 1.0f); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -void -glm_persp_sizes_lh_no(mat4 proj, float fovy, vec4 dest) { - float t, a, nearZ, farZ; - - t = 2.0f * tanf(fovy * 0.5f); - a = glm_persp_aspect(proj); - - glm_persp_decomp_z_lh_no(proj, &nearZ, &farZ); - - dest[1] = t * nearZ; - dest[3] = t * farZ; - dest[0] = a * dest[1]; - dest[2] = a * dest[3]; -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a left-hand coordinate system and a clip-space of [-1, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_fovy_lh_no(mat4 proj) { - return glm_persp_fovy(proj); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a left-hand coordinate system and a clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_aspect_lh_no(mat4 proj) { - return glm_persp_aspect(proj); -} - -#endif /*cglm_cam_lh_no_h*/ diff --git a/external/cglm/clipspace/persp_lh_zo.h b/external/cglm/clipspace/persp_lh_zo.h deleted file mode 100644 index de89643..0000000 --- a/external/cglm/clipspace/persp_lh_zo.h +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_frustum_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_lh_zo(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_default_lh_zo(float aspect, mat4 dest) - CGLM_INLINE void glm_perspective_resize_lh_zo(float aspect, mat4 proj) - CGLM_INLINE void glm_persp_move_far_lh_zo(mat4 proj, - float deltaFar) - CGLM_INLINE void glm_persp_decomp_lh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ, - float * __restrict top, - float * __restrict bottom, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decompv_lh_zo(mat4 proj, - float dest[6]) - CGLM_INLINE void glm_persp_decomp_x_lh_zo(mat4 proj, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decomp_y_lh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom) - CGLM_INLINE void glm_persp_decomp_z_lh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) - CGLM_INLINE void glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_persp_lh_zo_h -#define cglm_persp_lh_zo_h - -#include "../common.h" -#include "persp.h" - -/*! - * @brief set up perspective peprojection matrix with a left-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_frustum_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn, nv; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - nv = 2.0f * nearZ; - - dest[0][0] = nv * rl; - dest[1][1] = nv * tb; - dest[2][0] = (right + left) * rl; - dest[2][1] = (top + bottom) * tb; - dest[2][2] =-farZ * fn; - dest[2][3] = 1.0f; - dest[3][2] = farZ * nearZ * fn; -} - -/*! - * @brief set up perspective projection matrix with a left-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_lh_zo(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) { - float f, fn; - - glm_mat4_zero(dest); - - f = 1.0f / tanf(fovy * 0.5f); - fn = 1.0f / (nearZ - farZ); - - dest[0][0] = f / aspect; - dest[1][1] = f; - dest[2][2] =-farZ * fn; - dest[2][3] = 1.0f; - dest[3][2] = nearZ * farZ * fn; -} - -/*! - * @brief extend perspective projection matrix's far distance with a - * left-hand coordinate system and a clip-space with depth values - * from zero to one. - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -void -glm_persp_move_far_lh_zo(mat4 proj, float deltaFar) { - float fn, farZ, nearZ, p22, p32; - - p22 = -proj[2][2]; - p32 = proj[3][2]; - - nearZ = p32 / p22; - farZ = p32 / (p22 + 1.0f) + deltaFar; - fn = 1.0f / (nearZ - farZ); - - proj[2][2] = -farZ * fn; - proj[3][2] = nearZ * farZ * fn; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_default_lh_zo(float aspect, mat4 dest) { - glm_perspective_lh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in, out] proj perspective projection matrix - */ -CGLM_INLINE -void -glm_perspective_resize_lh_zo(float aspect, mat4 proj) { - if (proj[0][0] == 0.0f) - return; - - proj[0][0] = proj[1][1] / aspect; -} - -/*! - * @brief decomposes frustum values of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_lh_zo(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - float m00, m11, m20, m21, m22, m32, n, f; - float n_m11, n_m00; - - m00 = proj[0][0]; - m11 = proj[1][1]; - m20 = proj[2][0]; - m21 = proj[2][1]; - m22 =-proj[2][2]; - m32 = proj[3][2]; - - n = m32 / m22; - f = m32 / (m22 + 1.0f); - - n_m11 = n / m11; - n_m00 = n / m00; - - *nearZ = n; - *farZ = f; - *bottom = n_m11 * (m21 - 1.0f); - *top = n_m11 * (m21 + 1.0f); - *left = n_m00 * (m20 - 1.0f); - *right = n_m00 * (m20 + 1.0f); -} - -/*! - * @brief decomposes frustum values of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glm_persp_decompv_lh_zo(mat4 proj, float dest[6]) { - glm_persp_decomp_lh_zo(proj, &dest[0], &dest[1], &dest[2], - &dest[3], &dest[4], &dest[5]); -} - -/*! - * @brief decomposes left and right values of perspective projection (ZO). - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_x_lh_zo(mat4 proj, - float * __restrict left, - float * __restrict right) { - float nearZ, m20, m00; - - m00 = proj[0][0]; - m20 = proj[2][0]; - - nearZ = proj[3][2] / (proj[3][3]); - *left = nearZ * (m20 - 1.0f) / m00; - *right = nearZ * (m20 + 1.0f) / m00; -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glm_persp_decomp_y_lh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom) { - float nearZ, m21, m11; - - m21 = proj[2][1]; - m11 = proj[1][1]; - - nearZ = proj[3][2] / (proj[3][3]); - *bottom = nearZ * (m21 - 1) / m11; - *top = nearZ * (m21 + 1) / m11; -} - -/*! - * @brief decomposes near and far values of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_z_lh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) { - float m32, m22; - - m32 = proj[3][2]; - m22 = -proj[2][2]; - - *nearZ = m32 / m22; - *farZ = m32 / (m22 + 1.0f); -} - -/*! - * @brief decomposes far value of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_far_lh_zo(mat4 proj, float * __restrict farZ) { - *farZ = proj[3][2] / (-proj[2][2] + 1.0f); -} - -/*! - * @brief decomposes near value of perspective projection - * with angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glm_persp_decomp_near_lh_zo(mat4 proj, float * __restrict nearZ) { - *nearZ = proj[3][2] / -proj[2][2]; -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -void -glm_persp_sizes_lh_zo(mat4 proj, float fovy, vec4 dest) { - float t, a, nearZ, farZ; - - t = 2.0f * tanf(fovy * 0.5f); - a = glm_persp_aspect(proj); - - glm_persp_decomp_z_lh_zo(proj, &nearZ, &farZ); - - dest[1] = t * nearZ; - dest[3] = t * farZ; - dest[0] = a * dest[1]; - dest[2] = a * dest[3]; -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_fovy_lh_zo(mat4 proj) { - return glm_persp_fovy(proj); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a left-hand coordinate system and a clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_aspect_lh_zo(mat4 proj) { - return glm_persp_aspect(proj); -} - -#endif /*cglm_persp_lh_zo_h*/ diff --git a/external/cglm/clipspace/persp_rh_no.h b/external/cglm/clipspace/persp_rh_no.h deleted file mode 100644 index 9252332..0000000 --- a/external/cglm/clipspace/persp_rh_no.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_frustum_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_rh_no(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_default_rh_no(float aspect, mat4 dest) - CGLM_INLINE void glm_perspective_resize_rh_no(float aspect, mat4 proj) - CGLM_INLINE void glm_persp_move_far_rh_no(mat4 proj, - float deltaFar) - CGLM_INLINE void glm_persp_decomp_rh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ, - float * __restrict top, - float * __restrict bottom, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decompv_rh_no(mat4 proj, - float dest[6]) - CGLM_INLINE void glm_persp_decomp_x_rh_no(mat4 proj, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decomp_y_rh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom) - CGLM_INLINE void glm_persp_decomp_z_rh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) - CGLM_INLINE void glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_persp_rh_no_h -#define cglm_persp_rh_no_h - -#include "../common.h" -#include "persp.h" - -/*! - * @brief set up perspective peprojection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_frustum_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn, nv; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - nv = 2.0f * nearZ; - - dest[0][0] = nv * rl; - dest[1][1] = nv * tb; - dest[2][0] = (right + left) * rl; - dest[2][1] = (top + bottom) * tb; - dest[2][2] = (farZ + nearZ) * fn; - dest[2][3] =-1.0f; - dest[3][2] = farZ * nv * fn; -} - -/*! - * @brief set up perspective projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_rh_no(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) { - float f, fn; - - glm_mat4_zero(dest); - - f = 1.0f / tanf(fovy * 0.5f); - fn = 1.0f / (nearZ - farZ); - - dest[0][0] = f / aspect; - dest[1][1] = f; - dest[2][2] = (nearZ + farZ) * fn; - dest[2][3] =-1.0f; - dest[3][2] = 2.0f * nearZ * farZ * fn; - -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_default_rh_no(float aspect, mat4 dest) { - glm_perspective_rh_no(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * resized with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in, out] proj perspective projection matrix - */ -CGLM_INLINE -void -glm_perspective_resize_rh_no(float aspect, mat4 proj) { - if (proj[0][0] == 0.0f) - return; - - proj[0][0] = proj[1][1] / aspect; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -void -glm_persp_move_far_rh_no(mat4 proj, float deltaFar) { - float fn, farZ, nearZ, p22, p32; - - p22 = proj[2][2]; - p32 = proj[3][2]; - - nearZ = p32 / (p22 - 1.0f); - farZ = p32 / (p22 + 1.0f) + deltaFar; - fn = 1.0f / (nearZ - farZ); - - proj[2][2] = (farZ + nearZ) * fn; - proj[3][2] = 2.0f * nearZ * farZ * fn; -} - -/*! - * @brief decomposes frustum values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_rh_no(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - float m00, m11, m20, m21, m22, m32, n, f; - float n_m11, n_m00; - - m00 = proj[0][0]; - m11 = proj[1][1]; - m20 = proj[2][0]; - m21 = proj[2][1]; - m22 = proj[2][2]; - m32 = proj[3][2]; - - n = m32 / (m22 - 1.0f); - f = m32 / (m22 + 1.0f); - - n_m11 = n / m11; - n_m00 = n / m00; - - *nearZ = n; - *farZ = f; - *bottom = n_m11 * (m21 - 1.0f); - *top = n_m11 * (m21 + 1.0f); - *left = n_m00 * (m20 - 1.0f); - *right = n_m00 * (m20 + 1.0f); -} - -/*! - * @brief decomposes frustum values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glm_persp_decompv_rh_no(mat4 proj, float dest[6]) { - glm_persp_decomp_rh_no(proj, &dest[0], &dest[1], &dest[2], - &dest[3], &dest[4], &dest[5]); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_x_rh_no(mat4 proj, - float * __restrict left, - float * __restrict right) { - float nearZ, m20, m00, m22; - - m00 = proj[0][0]; - m20 = proj[2][0]; - m22 = proj[2][2]; - - nearZ = proj[3][2] / (m22 - 1.0f); - *left = nearZ * (m20 - 1.0f) / m00; - *right = nearZ * (m20 + 1.0f) / m00; -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glm_persp_decomp_y_rh_no(mat4 proj, - float * __restrict top, - float * __restrict bottom) { - float nearZ, m21, m11, m22; - - m21 = proj[2][1]; - m11 = proj[1][1]; - m22 = proj[2][2]; - - nearZ = proj[3][2] / (m22 - 1.0f); - *bottom = nearZ * (m21 - 1.0f) / m11; - *top = nearZ * (m21 + 1.0f) / m11; -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_z_rh_no(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) { - float m32, m22; - - m32 = proj[3][2]; - m22 = proj[2][2]; - - *nearZ = m32 / (m22 - 1.0f); - *farZ = m32 / (m22 + 1.0f); -} - -/*! - * @brief decomposes far value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_far_rh_no(mat4 proj, float * __restrict farZ) { - *farZ = proj[3][2] / (proj[2][2] + 1.0f); -} - -/*! - * @brief decomposes near value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glm_persp_decomp_near_rh_no(mat4 proj, float * __restrict nearZ) { - *nearZ = proj[3][2] / (proj[2][2] - 1.0f); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -void -glm_persp_sizes_rh_no(mat4 proj, float fovy, vec4 dest) { - float t, a, nearZ, farZ; - - t = 2.0f * tanf(fovy * 0.5f); - a = glm_persp_aspect(proj); - - glm_persp_decomp_z_rh_no(proj, &nearZ, &farZ); - - dest[1] = t * nearZ; - dest[3] = t * farZ; - dest[0] = a * dest[1]; - dest[2] = a * dest[3]; -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a right-hand coordinate system and a clip-space of [-1, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_fovy_rh_no(mat4 proj) { - return glm_persp_fovy(proj); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a right-hand coordinate system and a clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_aspect_rh_no(mat4 proj) { - return glm_persp_aspect(proj); -} - -#endif /*cglm_cam_rh_no_h*/ diff --git a/external/cglm/clipspace/persp_rh_zo.h b/external/cglm/clipspace/persp_rh_zo.h deleted file mode 100644 index ce632b3..0000000 --- a/external/cglm/clipspace/persp_rh_zo.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_frustum_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_rh_zo(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) - CGLM_INLINE void glm_perspective_default_rh_zo(float aspect, mat4 dest) - CGLM_INLINE void glm_perspective_resize_rh_zo(float aspect, mat4 proj) - CGLM_INLINE void glm_persp_move_far_rh_zo(mat4 proj, - float deltaFar) - CGLM_INLINE void glm_persp_decomp_rh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ, - float * __restrict top, - float * __restrict bottom, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decompv_rh_zo(mat4 proj, - float dest[6]) - CGLM_INLINE void glm_persp_decomp_x_rh_zo(mat4 proj, - float * __restrict left, - float * __restrict right) - CGLM_INLINE void glm_persp_decomp_y_rh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom) - CGLM_INLINE void glm_persp_decomp_z_rh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) - CGLM_INLINE void glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) - CGLM_INLINE void glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) - */ - -#ifndef cglm_persp_rh_zo_h -#define cglm_persp_rh_zo_h - -#include "../common.h" -#include "persp.h" - -/*! - * @brief set up perspective peprojection matrix with a right-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_frustum_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ, - mat4 dest) { - float rl, tb, fn, nv; - - glm_mat4_zero(dest); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - fn =-1.0f / (farZ - nearZ); - nv = 2.0f * nearZ; - - dest[0][0] = nv * rl; - dest[1][1] = nv * tb; - dest[2][0] = (right + left) * rl; - dest[2][1] = (top + bottom) * tb; - dest[2][2] = farZ * fn; - dest[2][3] =-1.0f; - dest[3][2] = farZ * nearZ * fn; -} - -/*! - * @brief set up perspective projection matrix with a right-hand coordinate - * system and a clip-space of [0, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_rh_zo(float fovy, - float aspect, - float nearZ, - float farZ, - mat4 dest) { - float f, fn; - - glm_mat4_zero(dest); - - f = 1.0f / tanf(fovy * 0.5f); - fn = 1.0f / (nearZ - farZ); - - dest[0][0] = f / aspect; - dest[1][1] = f; - dest[2][2] = farZ * fn; - dest[2][3] =-1.0f; - dest[3][2] = nearZ * farZ * fn; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_perspective_default_rh_zo(float aspect, mat4 dest) { - glm_perspective_rh_zo(GLM_PI_4f, aspect, 0.01f, 100.0f, dest); -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * resized with a right-hand coordinate system and a clip-space of - * [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in, out] proj perspective projection matrix - */ -CGLM_INLINE -void -glm_perspective_resize_rh_zo(float aspect, mat4 proj) { - if (proj[0][0] == 0.0f) - return; - - proj[0][0] = proj[1][1] / aspect; -} - -/*! - * @brief extend perspective projection matrix's far distance with a - * right-hand coordinate system and a clip-space of [0, 1]. - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -void -glm_persp_move_far_rh_zo(mat4 proj, float deltaFar) { - float fn, farZ, nearZ, p22, p32; - - p22 = proj[2][2]; - p32 = proj[3][2]; - - nearZ = p32 / p22; - farZ = p32 / (p22 + 1.0f) + deltaFar; - fn = 1.0f / (nearZ - farZ); - - proj[2][2] = farZ * fn; - proj[3][2] = nearZ * farZ * fn; -} - -/*! - * @brief decomposes frustum values of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_rh_zo(mat4 proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - float m00, m11, m20, m21, m22, m32, n, f; - float n_m11, n_m00; - - m00 = proj[0][0]; - m11 = proj[1][1]; - m20 = proj[2][0]; - m21 = proj[2][1]; - m22 = proj[2][2]; - m32 = proj[3][2]; - - n = m32 / m22; - f = m32 / (m22 + 1.0f); - - n_m11 = n / m11; - n_m00 = n / m00; - - *nearZ = n; - *farZ = f; - *bottom = n_m11 * (m21 - 1.0f); - *top = n_m11 * (m21 + 1.0f); - *left = n_m00 * (m20 - 1.0f); - *right = n_m00 * (m20 + 1.0f); -} - -/*! - * @brief decomposes frustum values of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glm_persp_decompv_rh_zo(mat4 proj, float dest[6]) { - glm_persp_decomp_rh_zo(proj, &dest[0], &dest[1], &dest[2], - &dest[3], &dest[4], &dest[5]); -} - -/*! - * @brief decomposes left and right values of perspective projection (ZO). - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glm_persp_decomp_x_rh_zo(mat4 proj, - float * __restrict left, - float * __restrict right) { - float nearZ, m20, m00, m22; - - m00 = proj[0][0]; - m20 = proj[2][0]; - m22 = proj[2][2]; - - nearZ = proj[3][2] / m22; - *left = nearZ * (m20 - 1.0f) / m00; - *right = nearZ * (m20 + 1.0f) / m00; -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glm_persp_decomp_y_rh_zo(mat4 proj, - float * __restrict top, - float * __restrict bottom) { - float nearZ, m21, m11, m22; - - m21 = proj[2][1]; - m11 = proj[1][1]; - m22 = proj[2][2]; - - nearZ = proj[3][2] / m22; - *bottom = nearZ * (m21 - 1) / m11; - *top = nearZ * (m21 + 1) / m11; -} - -/*! - * @brief decomposes near and far values of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_z_rh_zo(mat4 proj, - float * __restrict nearZ, - float * __restrict farZ) { - float m32, m22; - - m32 = proj[3][2]; - m22 = proj[2][2]; - - *nearZ = m32 / m22; - *farZ = m32 / (m22 + 1.0f); -} - -/*! - * @brief decomposes far value of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glm_persp_decomp_far_rh_zo(mat4 proj, float * __restrict farZ) { - *farZ = proj[3][2] / (proj[2][2] + 1.0f); -} - -/*! - * @brief decomposes near value of perspective projection - * with angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glm_persp_decomp_near_rh_zo(mat4 proj, float * __restrict nearZ) { - *nearZ = proj[3][2] / proj[2][2]; -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @param[out] dest sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -void -glm_persp_sizes_rh_zo(mat4 proj, float fovy, vec4 dest) { - float t, a, nearZ, farZ; - - t = 2.0f * tanf(fovy * 0.5f); - a = glm_persp_aspect(proj); - - glm_persp_decomp_z_rh_zo(proj, &nearZ, &farZ); - - dest[1] = t * nearZ; - dest[3] = t * farZ; - dest[0] = a * dest[1]; - dest[2] = a * dest[3]; -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a right-hand coordinate system and a clip-space of [0, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_fovy_rh_zo(mat4 proj) { - return glm_persp_fovy(proj); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a right-hand coordinate system and a clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glm_persp_aspect_rh_zo(mat4 proj) { - return glm_persp_aspect(proj); -} - -#endif /*cglm_persp_rh_zo_h*/ diff --git a/external/cglm/clipspace/project_no.h b/external/cglm/clipspace/project_no.h deleted file mode 100644 index 71fbc52..0000000 --- a/external/cglm/clipspace/project_no.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_project_no_h -#define cglm_project_no_h - -#include "../common.h" -#include "../vec3.h" -#include "../vec4.h" -#include "../mat4.h" - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest unprojected coordinates - */ -CGLM_INLINE -void -glm_unprojecti_no(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { - vec4 v; - - v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; - v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; - v[2] = 2.0f * pos[2] - 1.0f; - v[3] = 1.0f; - - glm_mat4_mulv(invMat, v, v); - glm_vec4_scale(v, 1.0f / v[3], v); - glm_vec3(v, dest); -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest projected coordinates - */ -CGLM_INLINE -void -glm_project_no(vec3 pos, mat4 m, vec4 vp, vec3 dest) { - CGLM_ALIGN(16) vec4 pos4; - - glm_vec4(pos, 1.0f, pos4); - - glm_mat4_mulv(m, pos4, pos4); - glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ - glm_vec4_scale(pos4, 0.5f, pos4); - glm_vec4_adds(pos4, 0.5f, pos4); - - dest[0] = pos4[0] * vp[2] + vp[0]; - dest[1] = pos4[1] * vp[3] + vp[1]; - dest[2] = pos4[2]; -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glm_project_z_no(vec3 v, mat4 m) { - float z, w; - - z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; - w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; - - return 0.5f * (z / w) + 0.5f; -} - -#endif /* cglm_project_no_h */ diff --git a/external/cglm/clipspace/project_zo.h b/external/cglm/clipspace/project_zo.h deleted file mode 100644 index dc32078..0000000 --- a/external/cglm/clipspace/project_zo.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_project_zo_h -#define cglm_project_zo_h - -#include "../common.h" -#include "../vec3.h" -#include "../vec4.h" -#include "../mat4.h" - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest unprojected coordinates - */ -CGLM_INLINE -void -glm_unprojecti_zo(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { - vec4 v; - - v[0] = 2.0f * (pos[0] - vp[0]) / vp[2] - 1.0f; - v[1] = 2.0f * (pos[1] - vp[1]) / vp[3] - 1.0f; - v[2] = pos[2]; - v[3] = 1.0f; - - glm_mat4_mulv(invMat, v, v); - glm_vec4_scale(v, 1.0f / v[3], v); - glm_vec3(v, dest); -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest projected coordinates - */ -CGLM_INLINE -void -glm_project_zo(vec3 pos, mat4 m, vec4 vp, vec3 dest) { - CGLM_ALIGN(16) vec4 pos4; - - glm_vec4(pos, 1.0f, pos4); - - glm_mat4_mulv(m, pos4, pos4); - glm_vec4_scale(pos4, 1.0f / pos4[3], pos4); /* pos = pos / pos.w */ - - dest[2] = pos4[2]; - - glm_vec4_scale(pos4, 0.5f, pos4); - glm_vec4_adds(pos4, 0.5f, pos4); - - dest[0] = pos4[0] * vp[2] + vp[0]; - dest[1] = pos4[1] * vp[3] + vp[1]; -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glm_project_z_zo(vec3 v, mat4 m) { - float z, w; - - z = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2]; - w = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3]; - - return z / w; -} - -#endif /* cglm_project_zo_h */ diff --git a/external/cglm/clipspace/view_lh.h b/external/cglm/clipspace/view_lh.h deleted file mode 100644 index 5667694..0000000 --- a/external/cglm/clipspace/view_lh.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_lh_h -#define cglm_view_lh_h - -#include "../common.h" -#include "../plane.h" - -/*! - * @brief set up view matrix (LH) - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_lh(vec3 eye, vec3 center, vec3 up, mat4 dest) { - CGLM_ALIGN(8) vec3 f, u, s; - - glm_vec3_sub(center, eye, f); - glm_vec3_normalize(f); - - glm_vec3_crossn(up, f, s); - glm_vec3_cross(f, s, u); - - dest[0][0] = s[0]; - dest[0][1] = u[0]; - dest[0][2] = f[0]; - dest[1][0] = s[1]; - dest[1][1] = u[1]; - dest[1][2] = f[1]; - dest[2][0] = s[2]; - dest[2][1] = u[2]; - dest[2][2] = f[2]; - dest[3][0] =-glm_vec3_dot(s, eye); - dest[3][1] =-glm_vec3_dot(u, eye); - dest[3][2] =-glm_vec3_dot(f, eye); - dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up view matrix with left handed coordinate system - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_lh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - CGLM_ALIGN(8) vec3 target; - glm_vec3_add(eye, dir, target); - glm_lookat_lh(eye, target, up, dest); -} - -/*! - * @brief set up view matrix with left handed coordinate system - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_lh(vec3 eye, vec3 dir, mat4 dest) { - CGLM_ALIGN(8) vec3 up; - glm_vec3_ortho(dir, up); - glm_look_lh(eye, dir, up, dest); -} - -#endif /*cglm_view_lh_h*/ diff --git a/external/cglm/clipspace/view_lh_no.h b/external/cglm/clipspace/view_lh_no.h deleted file mode 100644 index 454d903..0000000 --- a/external/cglm/clipspace/view_lh_no.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_lh_no_h -#define cglm_view_lh_no_h - -#include "../common.h" -#include "view_lh.h" - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_lh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { - glm_lookat_lh(eye, center, up, dest); -} - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_lh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - glm_look_lh(eye, dir, up, dest); -} - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_lh_no(vec3 eye, vec3 dir, mat4 dest) { - glm_look_anyup_lh(eye, dir, dest); -} - -#endif /*cglm_view_lh_no_h*/ diff --git a/external/cglm/clipspace/view_lh_zo.h b/external/cglm/clipspace/view_lh_zo.h deleted file mode 100644 index 6b0c4d1..0000000 --- a/external/cglm/clipspace/view_lh_zo.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_lh_zo_h -#define cglm_view_lh_zo_h - -#include "../common.h" -#include "view_lh.h" - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_lh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { - glm_lookat_lh(eye, center, up, dest); -} - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_lh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - glm_look_lh(eye, dir, up, dest); -} - -/*! - * @brief set up view matrix with left handed coordinate system. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_lh_zo(vec3 eye, vec3 dir, mat4 dest) { - glm_look_anyup_lh(eye, dir, dest); -} - -#endif /*cglm_view_lh_zo_h*/ diff --git a/external/cglm/clipspace/view_rh.h b/external/cglm/clipspace/view_rh.h deleted file mode 100644 index 51ec916..0000000 --- a/external/cglm/clipspace/view_rh.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_rh_h -#define cglm_view_rh_h - -#include "../common.h" -#include "../plane.h" - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_rh(vec3 eye, vec3 center, vec3 up, mat4 dest) { - CGLM_ALIGN(8) vec3 f, u, s; - - glm_vec3_sub(center, eye, f); - glm_vec3_normalize(f); - - glm_vec3_crossn(f, up, s); - glm_vec3_cross(s, f, u); - - dest[0][0] = s[0]; - dest[0][1] = u[0]; - dest[0][2] =-f[0]; - dest[1][0] = s[1]; - dest[1][1] = u[1]; - dest[1][2] =-f[1]; - dest[2][0] = s[2]; - dest[2][1] = u[2]; - dest[2][2] =-f[2]; - dest[3][0] =-glm_vec3_dot(s, eye); - dest[3][1] =-glm_vec3_dot(u, eye); - dest[3][2] = glm_vec3_dot(f, eye); - dest[0][3] = dest[1][3] = dest[2][3] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_rh(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - CGLM_ALIGN(8) vec3 target; - glm_vec3_add(eye, dir, target); - glm_lookat_rh(eye, target, up, dest); -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_rh(vec3 eye, vec3 dir, mat4 dest) { - CGLM_ALIGN(8) vec3 up; - glm_vec3_ortho(dir, up); - glm_look_rh(eye, dir, up, dest); -} - -#endif /*cglm_view_rh_h*/ diff --git a/external/cglm/clipspace/view_rh_no.h b/external/cglm/clipspace/view_rh_no.h deleted file mode 100644 index ca36d30..0000000 --- a/external/cglm/clipspace/view_rh_no.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_rh_no_h -#define cglm_view_rh_no_h - -#include "../common.h" -#include "view_rh.h" - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_rh_no(vec3 eye, vec3 center, vec3 up, mat4 dest) { - glm_lookat_rh(eye, center, up, dest); -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_rh_no(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - glm_look_rh(eye, dir, up, dest); -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_rh_no(vec3 eye, vec3 dir, mat4 dest) { - glm_look_anyup_rh(eye, dir, dest); -} - -#endif /*cglm_view_rh_no_h*/ diff --git a/external/cglm/clipspace/view_rh_zo.h b/external/cglm/clipspace/view_rh_zo.h deleted file mode 100644 index 1ad5c91..0000000 --- a/external/cglm/clipspace/view_rh_zo.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) - CGLM_INLINE void glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) - */ - -#ifndef cglm_view_rh_zo_h -#define cglm_view_rh_zo_h - -#include "../common.h" -#include "view_rh.h" - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_lookat_rh_zo(vec3 eye, vec3 center, vec3 up, mat4 dest) { - glm_lookat_rh(eye, center, up, dest); -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_rh_zo(vec3 eye, vec3 dir, vec3 up, mat4 dest) { - glm_look_rh(eye, dir, up, dest); -} - -/*! - * @brief set up view matrix with right handed coordinate system. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_look_anyup_rh_zo(vec3 eye, vec3 dir, mat4 dest) { - glm_look_anyup_rh(eye, dir, dest); -} - -#endif /*cglm_view_rh_zo_h*/ diff --git a/external/cglm/color.h b/external/cglm/color.h deleted file mode 100644 index 69566ad..0000000 --- a/external/cglm/color.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_color_h -#define cglm_color_h - -#include "common.h" -#include "vec3.h" - -/*! - * @brief averages the color channels into one value - * - * @param[in] rgb RGB color - */ -CGLM_INLINE -float -glm_luminance(vec3 rgb) { - vec3 l = {0.212671f, 0.715160f, 0.072169f}; - return glm_dot(rgb, l); -} - -#endif /* cglm_color_h */ diff --git a/external/cglm/common.h b/external/cglm/common.h deleted file mode 100644 index 1af754d..0000000 --- a/external/cglm/common.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_common_h -#define cglm_common_h - -#define __cglm__ 1 - -#ifndef _USE_MATH_DEFINES -# define _USE_MATH_DEFINES /* for windows */ -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -# define _CRT_SECURE_NO_WARNINGS /* for windows */ -#endif - -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) -# ifdef CGLM_STATIC -# define CGLM_EXPORT -# elif defined(CGLM_EXPORTS) -# define CGLM_EXPORT __declspec(dllexport) -# else -# define CGLM_EXPORT __declspec(dllimport) -# endif -# define CGLM_INLINE __forceinline -#else -# define CGLM_EXPORT __attribute__((visibility("default"))) -# define CGLM_INLINE static inline __attribute((always_inline)) -#endif - -#if defined(__GNUC__) || defined(__clang__) -# define CGLM_UNLIKELY(expr) __builtin_expect(!!(expr), 0) -# define CGLM_LIKELY(expr) __builtin_expect(!!(expr), 1) -#else -# define CGLM_UNLIKELY(expr) (expr) -# define CGLM_LIKELY(expr) (expr) -#endif - -#if defined(_M_FP_FAST) || defined(__FAST_MATH__) -# define CGLM_FAST_MATH -#endif - -#define GLM_SHUFFLE4(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w)) -#define GLM_SHUFFLE3(z, y, x) (((z) << 4) | ((y) << 2) | (x)) -#define GLM_SHUFFLE2(y, x) (((y) << 2) | (x)) - -#include "types.h" -#include "simd/intrin.h" - -#ifndef CGLM_USE_DEFAULT_EPSILON -# ifndef GLM_FLT_EPSILON -# define GLM_FLT_EPSILON 1e-5f -# endif -#else -# define GLM_FLT_EPSILON FLT_EPSILON -#endif - -/* - * Clip control: define CGLM_FORCE_DEPTH_ZERO_TO_ONE before including - * CGLM to use a clip space between 0 to 1. - * Coordinate system: define CGLM_FORCE_LEFT_HANDED before including - * CGLM to use the left handed coordinate system by default. - */ - -#define CGLM_CLIP_CONTROL_ZO_BIT (1 << 0) /* ZERO_TO_ONE */ -#define CGLM_CLIP_CONTROL_NO_BIT (1 << 1) /* NEGATIVE_ONE_TO_ONE */ -#define CGLM_CLIP_CONTROL_LH_BIT (1 << 2) /* LEFT_HANDED, For DirectX, Metal, Vulkan */ -#define CGLM_CLIP_CONTROL_RH_BIT (1 << 3) /* RIGHT_HANDED, For OpenGL, default in GLM */ - -#define CGLM_CLIP_CONTROL_LH_ZO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) -#define CGLM_CLIP_CONTROL_LH_NO (CGLM_CLIP_CONTROL_LH_BIT | CGLM_CLIP_CONTROL_NO_BIT) -#define CGLM_CLIP_CONTROL_RH_ZO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_ZO_BIT) -#define CGLM_CLIP_CONTROL_RH_NO (CGLM_CLIP_CONTROL_RH_BIT | CGLM_CLIP_CONTROL_NO_BIT) - -#ifdef CGLM_FORCE_DEPTH_ZERO_TO_ONE -# ifdef CGLM_FORCE_LEFT_HANDED -# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_ZO -# else -# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_ZO -# endif -#else -# ifdef CGLM_FORCE_LEFT_HANDED -# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_LH_NO -# else -# define CGLM_CONFIG_CLIP_CONTROL CGLM_CLIP_CONTROL_RH_NO -# endif -#endif - -/* struct API configurator */ -/* TODO: move struct/common.h? */ -/* WARN: dont use concant helpers outside cglm headers, because they may be changed */ - -#define CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E, ...) A ## B ## C ## D ## E ## __VA_ARGS__ -#define CGLM_MACRO_CONCAT(A, B, C, D, E, ...) CGLM_MACRO_CONCAT_HELPER(A, B, C, D, E,__VA_ARGS__) - -#ifndef CGLM_OMIT_NS_FROM_STRUCT_API -# ifndef CGLM_STRUCT_API_NS -# define CGLM_STRUCT_API_NS glms -# endif -# ifndef CGLM_STRUCT_API_NS_SEPERATOR -# define CGLM_STRUCT_API_NS_SEPERATOR _ -# endif -#else -# define CGLM_STRUCT_API_NS -# define CGLM_STRUCT_API_NS_SEPERATOR -#endif - -#ifndef CGLM_STRUCT_API_NAME_SUFFIX -# define CGLM_STRUCT_API_NAME_SUFFIX -#endif - -#define CGLM_STRUCTAPI(A, ...) CGLM_MACRO_CONCAT(CGLM_STRUCT_API_NS, \ - CGLM_STRUCT_API_NS_SEPERATOR, \ - A, \ - CGLM_STRUCT_API_NAME_SUFFIX, \ - _, \ - __VA_ARGS__) - -#endif /* cglm_common_h */ diff --git a/external/cglm/curve.h b/external/cglm/curve.h deleted file mode 100644 index 5033be5..0000000 --- a/external/cglm/curve.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_curve_h -#define cglm_curve_h - -#include "common.h" -#include "vec4.h" -#include "mat4.h" - -/*! - * @brief helper function to calculate S*M*C multiplication for curves - * - * This function does not encourage you to use SMC, - * instead it is a helper if you use SMC. - * - * if you want to specify S as vector then use more generic glm_mat4_rmc() func. - * - * Example usage: - * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) - * - * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) - * @param[in] m basis matrix - * @param[in] c position/control vector - * - * @return B(s) - */ -CGLM_INLINE -float -glm_smc(float s, mat4 m, vec4 c) { - vec4 vs; - glm_vec4_cubic(s, vs); - return glm_mat4_rmc(vs, m, c); -} - -#endif /* cglm_curve_h */ diff --git a/external/cglm/ease.h b/external/cglm/ease.h deleted file mode 100644 index e26b48c..0000000 --- a/external/cglm/ease.h +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_ease_h -#define cglm_ease_h - -#include "common.h" - -CGLM_INLINE -float -glm_ease_linear(float t) { - return t; -} - -CGLM_INLINE -float -glm_ease_sine_in(float t) { - return sinf((t - 1.0f) * GLM_PI_2f) + 1.0f; -} - -CGLM_INLINE -float -glm_ease_sine_out(float t) { - return sinf(t * GLM_PI_2f); -} - -CGLM_INLINE -float -glm_ease_sine_inout(float t) { - return 0.5f * (1.0f - cosf(t * GLM_PIf)); -} - -CGLM_INLINE -float -glm_ease_quad_in(float t) { - return t * t; -} - -CGLM_INLINE -float -glm_ease_quad_out(float t) { - return -(t * (t - 2.0f)); -} - -CGLM_INLINE -float -glm_ease_quad_inout(float t) { - float tt; - - tt = t * t; - if (t < 0.5f) - return 2.0f * tt; - - return (-2.0f * tt) + (4.0f * t) - 1.0f; -} - -CGLM_INLINE -float -glm_ease_cubic_in(float t) { - return t * t * t; -} - -CGLM_INLINE -float -glm_ease_cubic_out(float t) { - float f; - f = t - 1.0f; - return f * f * f + 1.0f; -} - -CGLM_INLINE -float -glm_ease_cubic_inout(float t) { - float f; - - if (t < 0.5f) - return 4.0f * t * t * t; - - f = 2.0f * t - 2.0f; - - return 0.5f * f * f * f + 1.0f; -} - -CGLM_INLINE -float -glm_ease_quart_in(float t) { - float f; - f = t * t; - return f * f; -} - -CGLM_INLINE -float -glm_ease_quart_out(float t) { - float f; - - f = t - 1.0f; - - return f * f * f * (1.0f - t) + 1.0f; -} - -CGLM_INLINE -float -glm_ease_quart_inout(float t) { - float f, g; - - if (t < 0.5f) { - f = t * t; - return 8.0f * f * f; - } - - f = t - 1.0f; - g = f * f; - - return -8.0f * g * g + 1.0f; -} - -CGLM_INLINE -float -glm_ease_quint_in(float t) { - float f; - f = t * t; - return f * f * t; -} - -CGLM_INLINE -float -glm_ease_quint_out(float t) { - float f, g; - - f = t - 1.0f; - g = f * f; - - return g * g * f + 1.0f; -} - -CGLM_INLINE -float -glm_ease_quint_inout(float t) { - float f, g; - - if (t < 0.5f) { - f = t * t; - return 16.0f * f * f * t; - } - - f = 2.0f * t - 2.0f; - g = f * f; - - return 0.5f * g * g * f + 1.0f; -} - -CGLM_INLINE -float -glm_ease_exp_in(float t) { - if (t == 0.0f) - return t; - - return powf(2.0f, 10.0f * (t - 1.0f)); -} - -CGLM_INLINE -float -glm_ease_exp_out(float t) { - if (t == 1.0f) - return t; - - return 1.0f - powf(2.0f, -10.0f * t); -} - -CGLM_INLINE -float -glm_ease_exp_inout(float t) { - if (t == 0.0f || t == 1.0f) - return t; - - if (t < 0.5f) - return 0.5f * powf(2.0f, (20.0f * t) - 10.0f); - - return -0.5f * powf(2.0f, (-20.0f * t) + 10.0f) + 1.0f; -} - -CGLM_INLINE -float -glm_ease_circ_in(float t) { - return 1.0f - sqrtf(1.0f - (t * t)); -} - -CGLM_INLINE -float -glm_ease_circ_out(float t) { - return sqrtf((2.0f - t) * t); -} - -CGLM_INLINE -float -glm_ease_circ_inout(float t) { - if (t < 0.5f) - return 0.5f * (1.0f - sqrtf(1.0f - 4.0f * (t * t))); - - return 0.5f * (sqrtf(-((2.0f * t) - 3.0f) * ((2.0f * t) - 1.0f)) + 1.0f); -} - -CGLM_INLINE -float -glm_ease_back_in(float t) { - float o, z; - - o = 1.70158f; - z = ((o + 1.0f) * t) - o; - - return t * t * z; -} - -CGLM_INLINE -float -glm_ease_back_out(float t) { - float o, z, n; - - o = 1.70158f; - n = t - 1.0f; - z = (o + 1.0f) * n + o; - - return n * n * z + 1.0f; -} - -CGLM_INLINE -float -glm_ease_back_inout(float t) { - float o, z, n, m, s, x; - - o = 1.70158f; - s = o * 1.525f; - x = 0.5f; - n = t / 0.5f; - - if (n < 1.0f) { - z = (s + 1) * n - s; - m = n * n * z; - return x * m; - } - - n -= 2.0f; - z = (s + 1.0f) * n + s; - m = (n * n * z) + 2; - - return x * m; -} - -CGLM_INLINE -float -glm_ease_elast_in(float t) { - return sinf(13.0f * GLM_PI_2f * t) * powf(2.0f, 10.0f * (t - 1.0f)); -} - -CGLM_INLINE -float -glm_ease_elast_out(float t) { - return sinf(-13.0f * GLM_PI_2f * (t + 1.0f)) * powf(2.0f, -10.0f * t) + 1.0f; -} - -CGLM_INLINE -float -glm_ease_elast_inout(float t) { - float a; - - a = 2.0f * t; - - if (t < 0.5f) - return 0.5f * sinf(13.0f * GLM_PI_2f * a) - * powf(2.0f, 10.0f * (a - 1.0f)); - - return 0.5f * (sinf(-13.0f * GLM_PI_2f * a) - * powf(2.0f, -10.0f * (a - 1.0f)) + 2.0f); -} - -CGLM_INLINE -float -glm_ease_bounce_out(float t) { - float tt; - - tt = t * t; - - if (t < (4.0f / 11.0f)) - return (121.0f * tt) / 16.0f; - - if (t < 8.0f / 11.0f) - return ((363.0f / 40.0f) * tt) - ((99.0f / 10.0f) * t) + (17.0f / 5.0f); - - if (t < (9.0f / 10.0f)) - return (4356.0f / 361.0f) * tt - - (35442.0f / 1805.0f) * t - + (16061.0f / 1805.0f); - - return ((54.0f / 5.0f) * tt) - ((513.0f / 25.0f) * t) + (268.0f / 25.0f); -} - -CGLM_INLINE -float -glm_ease_bounce_in(float t) { - return 1.0f - glm_ease_bounce_out(1.0f - t); -} - -CGLM_INLINE -float -glm_ease_bounce_inout(float t) { - if (t < 0.5f) - return 0.5f * (1.0f - glm_ease_bounce_out(t * 2.0f)); - - return 0.5f * glm_ease_bounce_out(t * 2.0f - 1.0f) + 0.5f; -} - -#endif /* cglm_ease_h */ diff --git a/external/cglm/euler.h b/external/cglm/euler.h deleted file mode 100644 index 8fae039..0000000 --- a/external/cglm/euler.h +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - NOTE: - angles must be passed as [X-Angle, Y-Angle, Z-angle] order - For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to - glm_euler_zxy function, All RELATED functions accept angles same order - which is [X, Y, Z]. - */ - -/* - Types: - enum glm_euler_seq - - Functions: - CGLM_INLINE glm_euler_seq glm_euler_order(int newOrder[3]); - CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest); - CGLM_INLINE void glm_euler(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest); - CGLM_INLINE void glm_euler_by_order(vec3 angles, - glm_euler_seq ord, - mat4 dest); - CGLM_INLINE void glm_euler_xyz_quat(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_xzy_quat(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yxz_quat(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yzx_quat(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zxy_quat(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zyx_quat(vec3 angles, versor dest); - */ - -#ifndef cglm_euler_h -#define cglm_euler_h - -#include "common.h" - -#ifdef CGLM_FORCE_LEFT_HANDED -# include "handed/euler_to_quat_lh.h" -#else -# include "handed/euler_to_quat_rh.h" -#endif - - -#ifndef CGLM_CLIPSPACE_INCLUDE_ALL -# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/view_lh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/view_lh_no.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/view_rh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_rh_no.h" -# endif -#else -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_lh_zo.h" -# include "clipspace/view_lh_no.h" -# include "clipspace/view_rh_zo.h" -# include "clipspace/view_rh_no.h" -#endif - - -/*! - * if you have axis order like vec3 orderVec = [0, 1, 2] or [0, 2, 1]... - * vector then you can convert it to this enum by doing this: - * @code - * glm_euler_seq order; - * order = orderVec[0] | orderVec[1] << 2 | orderVec[2] << 4; - * @endcode - * you may need to explicit cast if required - */ -typedef enum glm_euler_seq { - GLM_EULER_XYZ = 0 << 0 | 1 << 2 | 2 << 4, - GLM_EULER_XZY = 0 << 0 | 2 << 2 | 1 << 4, - GLM_EULER_YZX = 1 << 0 | 2 << 2 | 0 << 4, - GLM_EULER_YXZ = 1 << 0 | 0 << 2 | 2 << 4, - GLM_EULER_ZXY = 2 << 0 | 0 << 2 | 1 << 4, - GLM_EULER_ZYX = 2 << 0 | 1 << 2 | 0 << 4 -} glm_euler_seq; - -CGLM_INLINE -glm_euler_seq -glm_euler_order(int ord[3]) { - return (glm_euler_seq)(ord[0] << 0 | ord[1] << 2 | ord[2] << 4); -} - -/*! - * @brief extract euler angles (in radians) using xyz order - * - * @param[in] m affine transform - * @param[out] dest angles vector [x, y, z] - */ -CGLM_INLINE -void -glm_euler_angles(mat4 m, vec3 dest) { - float m00, m01, m10, m11, m20, m21, m22; - float thetaX, thetaY, thetaZ; - - m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; - m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; - m22 = m[2][2]; - - if (m20 < 1.0f) { - if (m20 > -1.0f) { - thetaY = asinf(m20); - thetaX = atan2f(-m21, m22); - thetaZ = atan2f(-m10, m00); - } else { /* m20 == -1 */ - /* Not a unique solution */ - thetaY = -GLM_PI_2f; - thetaX = -atan2f(m01, m11); - thetaZ = 0.0f; - } - } else { /* m20 == +1 */ - thetaY = GLM_PI_2f; - thetaX = atan2f(m01, m11); - thetaZ = 0.0f; - } - - dest[0] = thetaX; - dest[1] = thetaY; - dest[2] = thetaZ; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_xyz(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, czsx, cxcz, sysz; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - czsx = cz * sx; - cxcz = cx * cz; - sysz = sy * sz; - - dest[0][0] = cy * cz; - dest[0][1] = czsx * sy + cx * sz; - dest[0][2] = -cxcz * sy + sx * sz; - dest[1][0] = -cy * sz; - dest[1][1] = cxcz - sx * sysz; - dest[1][2] = czsx + cx * sysz; - dest[2][0] = sy; - dest[2][1] = -cy * sx; - dest[2][2] = cx * cy; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler(vec3 angles, mat4 dest) { - glm_euler_xyz(angles, dest); -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_xzy(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, sxsy, cysx, cxsy, cxcy; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - sxsy = sx * sy; - cysx = cy * sx; - cxsy = cx * sy; - cxcy = cx * cy; - - dest[0][0] = cy * cz; - dest[0][1] = sxsy + cxcy * sz; - dest[0][2] = -cxsy + cysx * sz; - dest[1][0] = -sz; - dest[1][1] = cx * cz; - dest[1][2] = cz * sx; - dest[2][0] = cz * sy; - dest[2][1] = -cysx + cxsy * sz; - dest[2][2] = cxcy + sxsy * sz; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_yxz(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, cycz, sysz, czsy, cysz; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - cycz = cy * cz; - sysz = sy * sz; - czsy = cz * sy; - cysz = cy * sz; - - dest[0][0] = cycz + sx * sysz; - dest[0][1] = cx * sz; - dest[0][2] = -czsy + cysz * sx; - dest[1][0] = -cysz + czsy * sx; - dest[1][1] = cx * cz; - dest[1][2] = cycz * sx + sysz; - dest[2][0] = cx * sy; - dest[2][1] = -sx; - dest[2][2] = cx * cy; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_yzx(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, sxsy, cxcy, cysx, cxsy; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - sxsy = sx * sy; - cxcy = cx * cy; - cysx = cy * sx; - cxsy = cx * sy; - - dest[0][0] = cy * cz; - dest[0][1] = sz; - dest[0][2] = -cz * sy; - dest[1][0] = sxsy - cxcy * sz; - dest[1][1] = cx * cz; - dest[1][2] = cysx + cxsy * sz; - dest[2][0] = cxsy + cysx * sz; - dest[2][1] = -cz * sx; - dest[2][2] = cxcy - sxsy * sz; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_zxy(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, cycz, sxsy, cysz; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - cycz = cy * cz; - sxsy = sx * sy; - cysz = cy * sz; - - dest[0][0] = cycz - sxsy * sz; - dest[0][1] = cz * sxsy + cysz; - dest[0][2] = -cx * sy; - dest[1][0] = -cx * sz; - dest[1][1] = cx * cz; - dest[1][2] = sx; - dest[2][0] = cz * sy + cysz * sx; - dest[2][1] = -cycz * sx + sy * sz; - dest[2][2] = cx * cy; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_zyx(vec3 angles, mat4 dest) { - float cx, cy, cz, - sx, sy, sz, czsx, cxcz, sysz; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - czsx = cz * sx; - cxcz = cx * cz; - sysz = sy * sz; - - dest[0][0] = cy * cz; - dest[0][1] = cy * sz; - dest[0][2] = -sy; - dest[1][0] = czsx * sy - cx * sz; - dest[1][1] = cxcz + sx * sysz; - dest[1][2] = cy * sx; - dest[2][0] = cxcz * sy + sx * sz; - dest[2][1] = -czsx + cx * sysz; - dest[2][2] = cx * cy; - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[in] ord euler order - * @param[out] dest rotation matrix - */ -CGLM_INLINE -void -glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) { - float cx, cy, cz, - sx, sy, sz; - - float cycz, cysz, cysx, cxcy, - czsy, cxcz, czsx, cxsz, - sysz; - - sx = sinf(angles[0]); cx = cosf(angles[0]); - sy = sinf(angles[1]); cy = cosf(angles[1]); - sz = sinf(angles[2]); cz = cosf(angles[2]); - - cycz = cy * cz; cysz = cy * sz; - cysx = cy * sx; cxcy = cx * cy; - czsy = cz * sy; cxcz = cx * cz; - czsx = cz * sx; cxsz = cx * sz; - sysz = sy * sz; - - switch (ord) { - case GLM_EULER_XZY: - dest[0][0] = cycz; - dest[0][1] = sx * sy + cx * cysz; - dest[0][2] = -cx * sy + cysx * sz; - dest[1][0] = -sz; - dest[1][1] = cxcz; - dest[1][2] = czsx; - dest[2][0] = czsy; - dest[2][1] = -cysx + cx * sysz; - dest[2][2] = cxcy + sx * sysz; - break; - case GLM_EULER_XYZ: - dest[0][0] = cycz; - dest[0][1] = czsx * sy + cxsz; - dest[0][2] = -cx * czsy + sx * sz; - dest[1][0] = -cysz; - dest[1][1] = cxcz - sx * sysz; - dest[1][2] = czsx + cx * sysz; - dest[2][0] = sy; - dest[2][1] = -cysx; - dest[2][2] = cxcy; - break; - case GLM_EULER_YXZ: - dest[0][0] = cycz + sx * sysz; - dest[0][1] = cxsz; - dest[0][2] = -czsy + cysx * sz; - dest[1][0] = czsx * sy - cysz; - dest[1][1] = cxcz; - dest[1][2] = cycz * sx + sysz; - dest[2][0] = cx * sy; - dest[2][1] = -sx; - dest[2][2] = cxcy; - break; - case GLM_EULER_YZX: - dest[0][0] = cycz; - dest[0][1] = sz; - dest[0][2] = -czsy; - dest[1][0] = sx * sy - cx * cysz; - dest[1][1] = cxcz; - dest[1][2] = cysx + cx * sysz; - dest[2][0] = cx * sy + cysx * sz; - dest[2][1] = -czsx; - dest[2][2] = cxcy - sx * sysz; - break; - case GLM_EULER_ZXY: - dest[0][0] = cycz - sx * sysz; - dest[0][1] = czsx * sy + cysz; - dest[0][2] = -cx * sy; - dest[1][0] = -cxsz; - dest[1][1] = cxcz; - dest[1][2] = sx; - dest[2][0] = czsy + cysx * sz; - dest[2][1] = -cycz * sx + sysz; - dest[2][2] = cxcy; - break; - case GLM_EULER_ZYX: - dest[0][0] = cycz; - dest[0][1] = cysz; - dest[0][2] = -sy; - dest[1][0] = czsx * sy - cxsz; - dest[1][1] = cxcz + sx * sysz; - dest[1][2] = cysx; - dest[2][0] = cx * czsy + sx * sz; - dest[2][1] = -czsx + cx * sysz; - dest[2][2] = cxcy; - break; - } - - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xyz_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_xyz_quat_lh(angles, dest); -#else - glm_euler_xyz_quat_rh(angles, dest); -#endif -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xzy_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_xzy_quat_lh(angles, dest); -#else - glm_euler_xzy_quat_rh(angles, dest); -#endif -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yxz_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_yxz_quat_lh(angles, dest); -#else - glm_euler_yxz_quat_rh(angles, dest); -#endif -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yzx_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_yzx_quat_lh(angles, dest); -#else - glm_euler_yzx_quat_rh(angles, dest); -#endif -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zxy_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_zxy_quat_lh(angles, dest); -#else - glm_euler_zxy_quat_rh(angles, dest); -#endif -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zyx_quat(vec3 angles, versor dest) { -#ifdef CGLM_FORCE_LEFT_HANDED - glm_euler_zyx_quat_lh(angles, dest); -#else - glm_euler_zyx_quat_rh(angles, dest); -#endif -} - - -#endif /* cglm_euler_h */ diff --git a/external/cglm/frustum.h b/external/cglm/frustum.h deleted file mode 100644 index 5aa3c17..0000000 --- a/external/cglm/frustum.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_frustum_h -#define cglm_frustum_h - -#include "common.h" -#include "plane.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -#define GLM_LBN 0 /* left bottom near */ -#define GLM_LTN 1 /* left top near */ -#define GLM_RTN 2 /* right top near */ -#define GLM_RBN 3 /* right bottom near */ - -#define GLM_LBF 4 /* left bottom far */ -#define GLM_LTF 5 /* left top far */ -#define GLM_RTF 6 /* right top far */ -#define GLM_RBF 7 /* right bottom far */ - -#define GLM_LEFT 0 -#define GLM_RIGHT 1 -#define GLM_BOTTOM 2 -#define GLM_TOP 3 -#define GLM_NEAR 4 -#define GLM_FAR 5 - -/* you can override clip space coords - but you have to provide all with same name - e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ -#ifndef GLM_CUSTOM_CLIPSPACE - -/* near */ -#define GLM_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} -#define GLM_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} -#define GLM_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} -#define GLM_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} - -/* far */ -#define GLM_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} -#define GLM_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} -#define GLM_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} -#define GLM_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} - -#endif - -/*! - * @brief extracts view frustum planes - * - * planes' space: - * 1- if m = proj: View Space - * 2- if m = viewProj: World Space - * 3- if m = MVP: Object Space - * - * You probably want to extract planes in world space so use viewProj as m - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * - * Exracted planes order: [left, right, bottom, top, near, far] - * - * @param[in] m matrix (see brief) - * @param[out] dest extracted view frustum planes (see brief) - */ -CGLM_INLINE -void -glm_frustum_planes(mat4 m, vec4 dest[6]) { - mat4 t; - - glm_mat4_transpose_to(m, t); - - glm_vec4_add(t[3], t[0], dest[0]); /* left */ - glm_vec4_sub(t[3], t[0], dest[1]); /* right */ - glm_vec4_add(t[3], t[1], dest[2]); /* bottom */ - glm_vec4_sub(t[3], t[1], dest[3]); /* top */ - glm_vec4_add(t[3], t[2], dest[4]); /* near */ - glm_vec4_sub(t[3], t[2], dest[5]); /* far */ - - glm_plane_normalize(dest[0]); - glm_plane_normalize(dest[1]); - glm_plane_normalize(dest[2]); - glm_plane_normalize(dest[3]); - glm_plane_normalize(dest[4]); - glm_plane_normalize(dest[5]); -} - -/*! - * @brief extracts view frustum corners using clip-space coordinates - * - * corners' space: - * 1- if m = invViewProj: World Space - * 2- if m = invMVP: Object Space - * - * You probably want to extract corners in world space so use invViewProj - * Computing invViewProj: - * glm_mat4_mul(proj, view, viewProj); - * ... - * glm_mat4_inv(viewProj, invViewProj); - * - * if you have a near coord at i index, you can get it's far coord by i + 4 - * - * Find center coordinates: - * for (j = 0; j < 4; j++) { - * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); - * } - * - * @param[in] invMat matrix (see brief) - * @param[out] dest exracted view frustum corners (see brief) - */ -CGLM_INLINE -void -glm_frustum_corners(mat4 invMat, vec4 dest[8]) { - vec4 c[8]; - - /* indexOf(nearCoord) = indexOf(farCoord) + 4 */ - vec4 csCoords[8] = { - GLM_CSCOORD_LBN, - GLM_CSCOORD_LTN, - GLM_CSCOORD_RTN, - GLM_CSCOORD_RBN, - - GLM_CSCOORD_LBF, - GLM_CSCOORD_LTF, - GLM_CSCOORD_RTF, - GLM_CSCOORD_RBF - }; - - glm_mat4_mulv(invMat, csCoords[0], c[0]); - glm_mat4_mulv(invMat, csCoords[1], c[1]); - glm_mat4_mulv(invMat, csCoords[2], c[2]); - glm_mat4_mulv(invMat, csCoords[3], c[3]); - glm_mat4_mulv(invMat, csCoords[4], c[4]); - glm_mat4_mulv(invMat, csCoords[5], c[5]); - glm_mat4_mulv(invMat, csCoords[6], c[6]); - glm_mat4_mulv(invMat, csCoords[7], c[7]); - - glm_vec4_scale(c[0], 1.0f / c[0][3], dest[0]); - glm_vec4_scale(c[1], 1.0f / c[1][3], dest[1]); - glm_vec4_scale(c[2], 1.0f / c[2][3], dest[2]); - glm_vec4_scale(c[3], 1.0f / c[3][3], dest[3]); - glm_vec4_scale(c[4], 1.0f / c[4][3], dest[4]); - glm_vec4_scale(c[5], 1.0f / c[5][3], dest[5]); - glm_vec4_scale(c[6], 1.0f / c[6][3], dest[6]); - glm_vec4_scale(c[7], 1.0f / c[7][3], dest[7]); -} - -/*! - * @brief finds center of view frustum - * - * @param[in] corners view frustum corners - * @param[out] dest view frustum center - */ -CGLM_INLINE -void -glm_frustum_center(vec4 corners[8], vec4 dest) { - vec4 center; - - glm_vec4_copy(corners[0], center); - - glm_vec4_add(corners[1], center, center); - glm_vec4_add(corners[2], center, center); - glm_vec4_add(corners[3], center, center); - glm_vec4_add(corners[4], center, center); - glm_vec4_add(corners[5], center, center); - glm_vec4_add(corners[6], center, center); - glm_vec4_add(corners[7], center, center); - - glm_vec4_scale(center, 0.125f, dest); -} - -/*! - * @brief finds bounding box of frustum relative to given matrix e.g. view mat - * - * @param[in] corners view frustum corners - * @param[in] m matrix to convert existing conners - * @param[out] box bounding box as array [min, max] - */ -CGLM_INLINE -void -glm_frustum_box(vec4 corners[8], mat4 m, vec3 box[2]) { - vec4 v; - vec3 min, max; - int i; - - glm_vec3_broadcast(FLT_MAX, min); - glm_vec3_broadcast(-FLT_MAX, max); - - for (i = 0; i < 8; i++) { - glm_mat4_mulv(m, corners[i], v); - - min[0] = glm_min(min[0], v[0]); - min[1] = glm_min(min[1], v[1]); - min[2] = glm_min(min[2], v[2]); - - max[0] = glm_max(max[0], v[0]); - max[1] = glm_max(max[1], v[1]); - max[2] = glm_max(max[2], v[2]); - } - - glm_vec3_copy(min, box[0]); - glm_vec3_copy(max, box[1]); -} - -/*! - * @brief finds planes corners which is between near and far planes (parallel) - * - * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will - * find planes' corners but you will need to one more plane. - * Actually you have it, it is near, far or created previously with this func ;) - * - * @param[in] corners view frustum corners - * @param[in] splitDist split distance - * @param[in] farDist far distance (zFar) - * @param[out] planeCorners plane corners [LB, LT, RT, RB] - */ -CGLM_INLINE -void -glm_frustum_corners_at(vec4 corners[8], - float splitDist, - float farDist, - vec4 planeCorners[4]) { - vec4 corner; - float dist, sc; - - /* because distance and scale is same for all */ - dist = glm_vec3_distance(corners[GLM_RTF], corners[GLM_RTN]); - sc = dist * (splitDist / farDist); - - /* left bottom */ - glm_vec4_sub(corners[GLM_LBF], corners[GLM_LBN], corner); - glm_vec4_scale_as(corner, sc, corner); - glm_vec4_add(corners[GLM_LBN], corner, planeCorners[0]); - - /* left top */ - glm_vec4_sub(corners[GLM_LTF], corners[GLM_LTN], corner); - glm_vec4_scale_as(corner, sc, corner); - glm_vec4_add(corners[GLM_LTN], corner, planeCorners[1]); - - /* right top */ - glm_vec4_sub(corners[GLM_RTF], corners[GLM_RTN], corner); - glm_vec4_scale_as(corner, sc, corner); - glm_vec4_add(corners[GLM_RTN], corner, planeCorners[2]); - - /* right bottom */ - glm_vec4_sub(corners[GLM_RBF], corners[GLM_RBN], corner); - glm_vec4_scale_as(corner, sc, corner); - glm_vec4_add(corners[GLM_RBN], corner, planeCorners[3]); -} - -#endif /* cglm_frustum_h */ diff --git a/external/cglm/handed/euler_to_quat_lh.h b/external/cglm/handed/euler_to_quat_lh.h deleted file mode 100644 index 1bb350b..0000000 --- a/external/cglm/handed/euler_to_quat_lh.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_euler_xyz_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_xzy_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yxz_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yzx_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zxy_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zyx_quat_lh(vec3 angles, versor dest); - */ - -/* - Things to note: - The only difference between euler to quat rh vs lh is that the zsin part is negative - */ - -#ifndef cglm_euler_to_quat_lh_h -#define cglm_euler_to_quat_lh_h - -#include "../common.h" - - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order in left hand (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xyz_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = xc * ys * zs + xs * yc * zc; - dest[1] = xc * ys * zc - xs * yc * zs; - dest[2] = xc * yc * zs + xs * ys * zc; - dest[3] = xc * yc * zc - xs * ys * zs; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order in left hand (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xzy_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = -xc * zs * ys + xs * zc * yc; - dest[1] = xc * zc * ys - xs * zs * yc; - dest[2] = xc * zs * yc + xs * zc * ys; - dest[3] = xc * zc * yc + xs * zs * ys; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order in left hand (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yxz_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = yc * xs * zc + ys * xc * zs; - dest[1] = -yc * xs * zs + ys * xc * zc; - dest[2] = yc * xc * zs - ys * xs * zc; - dest[3] = yc * xc * zc + ys * xs * zs; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order in left hand (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yzx_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = yc * zc * xs + ys * zs * xc; - dest[1] = yc * zs * xs + ys * zc * xc; - dest[2] = yc * zs * xc - ys * zc * xs; - dest[3] = yc * zc * xc - ys * zs * xs; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order in left hand (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zxy_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = zc * xs * yc - zs * xc * ys; - dest[1] = zc * xc * ys + zs * xs * yc; - dest[2] = zc * xs * ys + zs * xc * yc; - dest[3] = zc * xc * yc - zs * xs * ys; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order in left hand (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zyx_quat_lh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = -sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = zc * yc * xs - zs * ys * xc; - dest[1] = zc * ys * xc + zs * yc * xs; - dest[2] = -zc * ys * xs + zs * yc * xc; - dest[3] = zc * yc * xc + zs * ys * xs; -} - -#endif /*cglm_euler_to_quat_lh_h*/ diff --git a/external/cglm/handed/euler_to_quat_rh.h b/external/cglm/handed/euler_to_quat_rh.h deleted file mode 100644 index aeb6f81..0000000 --- a/external/cglm/handed/euler_to_quat_rh.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_euler_xyz_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_xzy_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yxz_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_yzx_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zxy_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glm_euler_zyx_quat_rh(vec3 angles, versor dest); - */ - -/* - Things to note: - The only difference between euler to quat rh vs lh is that the zsin part is negative - */ - -#ifndef cglm_euler_to_quat_rh_h -#define cglm_euler_to_quat_rh_h - -#include "../common.h" - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order in right hand (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xyz_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = xc * ys * zs + xs * yc * zc; - dest[1] = xc * ys * zc - xs * yc * zs; - dest[2] = xc * yc * zs + xs * ys * zc; - dest[3] = xc * yc * zc - xs * ys * zs; - -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order in right hand (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_xzy_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = -xc * zs * ys + xs * zc * yc; - dest[1] = xc * zc * ys - xs * zs * yc; - dest[2] = xc * zs * yc + xs * zc * ys; - dest[3] = xc * zc * yc + xs * zs * ys; - -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order in right hand (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yxz_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = yc * xs * zc + ys * xc * zs; - dest[1] = -yc * xs * zs + ys * xc * zc; - dest[2] = yc * xc * zs - ys * xs * zc; - dest[3] = yc * xc * zc + ys * xs * zs; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order in right hand (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_yzx_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = yc * zc * xs + ys * zs * xc; - dest[1] = yc * zs * xs + ys * zc * xc; - dest[2] = yc * zs * xc - ys * zc * xs; - dest[3] = yc * zc * xc - ys * zs * xs; - -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order in right hand (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zxy_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = zc * xs * yc - zs * xc * ys; - dest[1] = zc * xc * ys + zs * xs * yc; - dest[2] = zc * xs * ys + zs * xc * yc; - dest[3] = zc * xc * yc - zs * xs * ys; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order in right hand (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_euler_zyx_quat_rh(vec3 angles, versor dest) { - float xc, yc, zc, - xs, ys, zs; - - xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); - ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); - zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - - dest[0] = zc * yc * xs - zs * ys * xc; - dest[1] = zc * ys * xc + zs * yc * xs; - dest[2] = -zc * ys * xs + zs * yc * xc; - dest[3] = zc * yc * xc + zs * ys * xs; -} - - -#endif /*cglm_euler_to_quat_rh_h*/ diff --git a/external/cglm/io.h b/external/cglm/io.h deleted file mode 100644 index baa80f1..0000000 --- a/external/cglm/io.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_mat4_print(mat4 matrix, FILE *ostream); - CGLM_INLINE void glm_mat3_print(mat3 matrix, FILE *ostream); - CGLM_INLINE void glm_vec4_print(vec4 vec, FILE *ostream); - CGLM_INLINE void glm_ivec4_print(ivec4 vec, FILE *ostream); - CGLM_INLINE void glm_vec3_print(vec3 vec, FILE *ostream); - CGLM_INLINE void glm_ivec3_print(ivec3 vec, FILE *ostream); - CGLM_INLINE void glm_vec2_print(vec2 vec, FILE *ostream); - CGLM_INLINE void glm_ivec2_print(ivec2 vec, FILE *ostream); - CGLM_INLINE void glm_versor_print(versor vec, FILE *ostream); - CGLM_INLINE void glm_arch_print(FILE *ostream); - */ - -/* - cglm tried to enable print functions in debug mode and disable them in - release/production mode to eliminate printing costs. - - if you need to force enable then define CGLM_DEFINE_PRINTS macro not DEBUG one - - Print functions are enabled if: - - - DEBUG or _DEBUG macro is defined (mostly defined automatically in debugging) - - CGLM_DEFINE_PRINTS macro is defined including release/production - which makes enabled printing always - - glmc_ calls for io are always prints - - */ - -/* DEPRECATED: CGLM_NO_PRINTS_NOOP (use CGLM_DEFINE_PRINTS) */ - -#ifndef cglm_io_h -#define cglm_io_h -#if !defined(NDEBUG) \ - || defined(CGLM_DEFINE_PRINTS) || defined(CGLM_LIB_SRC) \ - || defined(CGLM_NO_PRINTS_NOOP) - -#include "common.h" -#include "util.h" - -#include -#include - -#ifndef CGLM_PRINT_PRECISION -# define CGLM_PRINT_PRECISION 5 -#endif - -#ifndef CGLM_PRINT_MAX_TO_SHORT -# define CGLM_PRINT_MAX_TO_SHORT 1e5f -#endif - -#ifndef GLM_TESTS_NO_COLORFUL_OUTPUT -# ifndef CGLM_PRINT_COLOR -# define CGLM_PRINT_COLOR "\033[36m" -# endif -# ifndef CGLM_PRINT_COLOR_RESET -# define CGLM_PRINT_COLOR_RESET "\033[0m" -# endif -#else -# ifndef CGLM_PRINT_COLOR -# define CGLM_PRINT_COLOR -# endif -# ifndef CGLM_PRINT_COLOR_RESET -# define CGLM_PRINT_COLOR_RESET -# endif -#endif - -/*! - * @brief prints current SIMD path in general - * - * @param[in] ostream stream to print e.g. stdout, stderr, FILE ... - */ -CGLM_INLINE -void -glm_arch_print(FILE* __restrict ostream) { - fprintf(ostream, CGLM_PRINT_COLOR "arch: " -#if defined(CGLM_SIMD_WASM) - "wasm SIMD128" -#elif defined(CGLM_SIMD_x86) - "x86 SSE* " -# ifdef __AVX__ - " AVX" -# endif -#elif defined(CGLM_SIMD_ARM) - "arm" -# ifndef __ARM_NEON_FP - " NEON_FP" -# endif -# ifdef CGLM_ARM64 - " ARM64" -# endif -#else - "uncommon" -#endif - CGLM_PRINT_COLOR_RESET); -} - -/*! - * @brief prints current SIMD path in general - * - * @param[in] ostream stream to print e.g. stdout, stderr, FILE ... - */ -CGLM_INLINE -void -glm_arch_print_name(FILE* __restrict ostream) { - fprintf(ostream, CGLM_PRINT_COLOR "\ncglm "); - glm_arch_print(ostream); - fprintf(ostream, "\n\n" CGLM_PRINT_COLOR_RESET); -} - -CGLM_INLINE -void -glm_mat4_print(mat4 matrix, - FILE * __restrict ostream) { - char buff[16]; - int i, j, cw[4], cwi; - -#define m 4 -#define n 4 - - fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n" , m, n); - - cw[0] = cw[1] = cw[2] = cw[3] = 0; - - for (i = 0; i < m; i++) { - for (j = 0; j < n; j++) { - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); - else - cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); - cw[i] = GLM_MAX(cw[i], cwi); - } - } - - for (i = 0; i < m; i++) { - fprintf(ostream, " |"); - - for (j = 0; j < n; j++) - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); - else - fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); - - fprintf(ostream, " |\n"); - } - - fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); - -#undef m -#undef n -} - - -CGLM_INLINE -void -glm_mat3_print(mat3 matrix, - FILE * __restrict ostream) { - char buff[16]; - int i, j, cw[4], cwi; - -#define m 3 -#define n 3 - - fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); - - cw[0] = cw[1] = cw[2] = 0; - - for (i = 0; i < m; i++) { - for (j = 0; j < n; j++) { - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); - else - cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); - cw[i] = GLM_MAX(cw[i], cwi); - } - } - - for (i = 0; i < m; i++) { - fprintf(ostream, " |"); - - for (j = 0; j < n; j++) - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); - else - fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); - - fprintf(ostream, " |\n"); - } - - fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); - -#undef m -#undef n -} - -CGLM_INLINE -void -glm_mat2_print(mat2 matrix, - FILE * __restrict ostream) { - char buff[16]; - int i, j, cw[4], cwi; - -#define m 2 -#define n 2 - - fprintf(ostream, "Matrix (float%dx%d): " CGLM_PRINT_COLOR "\n", m, n); - - cw[0] = cw[1] = 0; - - for (i = 0; i < m; i++) { - for (j = 0; j < n; j++) { - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - cwi = snprintf(buff, sizeof(buff), "% .*f", CGLM_PRINT_PRECISION, (double)matrix[i][j]); - else - cwi = snprintf(buff, sizeof(buff), "% g", (double)matrix[i][j]); - cw[i] = GLM_MAX(cw[i], cwi); - } - } - - for (i = 0; i < m; i++) { - fprintf(ostream, " |"); - - for (j = 0; j < n; j++) - if (matrix[i][j] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % *.*f", cw[j], CGLM_PRINT_PRECISION, (double)matrix[j][i]); - else - fprintf(ostream, " % *g", cw[j], (double)matrix[j][i]); - - fprintf(ostream, " |\n"); - } - - fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); - -#undef m -#undef n -} - -CGLM_INLINE -void -glm_vec4_print(vec4 vec, - FILE * __restrict ostream) { - int i; - -#define m 4 - - fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) { - if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); - else - fprintf(ostream, " % g", (double)vec[i]); - } - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_ivec4_print(ivec4 vec, - FILE * __restrict ostream) { - int i; - -#define m 4 - - fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) - fprintf(ostream, " % d", vec[i]); - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_vec3_print(vec3 vec, - FILE * __restrict ostream) { - int i; - -#define m 3 - - fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) { - if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); - else - fprintf(ostream, " % g", (double)vec[i]); - } - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_ivec3_print(ivec3 vec, - FILE * __restrict ostream) { - int i; - -#define m 3 - - fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) - fprintf(ostream, " % d", vec[i]); - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_vec2_print(vec2 vec, - FILE * __restrict ostream) { - int i; - -#define m 2 - - fprintf(ostream, "Vector (float%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) { - if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); - else - fprintf(ostream, " % g", (double)vec[i]); - } - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_ivec2_print(ivec2 vec, - FILE * __restrict ostream) { - int i; - -#define m 2 - - fprintf(ostream, "Vector (int%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) - fprintf(ostream, " % d", vec[i]); - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_versor_print(versor vec, - FILE * __restrict ostream) { - int i; - -#define m 4 - - fprintf(ostream, "Quaternion (float%d): " CGLM_PRINT_COLOR "\n (", m); - - for (i = 0; i < m; i++) { - if (vec[i] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)vec[i]); - else - fprintf(ostream, " % g", (double)vec[i]); - } - - - fprintf(ostream, " )" CGLM_PRINT_COLOR_RESET "\n\n"); - -#undef m -} - -CGLM_INLINE -void -glm_aabb_print(vec3 bbox[2], - const char * __restrict tag, - FILE * __restrict ostream) { - int i, j; - -#define m 3 - - fprintf(ostream, "AABB (%s): " CGLM_PRINT_COLOR "\n", tag ? tag: "float"); - - for (i = 0; i < 2; i++) { - fprintf(ostream, " ("); - - for (j = 0; j < m; j++) { - if (bbox[i][j] < CGLM_PRINT_MAX_TO_SHORT) - fprintf(ostream, " % .*f", CGLM_PRINT_PRECISION, (double)bbox[i][j]); - else - fprintf(ostream, " % g", (double)bbox[i][j]); - } - - fprintf(ostream, " )\n"); - } - - fprintf(ostream, CGLM_PRINT_COLOR_RESET "\n"); - -#undef m -} - -#else - -#include "common.h" - -#include -#include - -/* NOOP: Remove print from DEBUG */ -#define glm_mat4_print(v, s) (void)v; (void)s; -#define glm_mat3_print(v, s) (void)v; (void)s; -#define glm_mat2_print(v, s) (void)v; (void)s; -#define glm_vec4_print(v, s) (void)v; (void)s; -#define glm_ivec4_print(v, s) (void)v; (void)s; -#define glm_vec3_print(v, s) (void)v; (void)s; -#define glm_ivec3_print(v, s) (void)v; (void)s; -#define glm_vec2_print(v, s) (void)v; (void)s; -#define glm_ivec2_print(v, s) (void)v; (void)s; -#define glm_versor_print(v, s) (void)v; (void)s; -#define glm_aabb_print(v, t, s) (void)v; (void)t; (void)s; -#define glm_arch_print(s) (void)s; -#define glm_arch_print_name(s) (void)s; - -#endif -#endif /* cglm_io_h */ diff --git a/external/cglm/ivec2.h b/external/cglm/ivec2.h deleted file mode 100644 index 8d5ad88..0000000 --- a/external/cglm/ivec2.h +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_IVEC2_ONE_INIT - GLM_IVEC2_ZERO_INIT - GLM_IVEC2_ONE - GLM_IVEC2_ZERO - - Functions: - CGLM_INLINE void glm_ivec2(int * __restrict v, ivec2 dest) - CGLM_INLINE void glm_ivec2_copy(ivec2 a, ivec2 dest) - CGLM_INLINE void glm_ivec2_zero(ivec2 v) - CGLM_INLINE void glm_ivec2_one(ivec2 v) - CGLM_INLINE int glm_ivec2_dot(ivec2 a, ivec2 b) - CGLM_INLINE int glm_ivec2_cross(ivec2 a, ivec2 b) - CGLM_INLINE void glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_adds(ivec2 v, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_subs(ivec2 v, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_scale(ivec2 v, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_divs(ivec2 v, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_addadds(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_subadds(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_muladds(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) - CGLM_INLINE void glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE int glm_ivec2_distance2(ivec2 a, ivec2 b) - CGLM_INLINE float glm_ivec2_distance(ivec2 a, ivec2 b) - CGLM_INLINE void glm_ivec2_fill(ivec2 v, int val); - CGLM_INLINE bool glm_ivec2_eq(ivec2 v, int val); - CGLM_INLINE bool glm_ivec2_eqv(ivec2 a, ivec2 b); - CGLM_INLINE void glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) - CGLM_INLINE void glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) - CGLM_INLINE void glm_ivec2_abs(ivec2 v, ivec2 dest) - */ - -#ifndef cglm_ivec2_h -#define cglm_ivec2_h - -#include "common.h" -#include "util.h" - -#define GLM_IVEC2_ONE_INIT {1, 1} -#define GLM_IVEC2_ZERO_INIT {0, 0} - -#define GLM_IVEC2_ONE ((ivec2)GLM_IVEC2_ONE_INIT) -#define GLM_IVEC2_ZERO ((ivec2)GLM_IVEC2_ZERO_INIT) - -/*! - * @brief init ivec2 using vec3 or vec4 - * - * @param[in] v vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2(int * __restrict v, ivec2 dest) { - dest[0] = v[0]; - dest[1] = v[1]; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] a source vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_copy(ivec2 a, ivec2 dest) { - dest[0] = a[0]; - dest[1] = a[1]; -} - -/*! - * @brief set all members of [v] to zero - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec2_zero(ivec2 v) { - v[0] = v[1] = 0; -} - -/*! - * @brief set all members of [v] to one - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec2_one(ivec2 v) { - v[0] = v[1] = 1; -} - -/*! - * @brief ivec2 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -int -glm_ivec2_dot(ivec2 a, ivec2 b) { - return a[0] * b[0] + a[1] * b[1]; -} - -/*! - * @brief ivec2 cross product - * - * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return Z component of cross product - */ -CGLM_INLINE -int -glm_ivec2_cross(ivec2 a, ivec2 b) { - return a[0] * b[1] - a[1] * b[0]; -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_add(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_adds(ivec2 v, int s, ivec2 dest) { - dest[0] = v[0] + s; - dest[1] = v[1] + s; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_sub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_subs(ivec2 v, int s, ivec2 dest) { - dest[0] = v[0] - s; - dest[1] = v[1] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_mul(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_scale(ivec2 v, int s, ivec2 dest) { - dest[0] = v[0] * s; - dest[1] = v[1] * s; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]/b[0], a[1]/b[1]) - */ -CGLM_INLINE -void -glm_ivec2_div(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] / b[0]; - dest[1] = a[1] / b[1]; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest result = (a[0]/s, a[1]/s) - */ -CGLM_INLINE -void -glm_ivec2_divs(ivec2 v, int s, ivec2 dest) { - dest[0] = v[0] / s; - dest[1] = v[1] / s; -} - -/*! - * @brief mod vector with another component-wise modulo: d = a % b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]%b[0], a[1]%b[1]) - */ -CGLM_INLINE -void -glm_ivec2_mod(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] % b[0]; - dest[1] = a[1] % b[1]; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_ivec2_addadd(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a + s) - */ -CGLM_INLINE -void -glm_ivec2_addadds(ivec2 a, int s, ivec2 dest) { - dest[0] += a[0] + s; - dest[1] += a[1] + s; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a - b) - */ -CGLM_INLINE -void -glm_ivec2_subadd(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[out] dest dest += (a - s) - */ -CGLM_INLINE -void -glm_ivec2_subadds(ivec2 a, int s, ivec2 dest) { - dest[0] += a[0] - s; - dest[1] += a[1] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_ivec2_muladd(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * s) - */ -CGLM_INLINE -void -glm_ivec2_muladds(ivec2 a, int s, ivec2 dest) { - dest[0] += a[0] * s; - dest[1] += a[1] * s; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_ivec2_maxadd(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] += glm_imax(a[0], b[0]); - dest[1] += glm_imax(a[1], b[1]); -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_ivec2_minadd(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] += glm_imin(a[0], b[0]); - dest[1] += glm_imin(a[1], b[1]); -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_ivec2_subsub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a - s) - */ -CGLM_INLINE -void -glm_ivec2_subsubs(ivec2 a, int s, ivec2 dest) { - dest[0] -= a[0] - s; - dest[1] -= a[1] - s; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec2_addsub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec2_addsubs(ivec2 a, int s, ivec2 dest) { - dest[0] -= a[0] + s; - dest[1] -= a[1] + s; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_ivec2_mulsub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * s) - */ -CGLM_INLINE -void -glm_ivec2_mulsubs(ivec2 a, int s, ivec2 dest) { - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_ivec2_maxsub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] -= glm_imax(a[0], b[0]); - dest[1] -= glm_imax(a[1], b[1]); -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_ivec2_minsub(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] -= glm_imin(a[0], b[0]); - dest[1] -= glm_imin(a[1], b[1]); -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glm_ivec2_distance2(ivec2 a, ivec2 b) { - int xd, yd; - xd = a[0] - b[0]; - yd = a[1] - b[1]; - return xd * xd + yd * yd; -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glm_ivec2_distance(ivec2 a, ivec2 b) { - return sqrtf((float)glm_ivec2_distance2(a, b)); -} - - -/*! - * @brief fill a vector with specified value - * - * @param[out] v dest - * @param[in] val value - */ -CGLM_INLINE -void -glm_ivec2_fill(ivec2 v, int val) { - v[0] = v[1] = val; -} - -/*! - * @brief check if vector is equal to value - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_ivec2_eq(ivec2 v, int val) { - return v[0] == val && v[0] == v[1]; -} - -/*! - * @brief check if vector is equal to another - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_ivec2_eqv(ivec2 a, ivec2 b) { - return a[0] == b[0] - && a[1] == b[1]; -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_maxv(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] > b[0] ? a[0] : b[0]; - dest[1] = a[1] > b[1] ? a[1] : b[1]; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_minv(ivec2 a, ivec2 b, ivec2 dest) { - dest[0] = a[0] < b[0] ? a[0] : b[0]; - dest[1] = a[1] < b[1] ? a[1] : b[1]; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in, out] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -void -glm_ivec2_clamp(ivec2 v, int minVal, int maxVal) { - if (v[0] < minVal) - v[0] = minVal; - else if(v[0] > maxVal) - v[0] = maxVal; - - if (v[1] < minVal) - v[1] = minVal; - else if(v[1] > maxVal) - v[1] = maxVal; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec2_abs(ivec2 v, ivec2 dest) { - dest[0] = abs(v[0]); - dest[1] = abs(v[1]); -} - -#endif /* cglm_ivec2_h */ diff --git a/external/cglm/ivec3.h b/external/cglm/ivec3.h deleted file mode 100644 index 67eaa22..0000000 --- a/external/cglm/ivec3.h +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_IVEC3_ONE_INIT - GLM_IVEC3_ZERO_INIT - GLM_IVEC3_ONE - GLM_IVEC3_ZERO - - Functions: - CGLM_INLINE void glm_ivec3(ivec4 v4, ivec3 dest) - CGLM_INLINE void glm_ivec3_copy(ivec3 a, ivec3 dest) - CGLM_INLINE void glm_ivec3_zero(ivec3 v) - CGLM_INLINE void glm_ivec3_one(ivec3 v) - CGLM_INLINE int glm_ivec3_dot(ivec3 a, ivec3 b) - CGLM_INLINE int glm_ivec3_norm2(ivec3 v) - CGLM_INLINE int glm_ivec3_norm(ivec3 v) - CGLM_INLINE void glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_adds(ivec3 v, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_subs(ivec3 v, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_scale(ivec3 v, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_divs(ivec3 v, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_addadds(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_subadds(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_muladds(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) - CGLM_INLINE void glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE int glm_ivec3_distance2(ivec3 a, ivec3 b) - CGLM_INLINE float glm_ivec3_distance(ivec3 a, ivec3 b) - CGLM_INLINE void glm_ivec3_fill(ivec3 v, int val); - CGLM_INLINE bool glm_ivec3_eq(ivec3 v, int val); - CGLM_INLINE bool glm_ivec3_eqv(ivec3 a, ivec3 b); - CGLM_INLINE void glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) - CGLM_INLINE void glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) - CGLM_INLINE void glm_ivec3_abs(ivec3 v, ivec3 dest) - */ - -#ifndef cglm_ivec3_h -#define cglm_ivec3_h - -#include "common.h" -#include "util.h" - -#define GLM_IVEC3_ONE_INIT {1, 1, 1} -#define GLM_IVEC3_ZERO_INIT {0, 0, 0} - -#define GLM_IVEC3_ONE ((ivec3)GLM_IVEC3_ONE_INIT) -#define GLM_IVEC3_ZERO ((ivec3)GLM_IVEC3_ZERO_INIT) - -/*! - * @brief init ivec3 using ivec4 - * - * @param[in] v4 vector4 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3(ivec4 v4, ivec3 dest) { - dest[0] = v4[0]; - dest[1] = v4[1]; - dest[2] = v4[2]; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] a source vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_copy(ivec3 a, ivec3 dest) { - dest[0] = a[0]; - dest[1] = a[1]; - dest[2] = a[2]; -} - -/*! - * @brief set all members of [v] to zero - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec3_zero(ivec3 v) { - v[0] = v[1] = v[2] = 0; -} - -/*! - * @brief set all members of [v] to one - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec3_one(ivec3 v) { - v[0] = v[1] = v[2] = 1; -} - -/*! - * @brief ivec3 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -int -glm_ivec3_dot(ivec3 a, ivec3 b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -int -glm_ivec3_norm2(ivec3 v) { - return glm_ivec3_dot(v, v); -} - -/*! - * @brief euclidean norm (magnitude), also called L2 norm - * this will give magnitude of vector in euclidean space - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -int -glm_ivec3_norm(ivec3 v) { - return (int)sqrtf((float)glm_ivec3_norm2(v)); -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_add(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; - dest[2] = a[2] + b[2]; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_adds(ivec3 v, int s, ivec3 dest) { - dest[0] = v[0] + s; - dest[1] = v[1] + s; - dest[2] = v[2] + s; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_sub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; - dest[2] = a[2] - b[2]; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_subs(ivec3 v, int s, ivec3 dest) { - dest[0] = v[0] - s; - dest[1] = v[1] - s; - dest[2] = v[2] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_mul(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; - dest[2] = a[2] * b[2]; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_scale(ivec3 v, int s, ivec3 dest) { - dest[0] = v[0] * s; - dest[1] = v[1] * s; - dest[2] = v[2] * s; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) - */ -CGLM_INLINE -void -glm_ivec3_div(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] / b[0]; - dest[1] = a[1] / b[1]; - dest[2] = a[2] / b[2]; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s) - */ -CGLM_INLINE -void -glm_ivec3_divs(ivec3 v, int s, ivec3 dest) { - dest[0] = v[0] / s; - dest[1] = v[1] / s; - dest[2] = v[2] / s; -} - -/*! - * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b - * - * Performs element-wise modulo on each component of vectors `a` and `b`. - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]%b[0], a[1]%b[1], a[2]%b[2]) - */ -CGLM_INLINE -void -glm_ivec3_mod(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] % b[0]; - dest[1] = a[1] % b[1]; - dest[2] = a[2] % b[2]; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_ivec3_addadd(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; - dest[2] += a[2] + b[2]; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a + s) - */ -CGLM_INLINE -void -glm_ivec3_addadds(ivec3 a, int s, ivec3 dest) { - dest[0] += a[0] + s; - dest[1] += a[1] + s; - dest[2] += a[2] + s; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a - b) - */ -CGLM_INLINE -void -glm_ivec3_subadd(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; - dest[2] += a[2] - b[2]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[out] dest dest += (a - s) - */ -CGLM_INLINE -void -glm_ivec3_subadds(ivec3 a, int s, ivec3 dest) { - dest[0] += a[0] - s; - dest[1] += a[1] - s; - dest[2] += a[2] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_ivec3_muladd(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; - dest[2] += a[2] * b[2]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * s) - */ -CGLM_INLINE -void -glm_ivec3_muladds(ivec3 a, int s, ivec3 dest) { - dest[0] += a[0] * s; - dest[1] += a[1] * s; - dest[2] += a[2] * s; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_ivec3_maxadd(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] += glm_imax(a[0], b[0]); - dest[1] += glm_imax(a[1], b[1]); - dest[2] += glm_imax(a[2], b[2]); -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_ivec3_minadd(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] += glm_imin(a[0], b[0]); - dest[1] += glm_imin(a[1], b[1]); - dest[2] += glm_imin(a[2], b[2]); -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_ivec3_subsub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; - dest[2] -= a[2] - b[2]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a - s) - */ -CGLM_INLINE -void -glm_ivec3_subsubs(ivec3 a, int s, ivec3 dest) { - dest[0] -= a[0] - s; - dest[1] -= a[1] - s; - dest[2] -= a[2] - s; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec3_addsub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; - dest[2] -= a[2] + b[2]; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec3_addsubs(ivec3 a, int s, ivec3 dest) { - dest[0] -= a[0] + s; - dest[1] -= a[1] + s; - dest[2] -= a[2] + s; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_ivec3_mulsub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; - dest[2] -= a[2] * b[2]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * s) - */ -CGLM_INLINE -void -glm_ivec3_mulsubs(ivec3 a, int s, ivec3 dest) { - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; - dest[2] -= a[2] * s; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_ivec3_maxsub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] -= glm_imax(a[0], b[0]); - dest[1] -= glm_imax(a[1], b[1]); - dest[2] -= glm_imax(a[2], b[2]); -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_ivec3_minsub(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] -= glm_imin(a[0], b[0]); - dest[1] -= glm_imin(a[1], b[1]); - dest[2] -= glm_imin(a[2], b[2]); -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glm_ivec3_distance2(ivec3 a, ivec3 b) { - int xd, yd, zd; - xd = a[0] - b[0]; - yd = a[1] - b[1]; - zd = a[2] - b[2]; - return xd * xd + yd * yd + zd * zd; -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glm_ivec3_distance(ivec3 a, ivec3 b) { - return sqrtf((float)glm_ivec3_distance2(a, b)); -} - -/*! - * @brief fill a vector with specified value - * - * @param[out] v dest - * @param[in] val value - */ -CGLM_INLINE -void -glm_ivec3_fill(ivec3 v, int val) { - v[0] = v[1] = v[2] = val; -} - -/*! - * @brief check if vector is equal to value - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_ivec3_eq(ivec3 v, int val) { - return v[0] == val && v[0] == v[1] && v[0] == v[2]; -} - -/*! - * @brief check if vector is equal to another - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_ivec3_eqv(ivec3 a, ivec3 b) { - return a[0] == b[0] - && a[1] == b[1] - && a[2] == b[2]; -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_maxv(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] > b[0] ? a[0] : b[0]; - dest[1] = a[1] > b[1] ? a[1] : b[1]; - dest[2] = a[2] > b[2] ? a[2] : b[2]; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_minv(ivec3 a, ivec3 b, ivec3 dest) { - dest[0] = a[0] < b[0] ? a[0] : b[0]; - dest[1] = a[1] < b[1] ? a[1] : b[1]; - dest[2] = a[2] < b[2] ? a[2] : b[2]; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in, out] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -void -glm_ivec3_clamp(ivec3 v, int minVal, int maxVal) { - if (v[0] < minVal) - v[0] = minVal; - else if(v[0] > maxVal) - v[0] = maxVal; - - if (v[1] < minVal) - v[1] = minVal; - else if(v[1] > maxVal) - v[1] = maxVal; - - if (v[2] < minVal) - v[2] = minVal; - else if(v[2] > maxVal) - v[2] = maxVal; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec3_abs(ivec3 v, ivec3 dest) { - dest[0] = abs(v[0]); - dest[1] = abs(v[1]); - dest[2] = abs(v[2]); -} - -#endif /* cglm_ivec3_h */ diff --git a/external/cglm/ivec4.h b/external/cglm/ivec4.h deleted file mode 100644 index 6357599..0000000 --- a/external/cglm/ivec4.h +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_IVEC4_ONE_INIT - GLM_IVEC4_ZERO_INIT - GLM_IVEC4_ONE - GLM_IVEC4_ZERO - - Functions: - CGLM_INLINE void glm_ivec4(ivec3 v3, int last, ivec4 dest) - CGLM_INLINE void glm_ivec4_copy(ivec4 a, ivec4 dest) - CGLM_INLINE void glm_ivec4_zero(ivec4 v) - CGLM_INLINE void glm_ivec4_one(ivec4 v) - CGLM_INLINE void glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_adds(ivec4 v, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_subs(ivec4 v, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_scale(ivec4 v, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_addadds(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_subadds(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_muladds(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) - CGLM_INLINE void glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE int glm_ivec4_distance2(ivec4 a, ivec4 b) - CGLM_INLINE float glm_ivec4_distance(ivec4 a, ivec4 b) - CGLM_INLINE void glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) - CGLM_INLINE void glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) - CGLM_INLINE void glm_ivec4_abs(ivec4 v, ivec4 dest) - */ - -#ifndef cglm_ivec4_h -#define cglm_ivec4_h - -#include "common.h" -#include "util.h" - -#define GLM_IVEC4_ONE_INIT {1, 1, 1, 1} -#define GLM_IVEC4_ZERO_INIT {0, 0, 0, 0} - -#define GLM_IVEC4_ONE ((ivec4)GLM_IVEC4_ONE_INIT) -#define GLM_IVEC4_ZERO ((ivec4)GLM_IVEC4_ZERO_INIT) - -/*! - * @brief init ivec4 using ivec3 - * - * @param[in] v3 vector3 - * @param[in] last last item - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4(ivec3 v3, int last, ivec4 dest) { - dest[0] = v3[0]; - dest[1] = v3[1]; - dest[2] = v3[2]; - dest[3] = last; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] a source vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_copy(ivec4 a, ivec4 dest) { - dest[0] = a[0]; - dest[1] = a[1]; - dest[2] = a[2]; - dest[3] = a[3]; -} - -/*! - * @brief set all members of [v] to zero - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec4_zero(ivec4 v) { - v[0] = v[1] = v[2] = v[3] = 0; -} - -/*! - * @brief set all members of [v] to one - * - * @param[out] v vector - */ -CGLM_INLINE -void -glm_ivec4_one(ivec4 v) { - v[0] = v[1] = v[2] = v[3] = 1; -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_add(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; - dest[2] = a[2] + b[2]; - dest[3] = a[3] + b[3]; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_adds(ivec4 v, int s, ivec4 dest) { - dest[0] = v[0] + s; - dest[1] = v[1] + s; - dest[2] = v[2] + s; - dest[3] = v[3] + s; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_sub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; - dest[2] = a[2] - b[2]; - dest[3] = a[3] - b[3]; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_subs(ivec4 v, int s, ivec4 dest) { - dest[0] = v[0] - s; - dest[1] = v[1] - s; - dest[2] = v[2] - s; - dest[3] = v[3] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_mul(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; - dest[2] = a[2] * b[2]; - dest[3] = a[3] * b[3]; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_scale(ivec4 v, int s, ivec4 dest) { - dest[0] = v[0] * s; - dest[1] = v[1] * s; - dest[2] = v[2] * s; - dest[3] = v[3] * s; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_ivec4_addadd(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; - dest[2] += a[2] + b[2]; - dest[3] += a[3] + b[3]; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a + s) - */ -CGLM_INLINE -void -glm_ivec4_addadds(ivec4 a, int s, ivec4 dest) { - dest[0] += a[0] + s; - dest[1] += a[1] + s; - dest[2] += a[2] + s; - dest[3] += a[3] + s; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a - b) - */ -CGLM_INLINE -void -glm_ivec4_subadd(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; - dest[2] += a[2] - b[2]; - dest[3] += a[3] - b[3]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[out] dest dest += (a - s) - */ -CGLM_INLINE -void -glm_ivec4_subadds(ivec4 a, int s, ivec4 dest) { - dest[0] += a[0] - s; - dest[1] += a[1] - s; - dest[2] += a[2] - s; - dest[3] += a[3] - s; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_ivec4_muladd(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; - dest[2] += a[2] * b[2]; - dest[3] += a[3] * b[3]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * s) - */ -CGLM_INLINE -void -glm_ivec4_muladds(ivec4 a, int s, ivec4 dest) { - dest[0] += a[0] * s; - dest[1] += a[1] * s; - dest[2] += a[2] * s; - dest[3] += a[3] * s; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_ivec4_maxadd(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] += glm_imax(a[0], b[0]); - dest[1] += glm_imax(a[1], b[1]); - dest[2] += glm_imax(a[2], b[2]); - dest[3] += glm_imax(a[3], b[3]); -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_ivec4_minadd(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] += glm_imin(a[0], b[0]); - dest[1] += glm_imin(a[1], b[1]); - dest[2] += glm_imin(a[2], b[2]); - dest[3] += glm_imin(a[3], b[3]); -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_ivec4_subsub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; - dest[2] -= a[2] - b[2]; - dest[3] -= a[3] - b[3]; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a - s) - */ -CGLM_INLINE -void -glm_ivec4_subsubs(ivec4 a, int s, ivec4 dest) { - dest[0] -= a[0] - s; - dest[1] -= a[1] - s; - dest[2] -= a[2] - s; - dest[3] -= a[3] - s; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec4_addsub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; - dest[2] -= a[2] + b[2]; - dest[3] -= a[3] + b[3]; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_ivec4_addsubs(ivec4 a, int s, ivec4 dest) { - dest[0] -= a[0] + s; - dest[1] -= a[1] + s; - dest[2] -= a[2] + s; - dest[3] -= a[3] + s; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_ivec4_mulsub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; - dest[2] -= a[2] * b[2]; - dest[3] -= a[3] * b[3]; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * s) - */ -CGLM_INLINE -void -glm_ivec4_mulsubs(ivec4 a, int s, ivec4 dest) { - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; - dest[2] -= a[2] * s; - dest[3] -= a[3] * s; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_ivec4_maxsub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] -= glm_imax(a[0], b[0]); - dest[1] -= glm_imax(a[1], b[1]); - dest[2] -= glm_imax(a[2], b[2]); - dest[3] -= glm_imax(a[3], b[3]); -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_ivec4_minsub(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] -= glm_imin(a[0], b[0]); - dest[1] -= glm_imin(a[1], b[1]); - dest[2] -= glm_imin(a[2], b[2]); - dest[3] -= glm_imin(a[3], b[3]); -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glm_ivec4_distance2(ivec4 a, ivec4 b) { - int xd, yd, zd, wd; - xd = a[0] - b[0]; - yd = a[1] - b[1]; - zd = a[2] - b[2]; - wd = a[3] - b[3]; - return xd * xd + yd * yd + zd * zd + wd * wd; -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glm_ivec4_distance(ivec4 a, ivec4 b) { - return sqrtf((float)glm_ivec4_distance2(a, b)); -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_maxv(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] = a[0] > b[0] ? a[0] : b[0]; - dest[1] = a[1] > b[1] ? a[1] : b[1]; - dest[2] = a[2] > b[2] ? a[2] : b[2]; - dest[3] = a[3] > b[3] ? a[3] : b[3]; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_minv(ivec4 a, ivec4 b, ivec4 dest) { - dest[0] = a[0] < b[0] ? a[0] : b[0]; - dest[1] = a[1] < b[1] ? a[1] : b[1]; - dest[2] = a[2] < b[2] ? a[2] : b[2]; - dest[3] = a[3] < b[3] ? a[3] : b[3]; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in, out] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -void -glm_ivec4_clamp(ivec4 v, int minVal, int maxVal) { - if (v[0] < minVal) - v[0] = minVal; - else if(v[0] > maxVal) - v[0] = maxVal; - - if (v[1] < minVal) - v[1] = minVal; - else if(v[1] > maxVal) - v[1] = maxVal; - - if (v[2] < minVal) - v[2] = minVal; - else if(v[2] > maxVal) - v[2] = maxVal; - - if (v[3] < minVal) - v[3] = minVal; - else if(v[3] > maxVal) - v[3] = maxVal; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_ivec4_abs(ivec4 v, ivec4 dest) { - dest[0] = abs(v[0]); - dest[1] = abs(v[1]); - dest[2] = abs(v[2]); - dest[3] = abs(v[3]); -} - -#endif /* cglm_ivec4_h */ diff --git a/external/cglm/mat2.h b/external/cglm/mat2.h deleted file mode 100644 index 9248460..0000000 --- a/external/cglm/mat2.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT2_IDENTITY_INIT - GLM_MAT2_ZERO_INIT - GLM_MAT2_IDENTITY - GLM_MAT2_ZERO - - Functions: - CGLM_INLINE void glm_mat2_make(float * restrict src, mat2 dest) - CGLM_INLINE void glm_mat2_copy(mat2 mat, mat2 dest) - CGLM_INLINE void glm_mat2_identity(mat2 m) - CGLM_INLINE void glm_mat2_identity_array(mat2 * restrict mats, size_t count) - CGLM_INLINE void glm_mat2_zero(mat2 m) - CGLM_INLINE void glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) - CGLM_INLINE void glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) - CGLM_INLINE void glm_mat2_transpose_to(mat2 mat, mat2 dest) - CGLM_INLINE void glm_mat2_transpose(mat2 m) - CGLM_INLINE void glm_mat2_scale(mat2 m, float s) - CGLM_INLINE void glm_mat2_inv(mat2 mat, mat2 dest) - CGLM_INLINE void glm_mat2_swap_col(mat2 mat, int col1, int col2) - CGLM_INLINE void glm_mat2_swap_row(mat2 mat, int row1, int row2) - CGLM_INLINE float glm_mat2_det(mat2 m) - CGLM_INLINE float glm_mat2_trace(mat2 m) - CGLM_INLINE float glm_mat2_rmc(vec2 r, mat2 m, vec2 c) - */ - -#ifndef cglm_mat2_h -#define cglm_mat2_h - -#include "common.h" -#include "vec2.h" - -#ifdef CGLM_SSE_FP -# include "simd/sse2/mat2.h" -#endif - -#ifdef CGLM_NEON_FP -# include "simd/neon/mat2.h" -#endif - -#ifdef CGLM_SIMD_WASM -# include "simd/wasm/mat2.h" -#endif - -#define GLM_MAT2_IDENTITY_INIT {{1.0f, 0.0f}, {0.0f, 1.0f}} -#define GLM_MAT2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT2_IDENTITY ((mat2)GLM_MAT2_IDENTITY_INIT) -#define GLM_MAT2_ZERO ((mat2)GLM_MAT2_ZERO_INIT) - -/*! - * @brief Create mat2 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat2_make(const float * __restrict src, mat2 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[1][0] = src[2]; - dest[1][1] = src[3]; -} - -/*! - * @brief Copy mat2 (mat) to mat2 (dest). - * - * @param[in] mat mat2 (left, src) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat2_copy(mat2 mat, mat2 dest) { - glm_vec4_ucopy(mat[0], dest[0]); -} - -/*! - * @brief Copy a mat2 identity to mat2 (m), or makes mat2 (m) an identity. - * - * The same thing may be achieved with either of bellow methods, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat2_identity(aStruct->aMatrix); - * - * @code - * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only - * - * // or - * mat2 mat = GLM_MAT2_IDENTITY_INIT; - * @endcode - * - * @param[in, out] m mat2 (src, dest) - */ -CGLM_INLINE -void -glm_mat2_identity(mat2 m) { - CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; - glm_mat2_copy(t, m); -} - -/*! - * @brief Given an array of mat2’s (mats) make each matrix an identity matrix. - * - * @param[in, out] mats Array of mat2’s (must be aligned (16/32) if alignment is not disabled) - * @param[in] count Array size of mats or number of matrices - */ -CGLM_INLINE -void -glm_mat2_identity_array(mat2 * __restrict mats, size_t count) { - CGLM_ALIGN_MAT mat2 t = GLM_MAT2_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat2_copy(t, mats[i]); - } -} - -/*! - * @brief Zero out the mat2 (m). - * - * @param[in, out] m mat2 (src, dest) - */ -CGLM_INLINE -void -glm_mat2_zero(mat2 m) { - CGLM_ALIGN_MAT mat2 t = GLM_MAT2_ZERO_INIT; - glm_mat2_copy(t, m); -} - -/*! - * @brief Multiply mat2 (m1) by mat2 (m2) and store in mat2 (dest). - * - * m1, m2 and dest matrices can be same matrix, it is possible to write this: - * - * @code - * mat2 m = GLM_MAT2_IDENTITY_INIT; - * glm_mat2_mul(m, m, m); - * @endcode - * - * @param[in] m1 mat2 (left) - * @param[in] m2 mat2 (right) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat2_mul(mat2 m1, mat2 m2, mat2 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat2_mul_wasm(m1, m2, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat2_mul_sse2(m1, m2, dest); -#elif defined(CGLM_NEON_FP) - glm_mat2_mul_neon(m1, m2, dest); -#else - float a00 = m1[0][0], a01 = m1[0][1], - a10 = m1[1][0], a11 = m1[1][1], - b00 = m2[0][0], b01 = m2[0][1], - b10 = m2[1][0], b11 = m2[1][1]; - - dest[0][0] = a00 * b00 + a10 * b01; - dest[0][1] = a01 * b00 + a11 * b01; - dest[1][0] = a00 * b10 + a10 * b11; - dest[1][1] = a01 * b10 + a11 * b11; -#endif -} - -/*! - * @brief Multiply mat2 (m) by vec2 (v) and store in vec2 (dest). - * - * @param[in] m mat2 (left) - * @param[in] v vec2 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat2_mulv(mat2 m, vec2 v, vec2 dest) { - dest[0] = m[0][0] * v[0] + m[1][0] * v[1]; - dest[1] = m[0][1] * v[0] + m[1][1] * v[1]; -} - -/*! - * @brief Transpose mat2 (mat) and store in mat2 (dest). - * - * @param[in] mat mat2 (left, src) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat2_transpose_to(mat2 mat, mat2 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat2_transp_wasm(mat, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat2_transp_sse2(mat, dest); -#else - dest[0][0] = mat[0][0]; - dest[0][1] = mat[1][0]; - dest[1][0] = mat[0][1]; - dest[1][1] = mat[1][1]; -#endif -} - -/*! - * @brief Transpose mat2 (m) and store result in the same matrix. - * - * @param[in, out] m mat2 (src, dest) - */ -CGLM_INLINE -void -glm_mat2_transpose(mat2 m) { - float tmp; - tmp = m[0][1]; - m[0][1] = m[1][0]; - m[1][0] = tmp; -} - -/*! - * @brief Multiply mat2 (m) by scalar constant (s). - * - * @param[in, out] m mat2 (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat2_scale(mat2 m, float s) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(m[0], wasm_f32x4_mul(wasm_v128_load(m[0]), - wasm_f32x4_splat(s))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(m[0], _mm_mul_ps(_mm_loadu_ps(m[0]), glmm_set1(s))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), vdupq_n_f32(s))); -#else - m[0][0] = m[0][0] * s; - m[0][1] = m[0][1] * s; - m[1][0] = m[1][0] * s; - m[1][1] = m[1][1] * s; -#endif -} - -/*! - * @brief Inverse mat2 (mat) and store in mat2 (dest). - * - * @param[in] mat mat2 (left, src) - * @param[out] dest destination (result, inverse mat2) - */ -CGLM_INLINE -void -glm_mat2_inv(mat2 mat, mat2 dest) { - float det; - float a = mat[0][0], b = mat[0][1], - c = mat[1][0], d = mat[1][1]; - - det = 1.0f / (a * d - b * c); - - dest[0][0] = d * det; - dest[0][1] = -b * det; - dest[1][0] = -c * det; - dest[1][1] = a * det; -} - -/*! - * @brief Swap two columns in mat2 (mat) and store in same matrix. - * - * @param[in, out] mat mat2 (src, dest) - * @param[in] col1 Column 1 array index - * @param[in] col2 Column 2 array index - */ -CGLM_INLINE -void -glm_mat2_swap_col(mat2 mat, int col1, int col2) { - float a, b; - - a = mat[col1][0]; - b = mat[col1][1]; - - mat[col1][0] = mat[col2][0]; - mat[col1][1] = mat[col2][1]; - - mat[col2][0] = a; - mat[col2][1] = b; -} - -/*! - * @brief Swap two rows in mat2 (mat) and store in same matrix. - * - * @param[in, out] mat mat2 (src, dest) - * @param[in] row1 Row 1 array index - * @param[in] row2 Row 2 array index - */ -CGLM_INLINE -void -glm_mat2_swap_row(mat2 mat, int row1, int row2) { - float a, b; - - a = mat[0][row1]; - b = mat[1][row1]; - - mat[0][row1] = mat[0][row2]; - mat[1][row1] = mat[1][row2]; - - mat[0][row2] = a; - mat[1][row2] = b; -} - -/*! - * @brief Returns mat2 determinant. - * - * @param[in] m mat2 (src) - * - * @return[out] mat2 determinant (float) - */ -CGLM_INLINE -float -glm_mat2_det(mat2 m) { - return m[0][0] * m[1][1] - m[1][0] * m[0][1]; -} - -/*! - * @brief Returns trace of matrix. Which is: - * - * The sum of the elements on the main diagonal from - * upper left corner to the bottom right corner. - * - * @param[in] m mat2 (src) - * - * @return[out] mat2 trace (float) - */ -CGLM_INLINE -float -glm_mat2_trace(mat2 m) { - return m[0][0] + m[1][1]; -} - -/*! - * @brief Helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because M * C = ResC (1x2, column vector), - * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value. - * - * @param[in] r vec2 (2x1, row vector) - * @param[in] m mat2 (2x2, matrix) - * @param[in] c vec2 (1x2, column vector) - * - * @return[out] Scalar value (float, 1x1) - */ -CGLM_INLINE -float -glm_mat2_rmc(vec2 r, mat2 m, vec2 c) { - vec2 tmp; - glm_mat2_mulv(m, c, tmp); - return glm_vec2_dot(r, tmp); -} - -#endif /* cglm_mat2_h */ diff --git a/external/cglm/mat2x3.h b/external/cglm/mat2x3.h deleted file mode 100644 index 0bb8d70..0000000 --- a/external/cglm/mat2x3.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT2X3_ZERO_INIT - GLM_MAT2X3_ZERO - - Functions: - CGLM_INLINE void glm_mat2x3_copy(mat2x3 src, mat2x3 dest); - CGLM_INLINE void glm_mat2x3_zero(mat2x3 m); - CGLM_INLINE void glm_mat2x3_make(const float * __restrict src, mat2x3 dest); - CGLM_INLINE void glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest); - CGLM_INLINE void glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest); - CGLM_INLINE void glm_mat2x3_transpose(mat2x3 src, mat3x2 dest); - CGLM_INLINE void glm_mat2x3_scale(mat2x3 m, float s); - */ - -#ifndef cglm_mat2x3_h -#define cglm_mat2x3_h - -#include "common.h" - -#define GLM_MAT2X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT2X3_ZERO GLM_MAT2X3_ZERO_INIT - -/*! - * @brief Copy mat2x3 (src) to mat2x3 (dest). - * - * @param[in] src mat2x3 (left) - * @param[out] dest destination (result, mat2x3) - */ -CGLM_INLINE -void -glm_mat2x3_copy(mat2x3 src, mat2x3 dest) { - glm_vec3_copy(src[0], dest[0]); - glm_vec3_copy(src[1], dest[1]); -} - -/*! - * @brief Zero out the mat2x3 (m). - * - * @param[in, out] mat2x3 (src, dest) - */ -CGLM_INLINE -void -glm_mat2x3_zero(mat2x3 m) { - CGLM_ALIGN_MAT mat2x3 t = GLM_MAT2X3_ZERO_INIT; - glm_mat2x3_copy(t, m); -} - -/*! - * @brief Create mat2x3 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat2x3) - */ -CGLM_INLINE -void -glm_mat2x3_make(const float * __restrict src, mat2x3 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[0][2] = src[2]; - - dest[1][0] = src[3]; - dest[1][1] = src[4]; - dest[1][2] = src[5]; -} - -/*! - * @brief Multiply mat2x3 (m1) by mat3x2 (m2) and store in mat3 (dest). - * - * @code - * glm_mat2x3_mul(mat2x3, mat3x2, mat3); - * @endcode - * - * @param[in] m1 mat2x3 (left) - * @param[in] m2 mat3x2 (right) - * @param[out] dest destination (result, mat3) - */ -CGLM_INLINE -void -glm_mat2x3_mul(mat2x3 m1, mat3x2 m2, mat3 dest) { - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], - - b00 = m2[0][0], b01 = m2[0][1], - b10 = m2[1][0], b11 = m2[1][1], - b20 = m2[2][0], b21 = m2[2][1]; - - dest[0][0] = a00 * b00 + a10 * b01; - dest[0][1] = a01 * b00 + a11 * b01; - dest[0][2] = a02 * b00 + a12 * b01; - - dest[1][0] = a00 * b10 + a10 * b11; - dest[1][1] = a01 * b10 + a11 * b11; - dest[1][2] = a02 * b10 + a12 * b11; - - dest[2][0] = a00 * b20 + a10 * b21; - dest[2][1] = a01 * b20 + a11 * b21; - dest[2][2] = a02 * b20 + a12 * b21; -} - -/*! - * @brief Multiply mat2x3 (m) by vec2 (v) and store in vec3 (dest). - * - * @param[in] m mat2x3 (left) - * @param[in] v vec2 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat2x3_mulv(mat2x3 m, vec2 v, vec3 dest) { - float v0 = v[0], v1 = v[1]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1; - dest[1] = m[0][1] * v0 + m[1][1] * v1; - dest[2] = m[0][2] * v0 + m[1][2] * v1; -} - -/*! - * @brief Transpose mat2x3 (src) and store in mat3x2 (dest). - * - * @param[in] src mat2x3 (left) - * @param[out] dest destination (result, mat3x2) - */ -CGLM_INLINE -void -glm_mat2x3_transpose(mat2x3 src, mat3x2 dest) { - dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; - dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; - dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; -} - -/*! - * @brief Multiply mat2x3 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] float (scalar) - */ -CGLM_INLINE -void -glm_mat2x3_scale(mat2x3 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; - m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; -} - -#endif diff --git a/external/cglm/mat2x4.h b/external/cglm/mat2x4.h deleted file mode 100644 index fa9adf3..0000000 --- a/external/cglm/mat2x4.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT2X4_ZERO_INIT - GLM_MAT2X4_ZERO - - Functions: - CGLM_INLINE void glm_mat2x4_copy(mat2x4 src, mat2x4 dest); - CGLM_INLINE void glm_mat2x4_zero(mat2x4 m); - CGLM_INLINE void glm_mat2x4_make(const float * __restrict src, mat2x4 dest); - CGLM_INLINE void glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest); - CGLM_INLINE void glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest); - CGLM_INLINE void glm_mat2x4_transpose(mat2x4 src, mat4x2 dest); - CGLM_INLINE void glm_mat2x4_scale(mat2x4 m, float s); - */ - -#ifndef cglm_mat2x4_h -#define cglm_mat2x4_h - -#include "common.h" -#include "vec4.h" - -#define GLM_MAT2X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT2X4_ZERO GLM_MAT2X4_ZERO_INIT - -/*! - * @brief Copy mat2x4 (src) to mat2x4 (dest). - * - * @param[in] src mat2x4 (left) - * @param[out] dest destination (result, mat2x4) - */ -CGLM_INLINE -void -glm_mat2x4_copy(mat2x4 src, mat2x4 dest) { - glm_vec4_ucopy(src[0], dest[0]); - glm_vec4_ucopy(src[1], dest[1]); -} - -/*! - * @brief Zero out the mat2x4 (m). - * - * @param[in, out] mat2x4 (src, dest) - */ -CGLM_INLINE -void -glm_mat2x4_zero(mat2x4 m) { - CGLM_ALIGN_MAT mat2x4 t = GLM_MAT2X4_ZERO_INIT; - glm_mat2x4_copy(t, m); -} - -/*! - * @brief Create mat2x4 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat2x4) - */ -CGLM_INLINE -void -glm_mat2x4_make(const float * __restrict src, mat2x4 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[0][2] = src[2]; - dest[0][3] = src[3]; - - dest[1][0] = src[4]; - dest[1][1] = src[5]; - dest[1][2] = src[6]; - dest[1][3] = src[7]; -} - -/*! - * @brief Multiply mat2x4 (m1) by mat4x2 (m2) and store in mat4 (dest). - * - * @code - * glm_mat2x4_mul(mat2x4, mat4x2, mat4); - * @endcode - * - * @param[in] m1 mat2x4 (left) - * @param[in] m2 mat4x2 (right) - * @param[out] dest destination (result, mat4) - */ -CGLM_INLINE -void -glm_mat2x4_mul(mat2x4 m1, mat4x2 m2, mat4 dest) { - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], - - b00 = m2[0][0], b01 = m2[0][1], - b10 = m2[1][0], b11 = m2[1][1], - b20 = m2[2][0], b21 = m2[2][1], - b30 = m2[3][0], b31 = m2[3][1]; - - dest[0][0] = a00 * b00 + a10 * b01; - dest[0][1] = a01 * b00 + a11 * b01; - dest[0][2] = a02 * b00 + a12 * b01; - dest[0][3] = a03 * b00 + a13 * b01; - - dest[1][0] = a00 * b10 + a10 * b11; - dest[1][1] = a01 * b10 + a11 * b11; - dest[1][2] = a02 * b10 + a12 * b11; - dest[1][3] = a03 * b10 + a13 * b11; - - dest[2][0] = a00 * b20 + a10 * b21; - dest[2][1] = a01 * b20 + a11 * b21; - dest[2][2] = a02 * b20 + a12 * b21; - dest[2][3] = a03 * b20 + a13 * b21; - - dest[3][0] = a00 * b30 + a10 * b31; - dest[3][1] = a01 * b30 + a11 * b31; - dest[3][2] = a02 * b30 + a12 * b31; - dest[3][3] = a03 * b30 + a13 * b31; -} - -/*! - * @brief Multiply mat2x4 (m) by vec2 (v) and store in vec4 (dest). - * - * @param[in] m mat2x4 (left) - * @param[in] v vec2 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat2x4_mulv(mat2x4 m, vec2 v, vec4 dest) { - float v0 = v[0], v1 = v[1]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1; - dest[1] = m[0][1] * v0 + m[1][1] * v1; - dest[2] = m[0][2] * v0 + m[1][2] * v1; - dest[3] = m[0][3] * v0 + m[1][3] * v1; -} - -/*! - * @brief Transpose mat2x4 (src) and store in mat4x2 (dest). - * - * @param[in] src mat2x4 (left) - * @param[out] dest destination (result, mat4x2) - */ -CGLM_INLINE -void -glm_mat2x4_transpose(mat2x4 src, mat4x2 dest) { - dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; - dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; - dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; - dest[3][0] = src[0][3]; dest[3][1] = src[1][3]; -} - -/*! - * @brief Multiply mat2x4 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat2x4_scale(mat2x4 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; - m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; -} - -#endif diff --git a/external/cglm/mat3.h b/external/cglm/mat3.h deleted file mode 100644 index 10b373e..0000000 --- a/external/cglm/mat3.h +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT3_IDENTITY_INIT - GLM_MAT3_ZERO_INIT - GLM_MAT3_IDENTITY - GLM_MAT3_ZERO - glm_mat3_dup(mat, dest) - - Functions: - CGLM_INLINE void glm_mat3_copy(mat3 mat, mat3 dest); - CGLM_INLINE void glm_mat3_identity(mat3 mat); - CGLM_INLINE void glm_mat3_identity_array(mat3 * restrict mat, size_t count); - CGLM_INLINE void glm_mat3_zero(mat3 mat); - CGLM_INLINE void glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest); - CGLM_INLINE void glm_mat3_transpose_to(mat3 m, mat3 dest); - CGLM_INLINE void glm_mat3_transpose(mat3 m); - CGLM_INLINE void glm_mat3_mulv(mat3 m, vec3 v, vec3 dest); - CGLM_INLINE float glm_mat3_trace(mat3 m); - CGLM_INLINE void glm_mat3_quat(mat3 m, versor dest); - CGLM_INLINE void glm_mat3_scale(mat3 m, float s); - CGLM_INLINE float glm_mat3_det(mat3 mat); - CGLM_INLINE void glm_mat3_inv(mat3 mat, mat3 dest); - CGLM_INLINE void glm_mat3_swap_col(mat3 mat, int col1, int col2); - CGLM_INLINE void glm_mat3_swap_row(mat3 mat, int row1, int row2); - CGLM_INLINE float glm_mat3_rmc(vec3 r, mat3 m, vec3 c); - CGLM_INLINE void glm_mat3_make(float * restrict src, mat3 dest); - CGLM_INLINE void glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest); - */ - -#ifndef cglm_mat3_h -#define cglm_mat3_h - -#include "common.h" -#include "vec3.h" - -#ifdef CGLM_SSE_FP -# include "simd/sse2/mat3.h" -#endif - -#ifdef CGLM_SIMD_WASM -# include "simd/wasm/mat3.h" -#endif - -#define GLM_MAT3_IDENTITY_INIT {{1.0f, 0.0f, 0.0f}, \ - {0.0f, 1.0f, 0.0f}, \ - {0.0f, 0.0f, 1.0f}} -#define GLM_MAT3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f}} - - -/* for C only */ -#define GLM_MAT3_IDENTITY ((mat3)GLM_MAT3_IDENTITY_INIT) -#define GLM_MAT3_ZERO ((mat3)GLM_MAT3_ZERO_INIT) - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glm_mat3_dup(mat, dest) glm_mat3_copy(mat, dest) - -/*! - * @brief copy all members of [mat] to [dest] - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat3_copy(mat3 mat, mat3 dest) { - dest[0][0] = mat[0][0]; - dest[0][1] = mat[0][1]; - dest[0][2] = mat[0][2]; - - dest[1][0] = mat[1][0]; - dest[1][1] = mat[1][1]; - dest[1][2] = mat[1][2]; - - dest[2][0] = mat[2][0]; - dest[2][1] = mat[2][1]; - dest[2][2] = mat[2][2]; -} - -/*! - * @brief make given matrix identity. It is identical with below, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat3_identity(aStruct->aMatrix); - * - * @code - * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only - * - * // or - * mat3 mat = GLM_MAT3_IDENTITY_INIT; - * @endcode - * - * @param[in, out] mat destination - */ -CGLM_INLINE -void -glm_mat3_identity(mat3 mat) { - CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; - glm_mat3_copy(t, mat); -} - -/*! - * @brief make given matrix array's each element identity matrix - * - * @param[in, out] mat matrix array (must be aligned (16/32) - * if alignment is not disabled) - * - * @param[in] count count of matrices - */ -CGLM_INLINE -void -glm_mat3_identity_array(mat3 * __restrict mat, size_t count) { - CGLM_ALIGN_MAT mat3 t = GLM_MAT3_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat3_copy(t, mat[i]); - } -} - -/*! - * @brief make given matrix zero. - * - * @param[in, out] mat matrix - */ -CGLM_INLINE -void -glm_mat3_zero(mat3 mat) { - CGLM_ALIGN_MAT mat3 t = GLM_MAT3_ZERO_INIT; - glm_mat3_copy(t, mat); -} - -/*! - * @brief multiply m1 and m2 to dest - * - * m1, m2 and dest matrices can be same matrix, it is possible to write this: - * - * @code - * mat3 m = GLM_MAT3_IDENTITY_INIT; - * glm_mat3_mul(m, m, m); - * @endcode - * - * @param[in] m1 left matrix - * @param[in] m2 right matrix - * @param[out] dest destination matrix - */ -CGLM_INLINE -void -glm_mat3_mul(mat3 m1, mat3 m2, mat3 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat3_mul_wasm(m1, m2, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat3_mul_sse2(m1, m2, dest); -#else - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; -#endif -} - -/*! - * @brief transpose mat3 and store in dest - * - * source matrix will not be transposed unless dest is m - * - * @param[in] m matrix - * @param[out] dest result - */ -CGLM_INLINE -void -glm_mat3_transpose_to(mat3 m, mat3 dest) { - dest[0][0] = m[0][0]; - dest[0][1] = m[1][0]; - dest[0][2] = m[2][0]; - dest[1][0] = m[0][1]; - dest[1][1] = m[1][1]; - dest[1][2] = m[2][1]; - dest[2][0] = m[0][2]; - dest[2][1] = m[1][2]; - dest[2][2] = m[2][2]; -} - -/*! - * @brief transpose mat3 and store result in same matrix - * - * @param[in, out] m source and dest - */ -CGLM_INLINE -void -glm_mat3_transpose(mat3 m) { - CGLM_ALIGN_MAT mat3 tmp; - - tmp[0][1] = m[1][0]; - tmp[0][2] = m[2][0]; - tmp[1][0] = m[0][1]; - tmp[1][2] = m[2][1]; - tmp[2][0] = m[0][2]; - tmp[2][1] = m[1][2]; - - m[0][1] = tmp[0][1]; - m[0][2] = tmp[0][2]; - m[1][0] = tmp[1][0]; - m[1][2] = tmp[1][2]; - m[2][0] = tmp[2][0]; - m[2][1] = tmp[2][1]; -} - -/*! - * @brief multiply mat3 with vec3 (column vector) and store in dest vector - * - * @param[in] m mat3 (left) - * @param[in] v vec3 (right, column vector) - * @param[out] dest vec3 (result, column vector) - */ -CGLM_INLINE -void -glm_mat3_mulv(mat3 m, vec3 v, vec3 dest) { - vec3 res; - res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2]; - res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2]; - res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2]; - glm_vec3_copy(res, dest); -} - -/*! - * @brief trace of matrix - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glm_mat3_trace(mat3 m) { - return m[0][0] + m[1][1] + m[2][2]; -} - -/*! - * @brief convert mat3 to quaternion - * - * @param[in] m rotation matrix - * @param[out] dest destination quaternion - */ -CGLM_INLINE -void -glm_mat3_quat(mat3 m, versor dest) { - float trace, r, rinv; - - /* it seems using like m12 instead of m[1][2] causes extra instructions */ - - trace = m[0][0] + m[1][1] + m[2][2]; - if (trace >= 0.0f) { - r = sqrtf(1.0f + trace); - rinv = 0.5f / r; - - dest[0] = rinv * (m[1][2] - m[2][1]); - dest[1] = rinv * (m[2][0] - m[0][2]); - dest[2] = rinv * (m[0][1] - m[1][0]); - dest[3] = r * 0.5f; - } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { - r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); - rinv = 0.5f / r; - - dest[0] = r * 0.5f; - dest[1] = rinv * (m[0][1] + m[1][0]); - dest[2] = rinv * (m[0][2] + m[2][0]); - dest[3] = rinv * (m[1][2] - m[2][1]); - } else if (m[1][1] >= m[2][2]) { - r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); - rinv = 0.5f / r; - - dest[0] = rinv * (m[0][1] + m[1][0]); - dest[1] = r * 0.5f; - dest[2] = rinv * (m[1][2] + m[2][1]); - dest[3] = rinv * (m[2][0] - m[0][2]); - } else { - r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); - rinv = 0.5f / r; - - dest[0] = rinv * (m[0][2] + m[2][0]); - dest[1] = rinv * (m[1][2] + m[2][1]); - dest[2] = r * 0.5f; - dest[3] = rinv * (m[0][1] - m[1][0]); - } -} - -/*! - * @brief scale (multiply with scalar) matrix - * - * multiply matrix with scalar - * - * @param[in, out] m matrix - * @param[in] s scalar - */ -CGLM_INLINE -void -glm_mat3_scale(mat3 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; - m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; - m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; -} - -/*! - * @brief mat3 determinant - * - * @param[in] mat matrix - * - * @return determinant - */ -CGLM_INLINE -float -glm_mat3_det(mat3 mat) { - float a = mat[0][0], b = mat[0][1], c = mat[0][2], - d = mat[1][0], e = mat[1][1], f = mat[1][2], - g = mat[2][0], h = mat[2][1], i = mat[2][2]; - - return a * (e * i - h * f) - d * (b * i - h * c) + g * (b * f - e * c); -} - -/*! - * @brief inverse mat3 and store in dest - * - * @param[in] mat matrix - * @param[out] dest inverse matrix - */ -CGLM_INLINE -void -glm_mat3_inv(mat3 mat, mat3 dest) { - float a = mat[0][0], b = mat[0][1], c = mat[0][2], - d = mat[1][0], e = mat[1][1], f = mat[1][2], - g = mat[2][0], h = mat[2][1], i = mat[2][2], - - c1 = e * i - f * h, c2 = d * i - g * f, c3 = d * h - g * e, - idt = 1.0f / (a * c1 - b * c2 + c * c3), ndt = -idt; - - dest[0][0] = idt * c1; - dest[0][1] = ndt * (b * i - h * c); - dest[0][2] = idt * (b * f - e * c); - dest[1][0] = ndt * c2; - dest[1][1] = idt * (a * i - g * c); - dest[1][2] = ndt * (a * f - d * c); - dest[2][0] = idt * c3; - dest[2][1] = ndt * (a * h - g * b); - dest[2][2] = idt * (a * e - d * b); -} - -/*! - * @brief swap two matrix columns - * - * @param[in,out] mat matrix - * @param[in] col1 col1 - * @param[in] col2 col2 - */ -CGLM_INLINE -void -glm_mat3_swap_col(mat3 mat, int col1, int col2) { - vec3 tmp; - glm_vec3_copy(mat[col1], tmp); - glm_vec3_copy(mat[col2], mat[col1]); - glm_vec3_copy(tmp, mat[col2]); -} - -/*! - * @brief swap two matrix rows - * - * @param[in,out] mat matrix - * @param[in] row1 row1 - * @param[in] row2 row2 - */ -CGLM_INLINE -void -glm_mat3_swap_row(mat3 mat, int row1, int row2) { - vec3 tmp; - tmp[0] = mat[0][row1]; - tmp[1] = mat[1][row1]; - tmp[2] = mat[2][row1]; - - mat[0][row1] = mat[0][row2]; - mat[1][row1] = mat[1][row2]; - mat[2][row1] = mat[2][row2]; - - mat[0][row2] = tmp[0]; - mat[1][row2] = tmp[1]; - mat[2][row2] = tmp[2]; -} - -/*! - * @brief helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because R * M = Matrix1x3 (row vector), - * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) - * - * @param[in] r row vector or matrix1x3 - * @param[in] m matrix3x3 - * @param[in] c column vector or matrix3x1 - * - * @return scalar value e.g. Matrix1x1 - */ -CGLM_INLINE -float -glm_mat3_rmc(vec3 r, mat3 m, vec3 c) { - vec3 tmp; - glm_mat3_mulv(m, c, tmp); - return glm_vec3_dot(r, tmp); -} - -/*! - * @brief Create mat3 matrix from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest matrix - */ -CGLM_INLINE -void -glm_mat3_make(const float * __restrict src, mat3 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[0][2] = src[2]; - - dest[1][0] = src[3]; - dest[1][1] = src[4]; - dest[1][2] = src[5]; - - dest[2][0] = src[6]; - dest[2][1] = src[7]; - dest[2][2] = src[8]; -} - -/*! - * @brief Create mat3 matrix from texture transform parameters - * - * @param[in] sx scale x - * @param[in] sy scale y - * @param[in] rot rotation in radians CCW/RH - * @param[in] tx translate x - * @param[in] ty translate y - * @param[out] dest texture transform matrix - */ -CGLM_INLINE -void -glm_mat3_textrans(float sx, float sy, float rot, float tx, float ty, mat3 dest) { - float c, s; - - c = cosf(rot); - s = sinf(rot); - - glm_mat3_identity(dest); - - dest[0][0] = c * sx; - dest[0][1] = -s * sy; - dest[1][0] = s * sx; - dest[1][1] = c * sy; - dest[2][0] = tx; - dest[2][1] = ty; -} - -#endif /* cglm_mat3_h */ diff --git a/external/cglm/mat3x2.h b/external/cglm/mat3x2.h deleted file mode 100644 index 52173c0..0000000 --- a/external/cglm/mat3x2.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT3X2_ZERO_INIT - GLM_MAT3X2_ZERO - - Functions: - CGLM_INLINE void glm_mat3x2_copy(mat3x2 src, mat3x2 dest); - CGLM_INLINE void glm_mat3x2_zero(mat3x2 m); - CGLM_INLINE void glm_mat3x2_make(const float * __restrict src, mat3x2 dest); - CGLM_INLINE void glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest); - CGLM_INLINE void glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest); - CGLM_INLINE void glm_mat3x2_transpose(mat3x2 src, mat2x3 dest); - CGLM_INLINE void glm_mat3x2_scale(mat3x2 m, float s); - */ - -#ifndef cglm_mat3x2_h -#define cglm_mat3x2_h - -#include "common.h" - -#define GLM_MAT3X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT3X2_ZERO GLM_MAT3X2_ZERO_INIT - -/*! - * @brief Copy mat3x2 (src) to mat3x2 (dest). - * - * @param[in] src mat3x2 (left) - * @param[out] dest destination (result, mat3x2) - */ -CGLM_INLINE -void -glm_mat3x2_copy(mat3x2 src, mat3x2 dest) { - glm_vec2_copy(src[0], dest[0]); - glm_vec2_copy(src[1], dest[1]); - glm_vec2_copy(src[2], dest[2]); -} - -/*! - * @brief Zero out the mat3x2 (m). - * - * @param[in, out] mat3x2 (src, dest) - */ -CGLM_INLINE -void -glm_mat3x2_zero(mat3x2 m) { - CGLM_ALIGN_MAT mat3x2 t = GLM_MAT3X2_ZERO_INIT; - glm_mat3x2_copy(t, m); -} - -/*! - * @brief Create mat3x2 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat3x2) - */ -CGLM_INLINE -void -glm_mat3x2_make(const float * __restrict src, mat3x2 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - - dest[1][0] = src[2]; - dest[1][1] = src[3]; - - dest[2][0] = src[4]; - dest[2][1] = src[5]; -} - -/*! - * @brief Multiply mat3x2 (m1) by mat2x3 (m2) and store in mat2 (dest). - * - * @code - * glm_mat3x2_mul(mat3x2, mat2x3, mat2); - * @endcode - * - * @param[in] m1 mat3x2 (left) - * @param[in] m2 mat2x3 (right) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat3x2_mul(mat3x2 m1, mat2x3 m2, mat2 dest) { - float a00 = m1[0][0], a01 = m1[0][1], - a10 = m1[1][0], a11 = m1[1][1], - a20 = m1[2][0], a21 = m1[2][1], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; -} - -/*! - * @brief Multiply mat3x2 (m) by vec3 (v) and store in vec2 (dest). - * - * @param[in] m mat3x2 (left) - * @param[in] v vec3 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat3x2_mulv(mat3x2 m, vec3 v, vec2 dest) { - float v0 = v[0], v1 = v[1], v2 = v[2]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2; - dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2; -} - -/*! - * @brief Transpose mat3x2 (src) and store in mat2x3 (dest). - * - * @param[in] src mat3x2 (left) - * @param[out] dest destination (result, mat2x3) - */ -CGLM_INLINE -void -glm_mat3x2_transpose(mat3x2 src, mat2x3 dest) { - dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; - dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; -} - -/*! - * @brief Multiply mat3x2 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat3x2_scale(mat3x2 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[1][0] *= s; - m[1][1] *= s; m[2][0] *= s; m[2][1] *= s; -} - -#endif diff --git a/external/cglm/mat3x4.h b/external/cglm/mat3x4.h deleted file mode 100644 index 52d8e7e..0000000 --- a/external/cglm/mat3x4.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT3X4_ZERO_INIT - GLM_MAT3X4_ZERO - - Functions: - CGLM_INLINE void glm_mat3x4_copy(mat3x4 src, mat3x4 dest); - CGLM_INLINE void glm_mat3x4_zero(mat3x4 m); - CGLM_INLINE void glm_mat3x4_make(const float * __restrict src, mat3x4 dest); - CGLM_INLINE void glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest); - CGLM_INLINE void glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest); - CGLM_INLINE void glm_mat3x4_transpose(mat3x4 src, mat4x3 dest); - CGLM_INLINE void glm_mat3x4_scale(mat3x4 m, float s); - */ - -#ifndef cglm_mat3x4_h -#define cglm_mat3x4_h - -#include "common.h" - -#define GLM_MAT3X4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT3X4_ZERO GLM_MAT3X4_ZERO_INIT - -/*! - * @brief Copy mat3x4 (src) to mat3x4 (dest). - * - * @param[in] src mat3x4 (left) - * @param[out] dest destination (result, mat3x4) - */ -CGLM_INLINE -void -glm_mat3x4_copy(mat3x4 src, mat3x4 dest) { - glm_vec4_ucopy(src[0], dest[0]); - glm_vec4_ucopy(src[1], dest[1]); - glm_vec4_ucopy(src[2], dest[2]); -} - -/*! - * @brief Zero out the mat3x4 (m). - * - * @param[in, out] mat3x4 (src, dest) - */ -CGLM_INLINE -void -glm_mat3x4_zero(mat3x4 m) { - CGLM_ALIGN_MAT mat3x4 t = GLM_MAT3X4_ZERO_INIT; - glm_mat3x4_copy(t, m); -} - -/*! - * @brief Create mat3x4 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat3x4) - */ -CGLM_INLINE -void -glm_mat3x4_make(const float * __restrict src, mat3x4 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[0][2] = src[2]; - dest[0][3] = src[3]; - - dest[1][0] = src[4]; - dest[1][1] = src[5]; - dest[1][2] = src[6]; - dest[1][3] = src[7]; - - dest[2][0] = src[8]; - dest[2][1] = src[9]; - dest[2][2] = src[10]; - dest[2][3] = src[11]; -} - -/*! - * @brief Multiply mat3x4 (m1) by mat4x3 (m2) and store in mat4 (dest). - * - * @code - * glm_mat3x4_mul(mat3x4, mat4x3, mat4); - * @endcode - * - * @param[in] m1 mat3x4 (left) - * @param[in] m2 mat4x3 (right) - * @param[out] dest destination (result, mat4) - */ -CGLM_INLINE -void -glm_mat3x4_mul(mat3x4 m1, mat4x3 m2, mat4 dest) { - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], - b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02; - dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12; - dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12; - - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22; - dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22; - - dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32; - dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32; - dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32; - dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32; -} - -/*! - * @brief Multiply mat3x4 (m) by vec3 (v) and store in vec4 (dest). - * - * @param[in] m mat3x4 (left) - * @param[in] v vec3 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat3x4_mulv(mat3x4 m, vec3 v, vec4 dest) { - float v0 = v[0], v1 = v[1], v2 = v[2]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2; - dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2; - dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2; - dest[3] = m[0][3] * v0 + m[1][3] * v1 + m[2][3] * v2; -} - -/*! - * @brief Transpose mat3x4 (src) and store in mat4x3 (dest). - * - * @param[in] src mat3x4 (left) - * @param[out] dest destination (result, mat4x3) - */ -CGLM_INLINE -void -glm_mat3x4_transpose(mat3x4 src, mat4x3 dest) { - dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; - dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; - dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2]; - dest[3][0] = src[0][3]; dest[3][1] = src[1][3]; dest[3][2] = src[2][3]; -} - -/*! - * @brief Multiply mat3x4 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat3x4_scale(mat3x4 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; - m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; - m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s; -} - -#endif diff --git a/external/cglm/mat4.h b/external/cglm/mat4.h deleted file mode 100644 index c3fe7fd..0000000 --- a/external/cglm/mat4.h +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * Most of functions in this header are optimized manually with SIMD - * if available. You dont need to call/incude SIMD headers manually - */ - -/* - Macros: - GLM_MAT4_IDENTITY_INIT - GLM_MAT4_ZERO_INIT - GLM_MAT4_IDENTITY - GLM_MAT4_ZERO - - Functions: - CGLM_INLINE void glm_mat4_ucopy(mat4 mat, mat4 dest); - CGLM_INLINE void glm_mat4_copy(mat4 mat, mat4 dest); - CGLM_INLINE void glm_mat4_identity(mat4 mat); - CGLM_INLINE void glm_mat4_identity_array(mat4 * restrict mat, size_t count); - CGLM_INLINE void glm_mat4_zero(mat4 mat); - CGLM_INLINE void glm_mat4_pick3(mat4 mat, mat3 dest); - CGLM_INLINE void glm_mat4_pick3t(mat4 mat, mat3 dest); - CGLM_INLINE void glm_mat4_ins3(mat3 mat, mat4 dest); - CGLM_INLINE void glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest); - CGLM_INLINE void glm_mat4_mulN(mat4 *matrices[], int len, mat4 dest); - CGLM_INLINE void glm_mat4_mulv(mat4 m, vec4 v, vec4 dest); - CGLM_INLINE void glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest); - CGLM_INLINE float glm_mat4_trace(mat4 m); - CGLM_INLINE float glm_mat4_trace3(mat4 m); - CGLM_INLINE void glm_mat4_quat(mat4 m, versor dest) ; - CGLM_INLINE void glm_mat4_transpose_to(mat4 m, mat4 dest); - CGLM_INLINE void glm_mat4_transpose(mat4 m); - CGLM_INLINE void glm_mat4_scale_p(mat4 m, float s); - CGLM_INLINE void glm_mat4_scale(mat4 m, float s); - CGLM_INLINE float glm_mat4_det(mat4 mat); - CGLM_INLINE void glm_mat4_inv(mat4 mat, mat4 dest); - CGLM_INLINE void glm_mat4_inv_fast(mat4 mat, mat4 dest); - CGLM_INLINE void glm_mat4_swap_col(mat4 mat, int col1, int col2); - CGLM_INLINE void glm_mat4_swap_row(mat4 mat, int row1, int row2); - CGLM_INLINE float glm_mat4_rmc(vec4 r, mat4 m, vec4 c); - CGLM_INLINE void glm_mat4_make(float * restrict src, mat4 dest); - CGLM_INLINE void glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest); - */ - -#ifndef cglm_mat_h -#define cglm_mat_h - -#include "common.h" -#include "vec4.h" -#include "vec3.h" - -#ifdef CGLM_SSE_FP -# include "simd/sse2/mat4.h" -#endif - -#ifdef CGLM_AVX_FP -# include "simd/avx/mat4.h" -#endif - -#ifdef CGLM_NEON_FP -# include "simd/neon/mat4.h" -#endif - -#ifdef CGLM_SIMD_WASM -# include "simd/wasm/mat4.h" -#endif - -#ifndef NDEBUG -# include -#endif - -#define GLM_MAT4_IDENTITY_INIT {{1.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 1.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 1.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 1.0f}} - -#define GLM_MAT4_ZERO_INIT {{0.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT4_IDENTITY ((mat4)GLM_MAT4_IDENTITY_INIT) -#define GLM_MAT4_ZERO ((mat4)GLM_MAT4_ZERO_INIT) - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glm_mat4_udup(mat, dest) glm_mat4_ucopy(mat, dest) -#define glm_mat4_dup(mat, dest) glm_mat4_copy(mat, dest) - -/* DEPRECATED! default is precise now. */ -#define glm_mat4_inv_precise(mat, dest) glm_mat4_inv(mat, dest) - -/*! - * @brief copy all members of [mat] to [dest] - * - * matrix may not be aligned, u stands for unaligned, this may be useful when - * copying a matrix from external source e.g. asset importer... - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat4_ucopy(mat4 mat, mat4 dest) { - dest[0][0] = mat[0][0]; dest[1][0] = mat[1][0]; - dest[0][1] = mat[0][1]; dest[1][1] = mat[1][1]; - dest[0][2] = mat[0][2]; dest[1][2] = mat[1][2]; - dest[0][3] = mat[0][3]; dest[1][3] = mat[1][3]; - - dest[2][0] = mat[2][0]; dest[3][0] = mat[3][0]; - dest[2][1] = mat[2][1]; dest[3][1] = mat[3][1]; - dest[2][2] = mat[2][2]; dest[3][2] = mat[3][2]; - dest[2][3] = mat[2][3]; dest[3][3] = mat[3][3]; -} - -/*! - * @brief copy all members of [mat] to [dest] - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat4_copy(mat4 mat, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest[0], glmm_load(mat[0])); - glmm_store(dest[1], glmm_load(mat[1])); - glmm_store(dest[2], glmm_load(mat[2])); - glmm_store(dest[3], glmm_load(mat[3])); -#elif defined(__AVX__) - glmm_store256(dest[0], glmm_load256(mat[0])); - glmm_store256(dest[2], glmm_load256(mat[2])); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest[0], glmm_load(mat[0])); - glmm_store(dest[1], glmm_load(mat[1])); - glmm_store(dest[2], glmm_load(mat[2])); - glmm_store(dest[3], glmm_load(mat[3])); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest[0], vld1q_f32(mat[0])); - vst1q_f32(dest[1], vld1q_f32(mat[1])); - vst1q_f32(dest[2], vld1q_f32(mat[2])); - vst1q_f32(dest[3], vld1q_f32(mat[3])); -#else - glm_mat4_ucopy(mat, dest); -#endif -} - -/*! - * @brief make given matrix identity. It is identical with below, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat4_identity(aStruct->aMatrix); - * - * @code - * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only - * - * // or - * mat4 mat = GLM_MAT4_IDENTITY_INIT; - * @endcode - * - * @param[in, out] mat destination - */ -CGLM_INLINE -void -glm_mat4_identity(mat4 mat) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - glm_mat4_copy(t, mat); -} - -/*! - * @brief make given matrix array's each element identity matrix - * - * @param[in, out] mat matrix array (must be aligned (16/32) - * if alignment is not disabled) - * - * @param[in] count count of matrices - */ -CGLM_INLINE -void -glm_mat4_identity_array(mat4 * __restrict mat, size_t count) { - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat4_copy(t, mat[i]); - } -} - -/*! - * @brief make given matrix zero. - * - * @param[in, out] mat matrix - */ -CGLM_INLINE -void -glm_mat4_zero(mat4 mat) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_128 x0; - x0 = wasm_f32x4_const_splat(0.f); - glmm_store(mat[0], x0); - glmm_store(mat[1], x0); - glmm_store(mat[2], x0); - glmm_store(mat[3], x0); -#elif defined(__AVX__) - __m256 y0; - y0 = _mm256_setzero_ps(); - glmm_store256(mat[0], y0); - glmm_store256(mat[2], y0); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_128 x0; - x0 = _mm_setzero_ps(); - glmm_store(mat[0], x0); - glmm_store(mat[1], x0); - glmm_store(mat[2], x0); - glmm_store(mat[3], x0); -#elif defined(CGLM_NEON_FP) - glmm_128 x0; - x0 = vdupq_n_f32(0.0f); - vst1q_f32(mat[0], x0); - vst1q_f32(mat[1], x0); - vst1q_f32(mat[2], x0); - vst1q_f32(mat[3], x0); -#else - CGLM_ALIGN_MAT mat4 t = GLM_MAT4_ZERO_INIT; - glm_mat4_copy(t, mat); -#endif -} - -/*! - * @brief copy upper-left of mat4 to mat3 - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat4_pick3(mat4 mat, mat3 dest) { - dest[0][0] = mat[0][0]; - dest[0][1] = mat[0][1]; - dest[0][2] = mat[0][2]; - - dest[1][0] = mat[1][0]; - dest[1][1] = mat[1][1]; - dest[1][2] = mat[1][2]; - - dest[2][0] = mat[2][0]; - dest[2][1] = mat[2][1]; - dest[2][2] = mat[2][2]; -} - -/*! - * @brief copy upper-left of mat4 to mat3 (transposed) - * - * the postfix t stands for transpose - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat4_pick3t(mat4 mat, mat3 dest) { - dest[0][0] = mat[0][0]; - dest[0][1] = mat[1][0]; - dest[0][2] = mat[2][0]; - - dest[1][0] = mat[0][1]; - dest[1][1] = mat[1][1]; - dest[1][2] = mat[2][1]; - - dest[2][0] = mat[0][2]; - dest[2][1] = mat[1][2]; - dest[2][2] = mat[2][2]; -} - -/*! - * @brief copy mat3 to mat4's upper-left - * - * @param[in] mat source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_mat4_ins3(mat3 mat, mat4 dest) { - dest[0][0] = mat[0][0]; - dest[0][1] = mat[0][1]; - dest[0][2] = mat[0][2]; - - dest[1][0] = mat[1][0]; - dest[1][1] = mat[1][1]; - dest[1][2] = mat[1][2]; - - dest[2][0] = mat[2][0]; - dest[2][1] = mat[2][1]; - dest[2][2] = mat[2][2]; -} - -/*! - * @brief multiply m1 and m2 to dest - * - * m1, m2 and dest matrices can be same matrix, it is possible to write this: - * - * @code - * mat4 m = GLM_MAT4_IDENTITY_INIT; - * glm_mat4_mul(m, m, m); - * @endcode - * - * @param[in] m1 left matrix - * @param[in] m2 right matrix - * @param[out] dest destination matrix - */ -CGLM_INLINE -void -glm_mat4_mul(mat4 m1, mat4 m2, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_mul_wasm(m1, m2, dest); -#elif defined(__AVX__) - glm_mat4_mul_avx(m1, m2, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_mul_sse2(m1, m2, dest); -#elif defined(CGLM_NEON_FP) - glm_mat4_mul_neon(m1, m2, dest); -#else - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], a03 = m1[0][3], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], a13 = m1[1][3], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], a23 = m1[2][3], - a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], a33 = m1[3][3], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3], - b30 = m2[3][0], b31 = m2[3][1], b32 = m2[3][2], b33 = m2[3][3]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; - dest[0][3] = a03 * b00 + a13 * b01 + a23 * b02 + a33 * b03; - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; - dest[1][3] = a03 * b10 + a13 * b11 + a23 * b12 + a33 * b13; - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; - dest[2][3] = a03 * b20 + a13 * b21 + a23 * b22 + a33 * b23; - dest[3][0] = a00 * b30 + a10 * b31 + a20 * b32 + a30 * b33; - dest[3][1] = a01 * b30 + a11 * b31 + a21 * b32 + a31 * b33; - dest[3][2] = a02 * b30 + a12 * b31 + a22 * b32 + a32 * b33; - dest[3][3] = a03 * b30 + a13 * b31 + a23 * b32 + a33 * b33; -#endif -} - -/*! - * @brief mupliply N mat4 matrices and store result in dest - * - * this function lets you multiply multiple (more than two or more...) matrices - *

multiplication will be done in loop, this may reduce instructions - * size but if len is too small then compiler may unroll whole loop, - * usage: - * @code - * mat4 m1, m2, m3, m4, res; - * - * glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4, res); - * @endcode - * - * @warning matrices parameter is pointer array not mat4 array! - * - * @param[in] matrices mat4 * array - * @param[in] len matrices count - * @param[out] dest result - */ -CGLM_INLINE -void -glm_mat4_mulN(mat4 * __restrict matrices[], uint32_t len, mat4 dest) { - uint32_t i; - -#ifndef NDEBUG - assert(len > 1 && "there must be least 2 matrices to go!"); -#endif - - glm_mat4_mul(*matrices[0], *matrices[1], dest); - - for (i = 2; i < len; i++) - glm_mat4_mul(dest, *matrices[i], dest); -} - -/*! - * @brief multiply mat4 with vec4 (column vector) and store in dest vector - * - * @param[in] m mat4 (left) - * @param[in] v vec4 (right, column vector) - * @param[out] dest vec4 (result, column vector) - */ -CGLM_INLINE -void -glm_mat4_mulv(mat4 m, vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_mulv_wasm(m, v, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_mulv_sse2(m, v, dest); -#elif defined(CGLM_NEON_FP) - glm_mat4_mulv_neon(m, v, dest); -#else - vec4 res; - res[0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3]; - res[1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3]; - res[2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3]; - res[3] = m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]; - glm_vec4_copy(res, dest); -#endif -} - -/*! - * @brief trace of matrix - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glm_mat4_trace(mat4 m) { - return m[0][0] + m[1][1] + m[2][2] + m[3][3]; -} - -/*! - * @brief trace of matrix (rotation part) - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glm_mat4_trace3(mat4 m) { - return m[0][0] + m[1][1] + m[2][2]; -} - -/*! - * @brief convert mat4's rotation part to quaternion - * - * @param[in] m affine matrix - * @param[out] dest destination quaternion - */ -CGLM_INLINE -void -glm_mat4_quat(mat4 m, versor dest) { - float trace, r, rinv; - - /* it seems using like m12 instead of m[1][2] causes extra instructions */ - - trace = m[0][0] + m[1][1] + m[2][2]; - if (trace >= 0.0f) { - r = sqrtf(1.0f + trace); - rinv = 0.5f / r; - - dest[0] = rinv * (m[1][2] - m[2][1]); - dest[1] = rinv * (m[2][0] - m[0][2]); - dest[2] = rinv * (m[0][1] - m[1][0]); - dest[3] = r * 0.5f; - } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { - r = sqrtf(1.0f - m[1][1] - m[2][2] + m[0][0]); - rinv = 0.5f / r; - - dest[0] = r * 0.5f; - dest[1] = rinv * (m[0][1] + m[1][0]); - dest[2] = rinv * (m[0][2] + m[2][0]); - dest[3] = rinv * (m[1][2] - m[2][1]); - } else if (m[1][1] >= m[2][2]) { - r = sqrtf(1.0f - m[0][0] - m[2][2] + m[1][1]); - rinv = 0.5f / r; - - dest[0] = rinv * (m[0][1] + m[1][0]); - dest[1] = r * 0.5f; - dest[2] = rinv * (m[1][2] + m[2][1]); - dest[3] = rinv * (m[2][0] - m[0][2]); - } else { - r = sqrtf(1.0f - m[0][0] - m[1][1] + m[2][2]); - rinv = 0.5f / r; - - dest[0] = rinv * (m[0][2] + m[2][0]); - dest[1] = rinv * (m[1][2] + m[2][1]); - dest[2] = r * 0.5f; - dest[3] = rinv * (m[0][1] - m[1][0]); - } -} - -/*! - * @brief multiply vector with mat4 - * - * actually the result is vec4, after multiplication the last component - * is trimmed. if you need it don't use this func. - * - * @param[in] m mat4(affine transform) - * @param[in] v vec3 - * @param[in] last 4th item to make it vec4 - * @param[out] dest result vector (vec3) - */ -CGLM_INLINE -void -glm_mat4_mulv3(mat4 m, vec3 v, float last, vec3 dest) { - vec4 res; - glm_vec4(v, last, res); - glm_mat4_mulv(m, res, res); - glm_vec3(res, dest); -} - -/*! - * @brief transpose mat4 and store in dest - * - * source matrix will not be transposed unless dest is m - * - * @param[in] m matrix - * @param[out] dest result - */ -CGLM_INLINE -void -glm_mat4_transpose_to(mat4 m, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_transp_wasm(m, dest); -#elif defined(__AVX__) - glm_mat4_transp_avx(m, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_transp_sse2(m, dest); -#elif defined(CGLM_NEON_FP) - glm_mat4_transp_neon(m, dest); -#else - dest[0][0] = m[0][0]; dest[1][0] = m[0][1]; - dest[0][1] = m[1][0]; dest[1][1] = m[1][1]; - dest[0][2] = m[2][0]; dest[1][2] = m[2][1]; - dest[0][3] = m[3][0]; dest[1][3] = m[3][1]; - dest[2][0] = m[0][2]; dest[3][0] = m[0][3]; - dest[2][1] = m[1][2]; dest[3][1] = m[1][3]; - dest[2][2] = m[2][2]; dest[3][2] = m[2][3]; - dest[2][3] = m[3][2]; dest[3][3] = m[3][3]; -#endif -} - -/*! - * @brief transpose mat4 and store result in same matrix - * - * @param[in, out] m source and dest - */ -CGLM_INLINE -void -glm_mat4_transpose(mat4 m) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_transp_wasm(m, m); -#elif defined(__AVX__) - glm_mat4_transp_avx(m, m); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_transp_sse2(m, m); -#elif defined(CGLM_NEON_FP) - glm_mat4_transp_neon(m, m); -#else - mat4 d; - glm_mat4_transpose_to(m, d); - glm_mat4_ucopy(d, m); -#endif -} - -/*! - * @brief scale (multiply with scalar) matrix without simd optimization - * - * multiply matrix with scalar - * - * @param[in, out] m matrix - * @param[in] s scalar - */ -CGLM_INLINE -void -glm_mat4_scale_p(mat4 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[0][3] *= s; - m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[1][3] *= s; - m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; m[2][3] *= s; - m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; m[3][3] *= s; -} - -/*! - * @brief scale (multiply with scalar) matrix - * - * multiply matrix with scalar - * - * @param[in, out] m matrix - * @param[in] s scalar - */ -CGLM_INLINE -void -glm_mat4_scale(mat4 m, float s) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_scale_wasm(m, s); -#elif defined(__AVX__) - glm_mat4_scale_avx(m, s); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_scale_sse2(m, s); -#elif defined(CGLM_NEON_FP) - glm_mat4_scale_neon(m, s); -#else - glm_mat4_scale_p(m, s); -#endif -} - -/*! - * @brief mat4 determinant - * - * @param[in] mat matrix - * - * @return determinant - */ -CGLM_INLINE -float -glm_mat4_det(mat4 mat) { -#if defined(__wasm__) && defined(__wasm_simd128__) - return glm_mat4_det_wasm(mat); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - return glm_mat4_det_sse2(mat); -#elif defined(CGLM_NEON_FP) - return glm_mat4_det_neon(mat); -#else - /* [square] det(A) = det(At) */ - float t[6]; - float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], - e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], - i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], - m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3]; - - t[0] = k * p - o * l; - t[1] = j * p - n * l; - t[2] = j * o - n * k; - t[3] = i * p - m * l; - t[4] = i * o - m * k; - t[5] = i * n - m * j; - - return a * (f * t[0] - g * t[1] + h * t[2]) - - b * (e * t[0] - g * t[3] + h * t[4]) - + c * (e * t[1] - f * t[3] + h * t[5]) - - d * (e * t[2] - f * t[4] + g * t[5]); -#endif -} - -/*! - * @brief inverse mat4 and store in dest - * - * @param[in] mat matrix - * @param[out] dest inverse matrix - */ -CGLM_INLINE -void -glm_mat4_inv(mat4 mat, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_inv_wasm(mat, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_inv_sse2(mat, dest); -#elif defined(CGLM_NEON_FP) - glm_mat4_inv_neon(mat, dest); -#else - float a = mat[0][0], b = mat[0][1], c = mat[0][2], d = mat[0][3], - e = mat[1][0], f = mat[1][1], g = mat[1][2], h = mat[1][3], - i = mat[2][0], j = mat[2][1], k = mat[2][2], l = mat[2][3], - m = mat[3][0], n = mat[3][1], o = mat[3][2], p = mat[3][3], - - c1 = k * p - l * o, c2 = c * h - d * g, c3 = i * p - l * m, - c4 = a * h - d * e, c5 = j * p - l * n, c6 = b * h - d * f, - c7 = i * n - j * m, c8 = a * f - b * e, c9 = j * o - k * n, - c10 = b * g - c * f, c11 = i * o - k * m, c12 = a * g - c * e, - - idt = 1.0f/(c8*c1+c4*c9+c10*c3+c2*c7-c12*c5-c6*c11), ndt = -idt; - - dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; - dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; - dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; - dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; - - dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; - dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; - dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; - dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; - - dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; - dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; - dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; - dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; - - dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; - dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; - dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; - dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; -#endif -} - -/*! - * @brief inverse mat4 and store in dest - * - * this func uses reciprocal approximation without extra corrections - * e.g Newton-Raphson. this should work faster than normal, - * to get more precise use glm_mat4_inv version. - * - * NOTE: You will lose precision, glm_mat4_inv is more accurate - * - * @param[in] mat matrix - * @param[out] dest inverse matrix - */ -CGLM_INLINE -void -glm_mat4_inv_fast(mat4 mat, mat4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_mat4_inv_fast_wasm(mat, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_mat4_inv_fast_sse2(mat, dest); -#else - glm_mat4_inv(mat, dest); -#endif -} - -/*! - * @brief swap two matrix columns - * - * @param[in,out] mat matrix - * @param[in] col1 col1 - * @param[in] col2 col2 - */ -CGLM_INLINE -void -glm_mat4_swap_col(mat4 mat, int col1, int col2) { - CGLM_ALIGN(16) vec4 tmp; - glm_vec4_copy(mat[col1], tmp); - glm_vec4_copy(mat[col2], mat[col1]); - glm_vec4_copy(tmp, mat[col2]); -} - -/*! - * @brief swap two matrix rows - * - * @param[in,out] mat matrix - * @param[in] row1 row1 - * @param[in] row2 row2 - */ -CGLM_INLINE -void -glm_mat4_swap_row(mat4 mat, int row1, int row2) { - CGLM_ALIGN(16) vec4 tmp; - tmp[0] = mat[0][row1]; - tmp[1] = mat[1][row1]; - tmp[2] = mat[2][row1]; - tmp[3] = mat[3][row1]; - - mat[0][row1] = mat[0][row2]; - mat[1][row1] = mat[1][row2]; - mat[2][row1] = mat[2][row2]; - mat[3][row1] = mat[3][row2]; - - mat[0][row2] = tmp[0]; - mat[1][row2] = tmp[1]; - mat[2][row2] = tmp[2]; - mat[3][row2] = tmp[3]; -} - -/*! - * @brief helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because R * M = Matrix1x4 (row vector), - * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) - * - * @param[in] r row vector or matrix1x4 - * @param[in] m matrix4x4 - * @param[in] c column vector or matrix4x1 - * - * @return scalar value e.g. B(s) - */ -CGLM_INLINE -float -glm_mat4_rmc(vec4 r, mat4 m, vec4 c) { - vec4 tmp; - glm_mat4_mulv(m, c, tmp); - return glm_vec4_dot(r, tmp); -} - -/*! - * @brief Create mat4 matrix from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest matrix - */ -CGLM_INLINE -void -glm_mat4_make(const float * __restrict src, mat4 dest) { - dest[0][0] = src[0]; dest[1][0] = src[4]; - dest[0][1] = src[1]; dest[1][1] = src[5]; - dest[0][2] = src[2]; dest[1][2] = src[6]; - dest[0][3] = src[3]; dest[1][3] = src[7]; - - dest[2][0] = src[8]; dest[3][0] = src[12]; - dest[2][1] = src[9]; dest[3][1] = src[13]; - dest[2][2] = src[10]; dest[3][2] = src[14]; - dest[2][3] = src[11]; dest[3][3] = src[15]; -} - -/*! - * @brief Create mat4 matrix from texture transform parameters - * - * @param[in] sx scale x - * @param[in] sy scale y - * @param[in] rot rotation in radians CCW/RH - * @param[in] tx translate x - * @param[in] ty translate y - * @param[out] dest texture transform matrix - */ -CGLM_INLINE -void -glm_mat4_textrans(float sx, float sy, float rot, float tx, float ty, mat4 dest) { - float c, s; - - c = cosf(rot); - s = sinf(rot); - - glm_mat4_identity(dest); - - dest[0][0] = c * sx; - dest[0][1] = -s * sy; - dest[1][0] = s * sx; - dest[1][1] = c * sy; - dest[3][0] = tx; - dest[3][1] = ty; -} - -#endif /* cglm_mat_h */ diff --git a/external/cglm/mat4x2.h b/external/cglm/mat4x2.h deleted file mode 100644 index 91684e4..0000000 --- a/external/cglm/mat4x2.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT4X2_ZERO_INIT - GLM_MAT4X2_ZERO - - Functions: - CGLM_INLINE void glm_mat4x2_copy(mat4x2 src, mat4x2 dest); - CGLM_INLINE void glm_mat4x2_zero(mat4x2 m); - CGLM_INLINE void glm_mat4x2_make(const float * __restrict src, mat4x2 dest); - CGLM_INLINE void glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest); - CGLM_INLINE void glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest); - CGLM_INLINE void glm_mat4x2_transpose(mat4x2 src, mat2x4 dest); - CGLM_INLINE void glm_mat4x2_scale(mat4x2 m, float s); - */ - -#ifndef cglm_mat4x2_h -#define cglm_mat4x2_h - -#include "common.h" - -#define GLM_MAT4X2_ZERO_INIT {{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT4X2_ZERO GLM_MAT4X2_ZERO_INIT - -/*! - * @brief Copy mat4x2 (src) to mat4x2 (dest). - * - * @param[in] src mat4x2 (left) - * @param[out] dest destination (result, mat4x2) - */ -CGLM_INLINE -void -glm_mat4x2_copy(mat4x2 src, mat4x2 dest) { - glm_vec2_copy(src[0], dest[0]); - glm_vec2_copy(src[1], dest[1]); - glm_vec2_copy(src[2], dest[2]); - glm_vec2_copy(src[3], dest[3]); -} - -/*! - * @brief Zero out the mat4x2 (m). - * - * @param[in, out] mat4x2 (src, dest) - */ -CGLM_INLINE -void -glm_mat4x2_zero(mat4x2 m) { - CGLM_ALIGN_MAT mat4x2 t = GLM_MAT4X2_ZERO_INIT; - glm_mat4x2_copy(t, m); -} - -/*! - * @brief Create mat4x2 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat4x2) - */ -CGLM_INLINE -void -glm_mat4x2_make(const float * __restrict src, mat4x2 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - - dest[1][0] = src[2]; - dest[1][1] = src[3]; - - dest[2][0] = src[4]; - dest[2][1] = src[5]; - - dest[3][0] = src[6]; - dest[3][1] = src[7]; -} - -/*! - * @brief Multiply mat4x2 (m1) by mat2x4 (m2) and store in mat2 (dest). - * - * @code - * glm_mat4x2_mul(mat4x2, mat2x4, mat2); - * @endcode - * - * @param[in] m1 mat4x2 (left) - * @param[in] m2 mat2x4 (right) - * @param[out] dest destination (result, mat2) - */ -CGLM_INLINE -void -glm_mat4x2_mul(mat4x2 m1, mat2x4 m2, mat2 dest) { - float a00 = m1[0][0], a01 = m1[0][1], - a10 = m1[1][0], a11 = m1[1][1], - a20 = m1[2][0], a21 = m1[2][1], - a30 = m1[3][0], a31 = m1[3][1], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; -} - -/*! - * @brief Multiply mat4x2 (m) by vec4 (v) and store in vec2 (dest). - * - * @param[in] m mat4x2 (left) - * @param[in] v vec4 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat4x2_mulv(mat4x2 m, vec4 v, vec2 dest) { - float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3; - dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3; -} - -/*! - * @brief Transpose mat4x2 (src) and store in mat2x4 (dest). - * - * @param[in] src mat4x2 (left) - * @param[out] dest destination (result, mat2x4) - */ -CGLM_INLINE -void -glm_mat4x2_transpose(mat4x2 m, mat2x4 dest) { - dest[0][0] = m[0][0]; dest[0][1] = m[1][0]; dest[0][2] = m[2][0]; dest[0][3] = m[3][0]; - dest[1][0] = m[0][1]; dest[1][1] = m[1][1]; dest[1][2] = m[2][1]; dest[1][3] = m[3][1]; -} - -/*! - * @brief Multiply mat4x2 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat4x2_scale(mat4x2 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[1][0] *= s; m[1][1] *= s; - m[2][0] *= s; m[2][1] *= s; m[3][0] *= s; m[3][1] *= s; -} - -#endif diff --git a/external/cglm/mat4x3.h b/external/cglm/mat4x3.h deleted file mode 100644 index a429437..0000000 --- a/external/cglm/mat4x3.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT4X3_ZERO_INIT - GLM_MAT4X3_ZERO - - Functions: - CGLM_INLINE void glm_mat4x3_copy(mat4x3 src, mat4x3 dest); - CGLM_INLINE void glm_mat4x3_zero(mat4x3 m); - CGLM_INLINE void glm_mat4x3_make(const float * __restrict src, mat4x3 dest); - CGLM_INLINE void glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest); - CGLM_INLINE void glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest); - CGLM_INLINE void glm_mat4x3_transpose(mat4x3 src, mat3x4 dest); - CGLM_INLINE void glm_mat4x3_scale(mat4x3 m, float s); - */ - -#ifndef cglm_mat4x3_h -#define cglm_mat4x3_h - -#include "common.h" - -#define GLM_MAT4X3_ZERO_INIT {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, \ - {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}} - -/* for C only */ -#define GLM_MAT4X3_ZERO GLM_MAT4X3_ZERO_INIT - -/*! - * @brief Copy mat4x3 (src) to mat4x3 (dest). - * - * @param[in] src mat4x3 (left) - * @param[out] dest destination (result, mat4x3) - */ -CGLM_INLINE -void -glm_mat4x3_copy(mat4x3 src, mat4x3 dest) { - glm_vec3_copy(src[0], dest[0]); - glm_vec3_copy(src[1], dest[1]); - glm_vec3_copy(src[2], dest[2]); - glm_vec3_copy(src[3], dest[3]); -} - -/*! - * @brief Zero out the mat4x3 (m). - * - * @param[in, out] mat4x3 (src, dest) - */ -CGLM_INLINE -void -glm_mat4x3_zero(mat4x3 m) { - CGLM_ALIGN_MAT mat4x3 t = GLM_MAT4X3_ZERO_INIT; - glm_mat4x3_copy(t, m); -} - -/*! - * @brief Create mat4x3 (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats (left) - * @param[out] dest destination (result, mat4x3) - */ -CGLM_INLINE -void -glm_mat4x3_make(const float * __restrict src, mat4x3 dest) { - dest[0][0] = src[0]; - dest[0][1] = src[1]; - dest[0][2] = src[2]; - - dest[1][0] = src[3]; - dest[1][1] = src[4]; - dest[1][2] = src[5]; - - dest[2][0] = src[6]; - dest[2][1] = src[7]; - dest[2][2] = src[8]; - - dest[3][0] = src[9]; - dest[3][1] = src[10]; - dest[3][2] = src[11]; -} - -/*! - * @brief Multiply mat4x3 (m1) by mat3x4 (m2) and store in mat3 (dest). - * - * @code - * glm_mat4x3_mul(mat4x3, mat3x4, mat3); - * @endcode - * - * @param[in] m1 mat4x3 (left) - * @param[in] m2 mat3x4 (right) - * @param[out] dest destination (result, mat3) - */ -CGLM_INLINE -void -glm_mat4x3_mul(mat4x3 m1, mat3x4 m2, mat3 dest) { - float a00 = m1[0][0], a01 = m1[0][1], a02 = m1[0][2], - a10 = m1[1][0], a11 = m1[1][1], a12 = m1[1][2], - a20 = m1[2][0], a21 = m1[2][1], a22 = m1[2][2], - a30 = m1[3][0], a31 = m1[3][1], a32 = m1[3][2], - - b00 = m2[0][0], b01 = m2[0][1], b02 = m2[0][2], b03 = m2[0][3], - b10 = m2[1][0], b11 = m2[1][1], b12 = m2[1][2], b13 = m2[1][3], - b20 = m2[2][0], b21 = m2[2][1], b22 = m2[2][2], b23 = m2[2][3]; - - dest[0][0] = a00 * b00 + a10 * b01 + a20 * b02 + a30 * b03; - dest[0][1] = a01 * b00 + a11 * b01 + a21 * b02 + a31 * b03; - dest[0][2] = a02 * b00 + a12 * b01 + a22 * b02 + a32 * b03; - - dest[1][0] = a00 * b10 + a10 * b11 + a20 * b12 + a30 * b13; - dest[1][1] = a01 * b10 + a11 * b11 + a21 * b12 + a31 * b13; - dest[1][2] = a02 * b10 + a12 * b11 + a22 * b12 + a32 * b13; - - dest[2][0] = a00 * b20 + a10 * b21 + a20 * b22 + a30 * b23; - dest[2][1] = a01 * b20 + a11 * b21 + a21 * b22 + a31 * b23; - dest[2][2] = a02 * b20 + a12 * b21 + a22 * b22 + a32 * b23; -} - -/*! - * @brief Multiply mat4x3 (m) by vec4 (v) and store in vec3 (dest). - * - * @param[in] m mat4x3 (left) - * @param[in] v vec3 (right, column vector) - * @param[out] dest destination (result, column vector) - */ -CGLM_INLINE -void -glm_mat4x3_mulv(mat4x3 m, vec4 v, vec3 dest) { - float v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; - - dest[0] = m[0][0] * v0 + m[1][0] * v1 + m[2][0] * v2 + m[3][0] * v3; - dest[1] = m[0][1] * v0 + m[1][1] * v1 + m[2][1] * v2 + m[3][1] * v3; - dest[2] = m[0][2] * v0 + m[1][2] * v1 + m[2][2] * v2 + m[3][2] * v3; -} - -/*! - * @brief Transpose mat4x3 (src) and store in mat3x4 (dest). - * - * @param[in] src mat4x3 (left) - * @param[out] dest destination (result, mat3x4) - */ -CGLM_INLINE -void -glm_mat4x3_transpose(mat4x3 src, mat3x4 dest) { - dest[0][0] = src[0][0]; dest[0][1] = src[1][0]; dest[0][2] = src[2][0]; dest[0][3] = src[3][0]; - dest[1][0] = src[0][1]; dest[1][1] = src[1][1]; dest[1][2] = src[2][1]; dest[1][3] = src[3][1]; - dest[2][0] = src[0][2]; dest[2][1] = src[1][2]; dest[2][2] = src[2][2]; dest[2][3] = src[3][2]; -} - -/*! - * @brief Multiply mat4x3 (m) by scalar constant (s). - * - * @param[in, out] m (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -void -glm_mat4x3_scale(mat4x3 m, float s) { - m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; - m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s; - m[2][2] *= s; m[3][0] *= s; m[3][1] *= s; m[3][2] *= s; -} - -#endif /* cglm_mat4x3_h */ diff --git a/external/cglm/noise.h b/external/cglm/noise.h deleted file mode 100644 index bec12e9..0000000 --- a/external/cglm/noise.h +++ /dev/null @@ -1,734 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - * - * Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": - * https://github.com/stegu/webgl-noise - * Following Stefan Gustavson's paper "Simplex noise demystified": - * http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf - * - * Implementation based on glm::perlin function: - * https://github.com/g-truc/glm/blob/master/glm/gtc/noise.inl - */ - -#ifndef cglm_noise_h -#define cglm_noise_h - -#include "vec4.h" -#include "vec4-ext.h" - -#include "vec3.h" -#include "vec3-ext.h" - -#include "vec2.h" -#include "vec2-ext.h" - -#define glm__noiseDetail_mod289(x) (x - floorf(x * (1.0f / 289.0f)) * 289.0f) - -/* glm__noiseDetail_permute(vec4 x, vec4 dest) */ -#define glm__noiseDetail_permute(x, dest) { \ - dest[0] = glm__noiseDetail_mod289((x[0] * 34.0f + 1.0f) * x[0]); \ - dest[1] = glm__noiseDetail_mod289((x[1] * 34.0f + 1.0f) * x[1]); \ - dest[2] = glm__noiseDetail_mod289((x[2] * 34.0f + 1.0f) * x[2]); \ - dest[3] = glm__noiseDetail_mod289((x[3] * 34.0f + 1.0f) * x[3]); \ -} - -/* glm__noiseDetail_fade_vec4(vec4 t, vec4 dest) */ -#define glm__noiseDetail_fade_vec4(t, dest) { \ - /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - vec4 temp; \ - glm_vec4_mul(t, t, temp); \ - glm_vec4_mul(temp, t, temp); \ - /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - glm_vec4_scale(t, 6.0f, dest); \ - glm_vec4_subs(dest, 15.0f, dest); \ - glm_vec4_mul(t, dest, dest); \ - glm_vec4_adds(dest, 10.0f, dest); \ - /* dest = temp * dest */ \ - glm_vec4_mul(temp, dest, dest); \ -} - -/* glm__noiseDetail_fade_vec3(vec3 t, vec3 dest) */ -#define glm__noiseDetail_fade_vec3(t, dest) { \ - /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - /* temp = t * t * t */ \ - vec3 temp; \ - glm_vec3_mul(t, t, temp); \ - glm_vec3_mul(temp, t, temp); \ - /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - glm_vec3_scale(t, 6.0f, dest); \ - glm_vec3_subs(dest, 15.0f, dest); \ - glm_vec3_mul(t, dest, dest); \ - glm_vec3_adds(dest, 10.0f, dest); \ - /* dest = temp * dest */ \ - glm_vec3_mul(temp, dest, dest); \ -} - -/* glm__noiseDetail_fade_vec2(vec2 t, vec2 dest) */ -#define glm__noiseDetail_fade_vec2(t, dest) { \ - /* dest = (t * t * t) * (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - /* temp = t * t * t */ \ - vec2 temp; \ - glm_vec2_mul(t, t, temp); \ - glm_vec2_mul(temp, t, temp); \ - /* dest = (t * (t * 6.0f - 15.0f) + 10.0f) */ \ - glm_vec2_scale(t, 6.0f, dest); \ - glm_vec2_subs(dest, 15.0f, dest); \ - glm_vec2_mul(t, dest, dest); \ - glm_vec2_adds(dest, 10.0f, dest); \ - /* dest = temp * dest */ \ - glm_vec2_mul(temp, dest, dest); \ -} - -/* glm__noiseDetail_taylorInvSqrt(vec4 x, vec4 dest) */ -#define glm__noiseDetail_taylorInvSqrt(x, dest) { \ - /* dest = 1.79284291400159f - 0.85373472095314f * x */ \ - vec4 temp; \ - glm_vec4_scale(x, 0.85373472095314f, temp); /* temp = 0.853...f * x */ \ - glm_vec4_fill(dest, 1.79284291400159f); /* dest = 1.792...f */ \ - glm_vec4_sub(dest, temp, dest); /* dest = 1.79284291400159f - temp */ \ -} - -/* norm = taylorInvSqrt(vec4( - * dot(g00__, g00__), - * dot(g01__, g01__), - * dot(g10__, g10__), - * dot(g11__, g11__) - * )); -*/ - -/* glm__noiseDetail_gradNorm_vec4(vec4 g00__, vec4 g01__, vec4 g10__, vec4 g11__) */ -#define glm__noiseDetail_gradNorm_vec4(g00__, g01__, g10__, g11__) { \ - vec4 norm; \ - norm[0] = glm_vec4_dot(g00__, g00__); /* norm.x = dot(g00__, g00__) */ \ - norm[1] = glm_vec4_dot(g01__, g01__); /* norm.y = dot(g01__, g01__) */ \ - norm[2] = glm_vec4_dot(g10__, g10__); /* norm.z = dot(g10__, g10__) */ \ - norm[3] = glm_vec4_dot(g11__, g11__); /* norm.w = dot(g11__, g11__) */ \ - glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ - \ - glm_vec4_scale(g00__, norm[0], g00__); /* g00__ *= norm.x */ \ - glm_vec4_scale(g01__, norm[1], g01__); /* g01__ *= norm.y */ \ - glm_vec4_scale(g10__, norm[2], g10__); /* g10__ *= norm.z */ \ - glm_vec4_scale(g11__, norm[3], g11__); /* g11__ *= norm.w */ \ -} - -/* glm__noiseDetail_gradNorm_vec3(vec3 g00_, vec3 g01_, vec3 g10_, vec3 g11_) */ -#define glm__noiseDetail_gradNorm_vec3(g00_, g01_, g10_, g11_) { \ - vec4 norm; \ - norm[0] = glm_vec3_dot(g00_, g00_); /* norm.x = dot(g00_, g00_) */ \ - norm[1] = glm_vec3_dot(g01_, g01_); /* norm.y = dot(g01_, g01_) */ \ - norm[2] = glm_vec3_dot(g10_, g10_); /* norm.z = dot(g10_, g10_) */ \ - norm[3] = glm_vec3_dot(g11_, g11_); /* norm.w = dot(g11_, g11_) */ \ - glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ - \ - glm_vec3_scale(g00_, norm[0], g00_); /* g00_ *= norm.x */ \ - glm_vec3_scale(g01_, norm[1], g01_); /* g01_ *= norm.y */ \ - glm_vec3_scale(g10_, norm[2], g10_); /* g10_ *= norm.z */ \ - glm_vec3_scale(g11_, norm[3], g11_); /* g11_ *= norm.w */ \ -} - -/* glm__noiseDetail_gradNorm_vec2(vec2 g00, vec2 g01, vec2 g10, vec2 g11) */ -#define glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11) { \ - vec4 norm; \ - norm[0] = glm_vec2_dot(g00, g00); /* norm.x = dot(g00, g00) */ \ - norm[1] = glm_vec2_dot(g01, g01); /* norm.y = dot(g01, g01) */ \ - norm[2] = glm_vec2_dot(g10, g10); /* norm.z = dot(g10, g10) */ \ - norm[3] = glm_vec2_dot(g11, g11); /* norm.w = dot(g11, g11) */ \ - glm__noiseDetail_taylorInvSqrt(norm, norm); /* norm = taylorInvSqrt(norm) */ \ - \ - glm_vec2_scale(g00, norm[0], g00); /* g00 *= norm.x */ \ - glm_vec2_scale(g01, norm[1], g01); /* g01 *= norm.y */ \ - glm_vec2_scale(g10, norm[2], g10); /* g10 *= norm.z */ \ - glm_vec2_scale(g11, norm[3], g11); /* g11 *= norm.w */ \ -} - -/* glm__noiseDetail_i2gxyzw(vec4 ixy, vec4 gx, vec4 gy, vec4 gz, vec4 gw) */ -#define glm__noiseDetail_i2gxyzw(ixy, gx, gy, gz, gw) { \ - /* gx = ixy / 7.0 */ \ - glm_vec4_divs(ixy, 7.0f, gx); /* gx = ixy / 7.0 */ \ - \ - /* gy = fract(gx) / 7.0 */ \ - glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \ - glm_vec4_divs(gy, 7.0f, gy); /* gy /= 7.0 */ \ - \ - /* gz = floor(gy) / 6.0 */ \ - glm_vec4_floor(gy, gz); /* gz = floor(gy) */ \ - glm_vec4_divs(gz, 6.0f, gz); /* gz /= 6.0 */ \ - \ - /* gx = fract(gx) - 0.5f */ \ - glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ - glm_vec4_subs(gx, 0.5f, gx); /* gx -= 0.5f */ \ - \ - /* gy = fract(gy) - 0.5f */ \ - glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \ - glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \ - \ - /* gz = fract(gz) - 0.5f */ \ - glm_vec4_fract(gz, gz); /* gz = fract(gz) */ \ - glm_vec4_subs(gz, 0.5f, gz); /* gz -= 0.5f */ \ - \ - /* abs(gx), abs(gy), abs(gz) */ \ - vec4 gxa, gya, gza; \ - glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \ - glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \ - glm_vec4_abs(gz, gza); /* gza = abs(gz) */ \ - \ - /* gw = 0.75 - abs(gx) - abs(gy) - abs(gz) */ \ - glm_vec4_fill(gw, 0.75f); /* gw = 0.75 */ \ - glm_vec4_sub(gw, gxa, gw); /* gw -= gxa */ \ - glm_vec4_sub(gw, gza, gw); /* gw -= gza */ \ - glm_vec4_sub(gw, gya, gw); /* gw -= gya */ \ - \ - /* sw = step(gw, 0.0); */ \ - vec4 sw; \ - glm_vec4_stepr(gw, 0.0f, sw); /* sw = step(gw, 0.0) */ \ - \ - /* gx -= sw * (step(vec4(0), gx) - T(0.5)); */ \ - vec4 temp = {0.0f}; /* temp = 0.0 */ \ - glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \ - glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ - glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \ - glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \ - \ - /* gy -= sw * (step(vec4(0), gy) - T(0.5)); */ \ - glm_vec4_zero(temp); /* reset temp */ \ - glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \ - glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ - glm_vec4_mul(sw, temp, temp); /* temp *= sw */ \ - glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \ -} - -/* NOTE: This function is not *quite* analogous to glm__noiseDetail_i2gxyzw - * to try to match the output of glm::perlin. I think it might be a bug in - * in the original implementation, but for now I'm keeping it consistent. -MK - * - * Follow up: The original implementation (glm v 1.0.1) does: - * - * vec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0); - * - * as opposed to: - * - * vec<4, T, Q> gx0 = ixy0 / T(7); - * - * This ends up mapping to different simd instructions, at least on AMD. - * The delta is tiny but it gets amplified by the rest of the noise function. - * Hence we too need to do `glm_vec4_scale` as opposed to `glm_vec4_divs`, to - * match it. -MK - */ - -/* glm__noiseDetail_i2gxyz(vec4 i, vec4 gx, vec4 gy, vec4 gz) */ -#define glm__noiseDetail_i2gxyz(ixy, gx, gy, gz) { \ - /* gx = ixy / 7.0 */ \ - glm_vec4_scale(ixy, 1.0f / 7.0f, gx); /* gx = ixy * (1/7.0) */\ - \ - /* gy = fract(floor(gx0) / 7.0)) - 0.5; */ \ - glm_vec4_floor(gx, gy); /* gy = floor(gx) */ \ - glm_vec4_scale(gy, 1.0f / 7.0f, gy); /* gy *= 1 / 7.0 */ \ - glm_vec4_fract(gy, gy); /* gy = fract(gy) */ \ - glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5f */ \ - \ - /* gx = fract(gx); */ \ - glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ - \ - /* abs(gx), abs(gy) */ \ - vec4 gxa, gya; \ - glm_vec4_abs(gx, gxa); /* gxa = abs(gx) */ \ - glm_vec4_abs(gy, gya); /* gya = abs(gy) */ \ - \ - /* gz = vec4(0.5) - abs(gx0) - abs(gy0); */ \ - glm_vec4_fill(gz, 0.5f); /* gz = 0.5 */ \ - glm_vec4_sub(gz, gxa, gz); /* gz -= gxa */ \ - glm_vec4_sub(gz, gya, gz); /* gz -= gya */ \ - \ - /* sz = step(gw, 0.0); */ \ - vec4 sz; \ - glm_vec4_stepr(gz, 0.0f, sz); /* sz = step(gz, 0.0) */ \ - \ - /* gx0 -= sz0 * (step(0.0, gx0) - T(0.5)); */ \ - vec4 temp = {0.0f}; /* temp = 0.0 */ \ - glm_vec4_step(temp, gx, temp); /* temp = step(temp, gx) */ \ - glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ - glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \ - glm_vec4_sub(gx, temp, gx); /* gx -= temp */ \ - \ - /* gy0 -= sz0 * (step(0.0, gy0) - T(0.5)); */ \ - glm_vec4_zero(temp); /* reset temp */ \ - glm_vec4_step(temp, gy, temp); /* temp = step(temp, gy) */ \ - glm_vec4_subs(temp, 0.5f, temp); /* temp -= 0.5 */ \ - glm_vec4_mul(sz, temp, temp); /* temp *= sz */ \ - glm_vec4_sub(gy, temp, gy); /* gy -= temp */ \ -} - -/* glm__noiseDetail_i2gxy(vec4 i, vec4 gx, vec4 gy) */ -#define glm__noiseDetail_i2gxy(i, gx, gy) { \ - /* gx = 2.0 * fract(i / 41.0) - 1.0; */ \ - glm_vec4_divs(i, 41.0f, gx); /* gx = i / 41.0 */ \ - glm_vec4_fract(gx, gx); /* gx = fract(gx) */ \ - glm_vec4_scale(gx, 2.0f, gx); /* gx *= 2.0 */ \ - glm_vec4_subs(gx, 1.0f, gx); /* gx -= 1.0 */ \ - \ - /* gy = abs(gx) - 0.5; */ \ - glm_vec4_abs(gx, gy); /* gy = abs(gx) */ \ - glm_vec4_subs(gy, 0.5f, gy); /* gy -= 0.5 */ \ - \ - /* tx = floor(gx + 0.5); */ \ - vec4 tx; \ - glm_vec4_adds(gx, 0.5f, tx); /* tx = gx + 0.5 */ \ - glm_vec4_floor(tx, tx); /* tx = floor(tx) */ \ - \ - /* gx = gx - tx; */ \ - glm_vec4_sub(gx, tx, gx); /* gx -= tx */ \ -} - -/* ============================================================================ - * Classic perlin noise - * ============================================================================ - */ - -/*! - * @brief Classic perlin noise - * - * @param[in] point 4D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glm_perlin_vec4(vec4 point) { - /* Integer part of p for indexing */ - vec4 Pi0; - glm_vec4_floor(point, Pi0); /* Pi0 = floor(point); */ - - /* Integer part + 1 */ - vec4 Pi1; - glm_vec4_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */ - - glm_vec4_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */ - glm_vec4_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */ - - /* Fractional part of p for interpolation */ - vec4 Pf0; - glm_vec4_fract(point, Pf0); - - /* Fractional part - 1.0 */ - vec4 Pf1; - glm_vec4_subs(Pf0, 1.0f, Pf1); - - vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]}; - vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]}; - vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */ - vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */ - vec4 iw0 = {Pi0[3], Pi0[3], Pi0[3], Pi0[3]}; /* iw0 = vec4(Pi0.w); */ - vec4 iw1 = {Pi1[3], Pi1[3], Pi1[3], Pi1[3]}; /* iw1 = vec4(Pi1.w); */ - - /* ------------ */ - - /* ixy = permute(permute(ix) + iy) */ - vec4 ixy; - glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */ - glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */ - glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */ - - /* ixy0 = permute(ixy + iz0) */ - vec4 ixy0; - glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */ - glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */ - - /* ixy1 = permute(ixy + iz1) */ - vec4 ixy1; - glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */ - glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */ - - /* ixy00 = permute(ixy0 + iw0) */ - vec4 ixy00; - glm_vec4_add(ixy0, iw0, ixy00); /* ixy00 = ixy0 + iw0 */ - glm__noiseDetail_permute(ixy00, ixy00); /* ixy00 = permute(ixy00) */ - - /* ixy01 = permute(ixy0 + iw1) */ - vec4 ixy01; - glm_vec4_add(ixy0, iw1, ixy01); /* ixy01 = ixy0 + iw1 */ - glm__noiseDetail_permute(ixy01, ixy01); /* ixy01 = permute(ixy01) */ - - /* ixy10 = permute(ixy1 + iw0) */ - vec4 ixy10; - glm_vec4_add(ixy1, iw0, ixy10); /* ixy10 = ixy1 + iw0 */ - glm__noiseDetail_permute(ixy10, ixy10); /* ixy10 = permute(ixy10) */ - - /* ixy11 = permute(ixy1 + iw1) */ - vec4 ixy11; - glm_vec4_add(ixy1, iw1, ixy11); /* ixy11 = ixy1 + iw1 */ - glm__noiseDetail_permute(ixy11, ixy11); /* ixy11 = permute(ixy11) */ - - /* ------------ */ - - vec4 gx00, gy00, gz00, gw00; - glm__noiseDetail_i2gxyzw(ixy00, gx00, gy00, gz00, gw00); - - vec4 gx01, gy01, gz01, gw01; - glm__noiseDetail_i2gxyzw(ixy01, gx01, gy01, gz01, gw01); - - vec4 gx10, gy10, gz10, gw10; - glm__noiseDetail_i2gxyzw(ixy10, gx10, gy10, gz10, gw10); - - vec4 gx11, gy11, gz11, gw11; - glm__noiseDetail_i2gxyzw(ixy11, gx11, gy11, gz11, gw11); - - /* ------------ */ - - vec4 g0000 = {gx00[0], gy00[0], gz00[0], gw00[0]}; /* g0000 = vec4(gx00.x, gy00.x, gz00.x, gw00.x); */ - vec4 g0100 = {gx00[2], gy00[2], gz00[2], gw00[2]}; /* g0100 = vec4(gx00.z, gy00.z, gz00.z, gw00.z); */ - vec4 g1000 = {gx00[1], gy00[1], gz00[1], gw00[1]}; /* g1000 = vec4(gx00.y, gy00.y, gz00.y, gw00.y); */ - vec4 g1100 = {gx00[3], gy00[3], gz00[3], gw00[3]}; /* g1100 = vec4(gx00.w, gy00.w, gz00.w, gw00.w); */ - - vec4 g0001 = {gx01[0], gy01[0], gz01[0], gw01[0]}; /* g0001 = vec4(gx01.x, gy01.x, gz01.x, gw01.x); */ - vec4 g0101 = {gx01[2], gy01[2], gz01[2], gw01[2]}; /* g0101 = vec4(gx01.z, gy01.z, gz01.z, gw01.z); */ - vec4 g1001 = {gx01[1], gy01[1], gz01[1], gw01[1]}; /* g1001 = vec4(gx01.y, gy01.y, gz01.y, gw01.y); */ - vec4 g1101 = {gx01[3], gy01[3], gz01[3], gw01[3]}; /* g1101 = vec4(gx01.w, gy01.w, gz01.w, gw01.w); */ - - vec4 g0010 = {gx10[0], gy10[0], gz10[0], gw10[0]}; /* g0010 = vec4(gx10.x, gy10.x, gz10.x, gw10.x); */ - vec4 g0110 = {gx10[2], gy10[2], gz10[2], gw10[2]}; /* g0110 = vec4(gx10.z, gy10.z, gz10.z, gw10.z); */ - vec4 g1010 = {gx10[1], gy10[1], gz10[1], gw10[1]}; /* g1010 = vec4(gx10.y, gy10.y, gz10.y, gw10.y); */ - vec4 g1110 = {gx10[3], gy10[3], gz10[3], gw10[3]}; /* g1110 = vec4(gx10.w, gy10.w, gz10.w, gw10.w); */ - - vec4 g0011 = {gx11[0], gy11[0], gz11[0], gw11[0]}; /* g0011 = vec4(gx11.x, gy11.x, gz11.x, gw11.x); */ - vec4 g0111 = {gx11[2], gy11[2], gz11[2], gw11[2]}; /* g0111 = vec4(gx11.z, gy11.z, gz11.z, gw11.z); */ - vec4 g1011 = {gx11[1], gy11[1], gz11[1], gw11[1]}; /* g1011 = vec4(gx11.y, gy11.y, gz11.y, gw11.y); */ - vec4 g1111 = {gx11[3], gy11[3], gz11[3], gw11[3]}; /* g1111 = vec4(gx11.w, gy11.w, gz11.w, gw11.w); */ - - glm__noiseDetail_gradNorm_vec4(g0000, g0100, g1000, g1100); - glm__noiseDetail_gradNorm_vec4(g0001, g0101, g1001, g1101); - glm__noiseDetail_gradNorm_vec4(g0010, g0110, g1010, g1110); - glm__noiseDetail_gradNorm_vec4(g0011, g0111, g1011, g1111); - - /* ------------ */ - - float n0000 = glm_vec4_dot(g0000, Pf0); /* n0000 = dot(g0000, Pf0) */ - - /* n1000 = dot(g1000, vec4(Pf1.x, Pf0.y, Pf0.z, Pf0.w)) */ - vec4 n1000d = {Pf1[0], Pf0[1], Pf0[2], Pf0[3]}; - float n1000 = glm_vec4_dot(g1000, n1000d); - - /* n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.z, Pf0.w)) */ - vec4 n0100d = {Pf0[0], Pf1[1], Pf0[2], Pf0[3]}; - float n0100 = glm_vec4_dot(g0100, n0100d); - - /* n1100 = dot(g1100, vec4(Pf1.x, Pf1.y, Pf0.z, Pf0.w)) */ - vec4 n1100d = {Pf1[0], Pf1[1], Pf0[2], Pf0[3]}; - float n1100 = glm_vec4_dot(g1100, n1100d); - - /* n0010 = dot(g0010, vec4(Pf0.x, Pf0.y, Pf1.z, Pf0.w)) */ - vec4 n0010d = {Pf0[0], Pf0[1], Pf1[2], Pf0[3]}; - float n0010 = glm_vec4_dot(g0010, n0010d); - - /* n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w)) */ - vec4 n1010d = {Pf1[0], Pf0[1], Pf1[2], Pf0[3]}; - float n1010 = glm_vec4_dot(g1010, n1010d); - - /* n0110 = dot(g0110, vec4(Pf0.x, Pf1.y, Pf1.z, Pf0.w)) */ - vec4 n0110d = {Pf0[0], Pf1[1], Pf1[2], Pf0[3]}; - float n0110 = glm_vec4_dot(g0110, n0110d); - - /* n1110 = dot(g1110, vec4(Pf1.x, Pf1.y, Pf1.z, Pf0.w)) */ - vec4 n1110d = {Pf1[0], Pf1[1], Pf1[2], Pf0[3]}; - float n1110 = glm_vec4_dot(g1110, n1110d); - - /* n0001 = dot(g0001, vec4(Pf0.x, Pf0.y, Pf0.z, Pf1.w)) */ - vec4 n0001d = {Pf0[0], Pf0[1], Pf0[2], Pf1[3]}; - float n0001 = glm_vec4_dot(g0001, n0001d); - - /* n1001 = dot(g1001, vec4(Pf1.x, Pf0.y, Pf0.z, Pf1.w)) */ - vec4 n1001d = {Pf1[0], Pf0[1], Pf0[2], Pf1[3]}; - float n1001 = glm_vec4_dot(g1001, n1001d); - - /* n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w)) */ - vec4 n0101d = {Pf0[0], Pf1[1], Pf0[2], Pf1[3]}; - float n0101 = glm_vec4_dot(g0101, n0101d); - - /* n1101 = dot(g1101, vec4(Pf1.x, Pf1.y, Pf0.z, Pf1.w)) */ - vec4 n1101d = {Pf1[0], Pf1[1], Pf0[2], Pf1[3]}; - float n1101 = glm_vec4_dot(g1101, n1101d); - - /* n0011 = dot(g0011, vec4(Pf0.x, Pf0.y, Pf1.z, Pf1.w)) */ - vec4 n0011d = {Pf0[0], Pf0[1], Pf1[2], Pf1[3]}; - float n0011 = glm_vec4_dot(g0011, n0011d); - - /* n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.z, Pf1.w)) */ - vec4 n1011d = {Pf1[0], Pf0[1], Pf1[2], Pf1[3]}; - float n1011 = glm_vec4_dot(g1011, n1011d); - - /* n0111 = dot(g0111, vec4(Pf0.x, Pf1.y, Pf1.z, Pf1.w)) */ - vec4 n0111d = {Pf0[0], Pf1[1], Pf1[2], Pf1[3]}; - float n0111 = glm_vec4_dot(g0111, n0111d); - - float n1111 = glm_vec4_dot(g1111, Pf1); /* n1111 = dot(g1111, Pf1) */ - - /* ------------ */ - - vec4 fade_xyzw; - glm__noiseDetail_fade_vec4(Pf0, fade_xyzw); /* fade_xyzw = fade(Pf0) */ - - /* n_0w = lerp(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w) */ - vec4 n_0w1 = {n0000, n1000, n0100, n1100}; - vec4 n_0w2 = {n0001, n1001, n0101, n1101}; - vec4 n_0w; - glm_vec4_lerp(n_0w1, n_0w2, fade_xyzw[3], n_0w); - - /* n_1w = lerp(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w) */ - vec4 n_1w1 = {n0010, n1010, n0110, n1110}; - vec4 n_1w2 = {n0011, n1011, n0111, n1111}; - vec4 n_1w; - glm_vec4_lerp(n_1w1, n_1w2, fade_xyzw[3], n_1w); - - /* n_zw = lerp(n_0w, n_1w, fade_xyzw.z) */ - vec4 n_zw; - glm_vec4_lerp(n_0w, n_1w, fade_xyzw[2], n_zw); - - /* n_yzw = lerp(vec2(n_zw.x, n_zw.y), vec2(n_zw.z, n_zw.w), fade_xyzw.y) */ - vec2 n_yzw; - vec2 n_yzw1 = {n_zw[0], n_zw[1]}; - vec2 n_yzw2 = {n_zw[2], n_zw[3]}; - glm_vec2_lerp(n_yzw1, n_yzw2, fade_xyzw[1], n_yzw); - - /* n_xyzw = lerp(n_yzw.x, n_yzw.y, fade_xyzw.x) */ - float n_xyzw = glm_lerp(n_yzw[0], n_yzw[1], fade_xyzw[0]); - - return n_xyzw * 2.2f; -} - - -/*! - * @brief Classic perlin noise - * - * @param[in] point 3D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glm_perlin_vec3(vec3 point) { - /* Integer part of p for indexing */ - vec3 Pi0; - glm_vec3_floor(point, Pi0); /* Pi0 = floor(point); */ - - /* Integer part + 1 */ - vec3 Pi1; - glm_vec3_adds(Pi0, 1.0f, Pi1); /* Pi1 = Pi0 + 1.0f; */ - - glm_vec3_mods(Pi0, 289.0f, Pi0); /* Pi0 = mod(Pi0, 289.0f); */ - glm_vec3_mods(Pi1, 289.0f, Pi1); /* Pi1 = mod(Pi1, 289.0f); */ - - /* Fractional part of p for interpolation */ - vec3 Pf0; - glm_vec3_fract(point, Pf0); - - /* Fractional part - 1.0 */ - vec3 Pf1; - glm_vec3_subs(Pf0, 1.0f, Pf1); - - vec4 ix = {Pi0[0], Pi1[0], Pi0[0], Pi1[0]}; - vec4 iy = {Pi0[1], Pi0[1], Pi1[1], Pi1[1]}; - vec4 iz0 = {Pi0[2], Pi0[2], Pi0[2], Pi0[2]}; /* iz0 = vec4(Pi0.z); */ - vec4 iz1 = {Pi1[2], Pi1[2], Pi1[2], Pi1[2]}; /* iz1 = vec4(Pi1.z); */ - - /* ------------ */ - - /* ixy = permute(permute(ix) + iy) */ - vec4 ixy; - glm__noiseDetail_permute(ix, ixy); /* ixy = permute(ix) */ - glm_vec4_add(ixy, iy, ixy); /* ixy += iy; */ - glm__noiseDetail_permute(ixy, ixy); /* ixy = permute(ixy) */ - - /* ixy0 = permute(ixy + iz0) */ - vec4 ixy0; - glm_vec4_add(ixy, iz0, ixy0); /* ixy0 = ixy + iz0 */ - glm__noiseDetail_permute(ixy0, ixy0); /* ixy0 = permute(ixy0) */ - - /* ixy1 = permute(ixy + iz1) */ - vec4 ixy1; - glm_vec4_add(ixy, iz1, ixy1); /* ixy1 = ixy, iz1 */ - glm__noiseDetail_permute(ixy1, ixy1); /* ixy1 = permute(ixy1) */ - - /* ------------ */ - - vec4 gx0, gy0, gz0; - glm__noiseDetail_i2gxyz(ixy0, gx0, gy0, gz0); - - vec4 gx1, gy1, gz1; - glm__noiseDetail_i2gxyz(ixy1, gx1, gy1, gz1); - - /* ------------ */ - - vec3 g000 = {gx0[0], gy0[0], gz0[0]}; /* g000 = vec3(gx0.x, gy0.x, gz0.x); */ - vec3 g100 = {gx0[1], gy0[1], gz0[1]}; /* g100 = vec3(gx0.y, gy0.y, gz0.y); */ - vec3 g010 = {gx0[2], gy0[2], gz0[2]}; /* g010 = vec3(gx0.z, gy0.z, gz0.z); */ - vec3 g110 = {gx0[3], gy0[3], gz0[3]}; /* g110 = vec3(gx0.w, gy0.w, gz0.w); */ - - vec3 g001 = {gx1[0], gy1[0], gz1[0]}; /* g001 = vec3(gx1.x, gy1.x, gz1.x); */ - vec3 g101 = {gx1[1], gy1[1], gz1[1]}; /* g101 = vec3(gx1.y, gy1.y, gz1.y); */ - vec3 g011 = {gx1[2], gy1[2], gz1[2]}; /* g011 = vec3(gx1.z, gy1.z, gz1.z); */ - vec3 g111 = {gx1[3], gy1[3], gz1[3]}; /* g111 = vec3(gx1.w, gy1.w, gz1.w); */ - - glm__noiseDetail_gradNorm_vec3(g000, g010, g100, g110); - glm__noiseDetail_gradNorm_vec3(g001, g011, g101, g111); - - /* ------------ */ - - float n000 = glm_vec3_dot(g000, Pf0); /* n000 = dot(g000, Pf0) */ - - /* n100 = dot(g100, vec3(Pf1.x, Pf0.y, Pf0.z)) */ - vec3 n100d = {Pf1[0], Pf0[1], Pf0[2]}; - float n100 = glm_vec3_dot(g100, n100d); - - /* n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)) */ - vec3 n010d = {Pf0[0], Pf1[1], Pf0[2]}; - float n010 = glm_vec3_dot(g010, n010d); - - /* n110 = dot(g110, vec3(Pf1.x, Pf1.y, Pf0.z)) */ - vec3 n110d = {Pf1[0], Pf1[1], Pf0[2]}; - float n110 = glm_vec3_dot(g110, n110d); - - /* n001 = dot(g001, vec3(Pf0.x, Pf0.y, Pf1.z)) */ - vec3 n001d = {Pf0[0], Pf0[1], Pf1[2]}; - float n001 = glm_vec3_dot(g001, n001d); - - /* n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)) */ - vec3 n101d = {Pf1[0], Pf0[1], Pf1[2]}; - float n101 = glm_vec3_dot(g101, n101d); - - /* n011 = dot(g011, vec3(Pf0.x, Pf1.y, Pf1.z)) */ - vec3 n011d = {Pf0[0], Pf1[1], Pf1[2]}; - float n011 = glm_vec3_dot(g011, n011d); - - float n111 = glm_vec3_dot(g111, Pf1); /* n111 = dot(g111, Pf1) */ - - /* ------------ */ - - vec3 fade_xyz; - glm__noiseDetail_fade_vec3(Pf0, fade_xyz); /* fade_xyz = fade(Pf0) */ - - /* n_z = lerp(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); */ - vec4 n_z; - vec4 n_z1 = {n000, n100, n010, n110}; - vec4 n_z2 = {n001, n101, n011, n111}; - glm_vec4_lerp(n_z1, n_z2, fade_xyz[2], n_z); - - /* vec2 n_yz = lerp(vec2(n_z.x, n_z.y), vec2(n_z.z, n_z.w), fade_xyz.y); */ - vec2 n_yz; - vec2 n_yz1 = {n_z[0], n_z[1]}; - vec2 n_yz2 = {n_z[2], n_z[3]}; - glm_vec2_lerp(n_yz1, n_yz2, fade_xyz[1], n_yz); - - /* n_xyz = lerp(n_yz.x, n_yz.y, fade_xyz.x); */ - float n_xyz = glm_lerp(n_yz[0], n_yz[1], fade_xyz[0]); - - return n_xyz * 2.2f; -} - -/*! - * @brief Classic perlin noise - * - * @param[in] point 2D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glm_perlin_vec2(vec2 point) { - - /* Integer part of p for indexing */ - /* Pi = floor(vec4(point.x, point.y, point.x, point.y)) + vec4(0.0, 0.0, 1.0, 1.0); */ - vec4 Pi = {point[0], point[1], point[0], point[1]}; /* Pi = vec4(point.x, point.y, point.x, point.y) */ - glm_vec4_floor(Pi, Pi); /* Pi = floor(Pi) */ - Pi[2] += 1.0f; /* Pi.z += 1.0 */ - Pi[3] += 1.0f; /* Pi.w += 1.0 */ - - /* Fractional part of p for interpolation */ - /* vec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0); */ - vec4 Pf = {point[0], point[1], point[0], point[1]}; /* Pf = vec4(point.x, point.y, point.x, point.y) */ - glm_vec4_fract(Pf, Pf); /* Pf = fract(Pf) */ - Pf[2] -= 1.0f; /* Pf.z -= 1.0 */ - Pf[3] -= 1.0f; /* Pf.w -= 1.0 */ - - /* Mod to avoid truncation effects in permutation */ - glm_vec4_mods(Pi, 289.0f, Pi); /* Pi = mod(Pi, 289.0f); */ - - vec4 ix = {Pi[0], Pi[2], Pi[0], Pi[2]}; /* ix = vec4(Pi.x, Pi.z, Pi.x, Pi.z) */ - vec4 iy = {Pi[1], Pi[1], Pi[3], Pi[3]}; /* iy = vec4(Pi.y, Pi.y, Pi.w, Pi.w) */ - vec4 fx = {Pf[0], Pf[2], Pf[0], Pf[2]}; /* fx = vec4(Pf.x, Pf.z, Pf.x, Pf.z) */ - vec4 fy = {Pf[1], Pf[1], Pf[3], Pf[3]}; /* fy = vec4(Pf.y, Pf.y, Pf.w, Pf.w) */ - - /* ------------ */ - - /* i = permute(permute(ix) + iy); */ - vec4 i; - glm__noiseDetail_permute(ix, i); /* i = permute(ix) */ - glm_vec4_add(i, iy, i); /* i += iy; */ - glm__noiseDetail_permute(i, i); /* i = permute(i) */ - - /* ------------ */ - - vec4 gx, gy; - glm__noiseDetail_i2gxy(i, gx, gy); - - /* ------------ */ - - vec2 g00 = {gx[0], gy[0]}; /* g00 = vec2(gx.x, gy.x) */ - vec2 g10 = {gx[1], gy[1]}; /* g10 = vec2(gx.y, gy.y) */ - vec2 g01 = {gx[2], gy[2]}; /* g01 = vec2(gx.z, gy.z) */ - vec2 g11 = {gx[3], gy[3]}; /* g11 = vec2(gx.w, gy.w) */ - - glm__noiseDetail_gradNorm_vec2(g00, g01, g10, g11); - - /* ------------ */ - - /* n00 = dot(g00, vec2(fx.x, fy.x)) */ - vec2 n00d = {fx[0], fy[0]}; /* n00d = vec2(fx.x, fy.x) */ - float n00 = glm_vec2_dot(g00, n00d); /* n00 = dot(g00, n00d) */ - - /* n10 = dot(g10, vec2(fx.y, fy.y)) */ - vec2 n10d = {fx[1], fy[1]}; /* n10d = vec2(fx.y, fy.y) */ - float n10 = glm_vec2_dot(g10, n10d); /* n10 = dot(g10, n10d) */ - - /* n01 = dot(g01, vec2(fx.z, fy.z)) */ - vec2 n01d = {fx[2], fy[2]}; /* n01d = vec2(fx.z, fy.z) */ - float n01 = glm_vec2_dot(g01, n01d); /* n01 = dot(g01, n01d) */ - - /* n11 = dot(g11, vec2(fx.w, fy.w)) */ - vec2 n11d = {fx[3], fy[3]}; /* n11d = vec2(fx.w, fy.w) */ - float n11 = glm_vec2_dot(g11, n11d); /* n11 = dot(g11, n11d) */ - - /* ------------ */ - - /* fade_xyz = fade(vec2(Pf.x, Pf.y)) */ - vec2 fade_xy; - vec2 temp2 = {Pf[0], Pf[1]}; /* temp = vec2(Pf.x, Pf.y) */ - glm__noiseDetail_fade_vec2(temp2, fade_xy); /* fade_xy = fade(temp) */ - - /* n_x = lerp(vec2(n00, n01), vec2(n10, n11), fade_xy.x); */ - vec2 n_x; - vec2 n_x1 = {n00, n01}; /* n_x1 = vec2(n00, n01) */ - vec2 n_x2 = {n10, n11}; /* n_x2 = vec2(n10, n11) */ - glm_vec2_lerp(n_x1, n_x2, fade_xy[0], n_x); /* n_x = lerp(n_x1, n_x2, fade_xy.x) */ - - /* T n_xy = mix(n_x.x, n_x.y, fade_xy.y); */ - /* n_xy = lerp(n_x.x, n_x.y, fade_xy.y); */ - float n_xy = glm_lerp(n_x[0], n_x[1], fade_xy[1]); - - return n_xy * 2.3f; -} - -/* Undefine all helper macros */ - -#undef glm__noiseDetail_mod289 -#undef glm__noiseDetail_permute -#undef glm__noiseDetail_fade_vec4 -#undef glm__noiseDetail_fade_vec3 -#undef glm__noiseDetail_fade_vec2 -#undef glm__noiseDetail_taylorInvSqrt -#undef glm__noiseDetail_gradNorm_vec4 -#undef glm__noiseDetail_gradNorm_vec3 -#undef glm__noiseDetail_gradNorm_vec2 -#undef glm__noiseDetail_i2gxyzw -#undef glm__noiseDetail_i2gxyz -#undef glm__noiseDetail_i2gxy - -#endif /* cglm_noise_h */ diff --git a/external/cglm/plane.h b/external/cglm/plane.h deleted file mode 100644 index 9efabb7..0000000 --- a/external/cglm/plane.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_plane_h -#define cglm_plane_h - -#include "common.h" -#include "vec3.h" -#include "vec4.h" - -/* - Plane equation: Ax + By + Cz + D = 0; - - It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance -*/ - -/* - Functions: - CGLM_INLINE void glm_plane_normalize(vec4 plane); - */ - -/*! - * @brief normalizes a plane - * - * @param[in, out] plane plane to normalize - */ -CGLM_INLINE -void -glm_plane_normalize(vec4 plane) { - float norm; - - if (CGLM_UNLIKELY((norm = glm_vec3_norm(plane)) < FLT_EPSILON)) { - glm_vec4_zero(plane); - return; - } - - glm_vec4_scale(plane, 1.0f / norm, plane); -} - -#endif /* cglm_plane_h */ diff --git a/external/cglm/project.h b/external/cglm/project.h deleted file mode 100644 index 1d0a4e5..0000000 --- a/external/cglm/project.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_project_h -#define cglm_project_h - -#include "common.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -#ifndef CGLM_CLIPSPACE_INCLUDE_ALL -# if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT -# include "clipspace/project_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT -# include "clipspace/project_no.h" -# endif -#else -# include "clipspace/project_zo.h" -# include "clipspace/project_no.h" -#endif - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest unprojected coordinates - */ -CGLM_INLINE -void -glm_unprojecti(vec3 pos, mat4 invMat, vec4 vp, vec3 dest) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT - glm_unprojecti_zo(pos, invMat, vp, dest); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT - glm_unprojecti_no(pos, invMat, vp, dest); -#endif -} - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * this is same as glm_unprojecti except this function get inverse matrix for - * you. - * - * [1] space: - * 1- if m = proj: View Space - * 2- if m = viewProj: World Space - * 3- if m = MVP: Object Space - * - * You probably want to map the coordinates into object space - * so use MVP as m - * - * Computing viewProj and MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] m matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest unprojected coordinates - */ -CGLM_INLINE -void -glm_unproject(vec3 pos, mat4 m, vec4 vp, vec3 dest) { - mat4 inv; - glm_mat4_inv(m, inv); - glm_unprojecti(pos, inv, vp, dest); -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest projected coordinates - */ -CGLM_INLINE -void -glm_project(vec3 pos, mat4 m, vec4 vp, vec3 dest) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT - glm_project_zo(pos, m, vp, dest); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT - glm_project_no(pos, m, vp, dest); -#endif -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glm_project_z(vec3 v, mat4 m) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT - return glm_project_z_zo(v, m); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT - return glm_project_z_no(v, m); -#endif -} - -/*! - * @brief define a picking region - * - * @param[in] center center [x, y] of a picking region in window coordinates - * @param[in] size size [width, height] of the picking region in window coordinates - * @param[in] vp viewport as [x, y, width, height] - * @param[out] dest projected coordinates - */ -CGLM_INLINE -void -glm_pickmatrix(vec2 center, vec2 size, vec4 vp, mat4 dest) { - mat4 res; - vec3 v; - - if (size[0] <= 0.0f || size[1] <= 0.0f) - return; - - /* Translate and scale the picked region to the entire window */ - v[0] = (vp[2] - 2.0f * (center[0] - vp[0])) / size[0]; - v[1] = (vp[3] - 2.0f * (center[1] - vp[1])) / size[1]; - v[2] = 0.0f; - - glm_translate_make(res, v); - - v[0] = vp[2] / size[0]; - v[1] = vp[3] / size[1]; - v[2] = 1.0f; - - glm_scale(res, v); - - glm_mat4_copy(res, dest); -} - -#endif /* cglm_project_h */ diff --git a/external/cglm/quat.h b/external/cglm/quat.h deleted file mode 100644 index cf1f325..0000000 --- a/external/cglm/quat.h +++ /dev/null @@ -1,949 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_QUAT_IDENTITY_INIT - GLM_QUAT_IDENTITY - - Functions: - CGLM_INLINE void glm_quat_identity(versor q); - CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w); - CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z); - CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis); - CGLM_INLINE void glm_quat_copy(versor q, versor dest); - CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest); - CGLM_INLINE float glm_quat_norm(versor q); - CGLM_INLINE void glm_quat_normalize(versor q); - CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest); - CGLM_INLINE float glm_quat_dot(versor p, versor q); - CGLM_INLINE void glm_quat_conjugate(versor q, versor dest); - CGLM_INLINE void glm_quat_inv(versor q, versor dest); - CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest); - CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest); - CGLM_INLINE float glm_quat_real(versor q); - CGLM_INLINE void glm_quat_imag(versor q, vec3 dest); - CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest); - CGLM_INLINE float glm_quat_imaglen(versor q); - CGLM_INLINE float glm_quat_angle(versor q); - CGLM_INLINE void glm_quat_axis(versor q, vec3 dest); - CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest); - CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest); - CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest); - CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest); - CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest); - CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest); - CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest); - CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest); - CGLM_INLINE void glm_quat_slerp_longest(versor q, versor r, float t, versor dest); - CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest); - CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest); - CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest); - CGLM_INLINE void glm_quat_forp(vec3 from, - vec3 to, - vec3 fwd, - vec3 up, - versor dest); - CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest); - CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest); - CGLM_INLINE void glm_quat_make(float * restrict src, versor dest); - */ - -#ifndef cglm_quat_h -#define cglm_quat_h - -#include "common.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" -#include "mat3.h" -#include "affine-mat.h" -#include "affine.h" - -#ifdef CGLM_SSE_FP -# include "simd/sse2/quat.h" -#endif - -#ifdef CGLM_NEON_FP -# include "simd/neon/quat.h" -#endif - -#ifdef CGLM_SIMD_WASM -# include "simd/wasm/quat.h" -#endif - -CGLM_INLINE void glm_quat_normalize(versor q); - -/* - * IMPORTANT: - * ---------------------------------------------------------------------------- - * cglm stores quat as [x, y, z, w] since v0.3.6 - * - * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] - * with v0.3.6 version. - * ---------------------------------------------------------------------------- - */ - -#define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f} -#define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT) - -/*! - * @brief makes given quat to identity - * - * @param[in, out] q quaternion - */ -CGLM_INLINE -void -glm_quat_identity(versor q) { - CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; - glm_vec4_copy(v, q); -} - -/*! - * @brief make given quaternion array's each element identity quaternion - * - * @param[in, out] q quat array (must be aligned (16) - * if alignment is not disabled) - * - * @param[in] count count of quaternions - */ -CGLM_INLINE -void -glm_quat_identity_array(versor * __restrict q, size_t count) { - CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_vec4_copy(v, q[i]); - } -} - -/*! - * @brief inits quaternion with raw values - * - * @param[out] q quaternion - * @param[in] x x - * @param[in] y y - * @param[in] z z - * @param[in] w w (real part) - */ -CGLM_INLINE -void -glm_quat_init(versor q, float x, float y, float z, float w) { - q[0] = x; - q[1] = y; - q[2] = z; - q[3] = w; -} - -/*! - * @brief creates NEW quaternion with axis vector - * - * @param[out] q quaternion - * @param[in] angle angle (radians) - * @param[in] axis axis - */ -CGLM_INLINE -void -glm_quatv(versor q, float angle, vec3 axis) { - CGLM_ALIGN(8) vec3 k; - float a, c, s; - - a = angle * 0.5f; - c = cosf(a); - s = sinf(a); - - glm_normalize_to(axis, k); - - q[0] = s * k[0]; - q[1] = s * k[1]; - q[2] = s * k[2]; - q[3] = c; -} - -/*! - * @brief creates NEW quaternion with individual axis components - * - * @param[out] q quaternion - * @param[in] angle angle (radians) - * @param[in] x axis.x - * @param[in] y axis.y - * @param[in] z axis.z - */ -CGLM_INLINE -void -glm_quat(versor q, float angle, float x, float y, float z) { - CGLM_ALIGN(8) vec3 axis = {x, y, z}; - glm_quatv(q, angle, axis); -} - -/*! - * @brief copy quaternion to another one - * - * @param[in] q quaternion - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_quat_copy(versor q, versor dest) { - glm_vec4_copy(q, dest); -} - -/*! - * @brief compute quaternion rotating vector A to vector B - * - * @param[in] a vec3 (must have unit length) - * @param[in] b vec3 (must have unit length) - * @param[out] dest quaternion (of unit length) - */ -CGLM_INLINE -void -glm_quat_from_vecs(vec3 a, vec3 b, versor dest) { - CGLM_ALIGN(8) vec3 axis; - float cos_theta; - float cos_half_theta; - - cos_theta = glm_vec3_dot(a, b); - if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */ - glm_quat_identity(dest); - return; - } - if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */ - glm_vec3_ortho(a, axis); - cos_half_theta = 0.f; /* cos π/2 */ - } else { - glm_vec3_cross(a, b, axis); - cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */ - } - - glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta); - glm_quat_normalize(dest); -} - -/*! - * @brief returns norm (magnitude) of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glm_quat_norm(versor q) { - return glm_vec4_norm(q); -} - -/*! - * @brief normalize quaternion and store result in dest - * - * @param[in] q quaternion to normalze - * @param[out] dest destination quaternion - */ -CGLM_INLINE -void -glm_quat_normalize_to(versor q, versor dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_128 xdot, x0; - float dot; - - x0 = glmm_load(q); - xdot = glmm_vdot(x0, x0); - /* dot = _mm_cvtss_f32(xdot); */ - dot = wasm_f32x4_extract_lane(xdot, 0); - - if (dot <= 0.0f) { - glm_quat_identity(dest); - return; - } - - glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - __m128 xdot, x0; - float dot; - - x0 = glmm_load(q); - xdot = glmm_vdot(x0, x0); - dot = _mm_cvtss_f32(xdot); - - if (dot <= 0.0f) { - glm_quat_identity(dest); - return; - } - - glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot))); -#else - float dot; - - dot = glm_vec4_norm2(q); - - if (dot <= 0.0f) { - glm_quat_identity(dest); - return; - } - - glm_vec4_scale(q, 1.0f / sqrtf(dot), dest); -#endif -} - -/*! - * @brief normalize quaternion - * - * @param[in, out] q quaternion - */ -CGLM_INLINE -void -glm_quat_normalize(versor q) { - glm_quat_normalize_to(q, q); -} - -/*! - * @brief dot product of two quaternion - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - */ -CGLM_INLINE -float -glm_quat_dot(versor p, versor q) { - return glm_vec4_dot(p, q); -} - -/*! - * @brief conjugate of quaternion - * - * @param[in] q quaternion - * @param[out] dest conjugate - */ -CGLM_INLINE -void -glm_quat_conjugate(versor q, versor dest) { - glm_vec4_negate_to(q, dest); - dest[3] = -dest[3]; -} - -/*! - * @brief inverse of non-zero quaternion - * - * @param[in] q quaternion - * @param[out] dest inverse quaternion - */ -CGLM_INLINE -void -glm_quat_inv(versor q, versor dest) { - CGLM_ALIGN(16) versor conj; - glm_quat_conjugate(q, conj); - glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest); -} - -/*! - * @brief add (componentwise) two quaternions and store result in dest - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_add(versor p, versor q, versor dest) { - glm_vec4_add(p, q, dest); -} - -/*! - * @brief subtract (componentwise) two quaternions and store result in dest - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_sub(versor p, versor q, versor dest) { - glm_vec4_sub(p, q, dest); -} - -/*! - * @brief returns real part of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glm_quat_real(versor q) { - return q[3]; -} - -/*! - * @brief returns imaginary part of quaternion - * - * @param[in] q quaternion - * @param[out] dest imag - */ -CGLM_INLINE -void -glm_quat_imag(versor q, vec3 dest) { - dest[0] = q[0]; - dest[1] = q[1]; - dest[2] = q[2]; -} - -/*! - * @brief returns normalized imaginary part of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -void -glm_quat_imagn(versor q, vec3 dest) { - glm_normalize_to(q, dest); -} - -/*! - * @brief returns length of imaginary part of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glm_quat_imaglen(versor q) { - return glm_vec3_norm(q); -} - -/*! - * @brief returns angle of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glm_quat_angle(versor q) { - /* - sin(theta / 2) = length(x*x + y*y + z*z) - cos(theta / 2) = w - theta = 2 * atan(sin(theta / 2) / cos(theta / 2)) - */ - return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q)); -} - -/*! - * @brief axis of quaternion - * - * @param[in] q quaternion - * @param[out] dest axis of quaternion - */ -CGLM_INLINE -void -glm_quat_axis(versor q, vec3 dest) { - glm_quat_imagn(q, dest); -} - -/*! - * @brief multiplies two quaternion and stores result in dest - * this is also called Hamilton Product - * - * According to WikiPedia: - * The product of two rotation quaternions [clarification needed] will be - * equivalent to the rotation q followed by the rotation p - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_mul(versor p, versor q, versor dest) { - /* - + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i - + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j - + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k - a1 a2 − b1 b2 − c1 c2 − d1 d2 - */ -#if defined(__wasm__) && defined(__wasm_simd128__) - glm_quat_mul_wasm(p, q, dest); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glm_quat_mul_sse2(p, q, dest); -#elif defined(CGLM_NEON_FP) - glm_quat_mul_neon(p, q, dest); -#else - dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1]; - dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0]; - dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3]; - dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2]; -#endif -} - -/*! - * @brief convert quaternion to mat4 - * - * @param[in] q quaternion - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_quat_mat4(versor q, mat4 dest) { - float w, x, y, z, - xx, yy, zz, - xy, yz, xz, - wx, wy, wz, norm, s; - - norm = glm_quat_norm(q); - s = norm > 0.0f ? 2.0f / norm : 0.0f; - - x = q[0]; - y = q[1]; - z = q[2]; - w = q[3]; - - xx = s * x * x; xy = s * x * y; wx = s * w * x; - yy = s * y * y; yz = s * y * z; wy = s * w * y; - zz = s * z * z; xz = s * x * z; wz = s * w * z; - - dest[0][0] = 1.0f - yy - zz; - dest[1][1] = 1.0f - xx - zz; - dest[2][2] = 1.0f - xx - yy; - - dest[0][1] = xy + wz; - dest[1][2] = yz + wx; - dest[2][0] = xz + wy; - - dest[1][0] = xy - wz; - dest[2][1] = yz - wx; - dest[0][2] = xz - wy; - - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief convert quaternion to mat4 (transposed) - * - * @param[in] q quaternion - * @param[out] dest result matrix as transposed - */ -CGLM_INLINE -void -glm_quat_mat4t(versor q, mat4 dest) { - float w, x, y, z, - xx, yy, zz, - xy, yz, xz, - wx, wy, wz, norm, s; - - norm = glm_quat_norm(q); - s = norm > 0.0f ? 2.0f / norm : 0.0f; - - x = q[0]; - y = q[1]; - z = q[2]; - w = q[3]; - - xx = s * x * x; xy = s * x * y; wx = s * w * x; - yy = s * y * y; yz = s * y * z; wy = s * w * y; - zz = s * z * z; xz = s * x * z; wz = s * w * z; - - dest[0][0] = 1.0f - yy - zz; - dest[1][1] = 1.0f - xx - zz; - dest[2][2] = 1.0f - xx - yy; - - dest[1][0] = xy + wz; - dest[2][1] = yz + wx; - dest[0][2] = xz + wy; - - dest[0][1] = xy - wz; - dest[1][2] = yz - wx; - dest[2][0] = xz - wy; - - dest[0][3] = 0.0f; - dest[1][3] = 0.0f; - dest[2][3] = 0.0f; - dest[3][0] = 0.0f; - dest[3][1] = 0.0f; - dest[3][2] = 0.0f; - dest[3][3] = 1.0f; -} - -/*! - * @brief convert quaternion to mat3 - * - * @param[in] q quaternion - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_quat_mat3(versor q, mat3 dest) { - float w, x, y, z, - xx, yy, zz, - xy, yz, xz, - wx, wy, wz, norm, s; - - norm = glm_quat_norm(q); - s = norm > 0.0f ? 2.0f / norm : 0.0f; - - x = q[0]; - y = q[1]; - z = q[2]; - w = q[3]; - - xx = s * x * x; xy = s * x * y; wx = s * w * x; - yy = s * y * y; yz = s * y * z; wy = s * w * y; - zz = s * z * z; xz = s * x * z; wz = s * w * z; - - dest[0][0] = 1.0f - yy - zz; - dest[1][1] = 1.0f - xx - zz; - dest[2][2] = 1.0f - xx - yy; - - dest[0][1] = xy + wz; - dest[1][2] = yz + wx; - dest[2][0] = xz + wy; - - dest[1][0] = xy - wz; - dest[2][1] = yz - wx; - dest[0][2] = xz - wy; -} - -/*! - * @brief convert quaternion to mat3 (transposed) - * - * @param[in] q quaternion - * @param[out] dest result matrix - */ -CGLM_INLINE -void -glm_quat_mat3t(versor q, mat3 dest) { - float w, x, y, z, - xx, yy, zz, - xy, yz, xz, - wx, wy, wz, norm, s; - - norm = glm_quat_norm(q); - s = norm > 0.0f ? 2.0f / norm : 0.0f; - - x = q[0]; - y = q[1]; - z = q[2]; - w = q[3]; - - xx = s * x * x; xy = s * x * y; wx = s * w * x; - yy = s * y * y; yz = s * y * z; wy = s * w * y; - zz = s * z * z; xz = s * x * z; wz = s * w * z; - - dest[0][0] = 1.0f - yy - zz; - dest[1][1] = 1.0f - xx - zz; - dest[2][2] = 1.0f - xx - yy; - - dest[1][0] = xy + wz; - dest[2][1] = yz + wx; - dest[0][2] = xz + wy; - - dest[0][1] = xy - wz; - dest[1][2] = yz - wx; - dest[2][0] = xz - wy; -} - -/*! - * @brief interpolates between two quaternions - * using linear interpolation (LERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_lerp(versor from, versor to, float t, versor dest) { - glm_vec4_lerp(from, to, t, dest); -} - -/*! - * @brief interpolates between two quaternions - * using linear interpolation (LERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_lerpc(versor from, versor to, float t, versor dest) { - glm_vec4_lerpc(from, to, t, dest); -} - -/*! - * @brief interpolates between two quaternions - * taking the shortest rotation path using - * normalized linear interpolation (NLERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_nlerp(versor from, versor to, float t, versor dest) { - versor target; - float dot; - - dot = glm_vec4_dot(from, to); - - glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target); - glm_quat_lerp(from, target, t, dest); - glm_quat_normalize(dest); -} - -/*! - * @brief interpolates between two quaternions - * using spherical linear interpolation (SLERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t amount - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_slerp(versor from, versor to, float t, versor dest) { - CGLM_ALIGN(16) vec4 q1, q2; - float cosTheta, sinTheta, angle; - - cosTheta = glm_quat_dot(from, to); - glm_quat_copy(from, q1); - - if (fabsf(cosTheta) >= 1.0f) { - glm_quat_copy(q1, dest); - return; - } - - if (cosTheta < 0.0f) { - glm_vec4_negate(q1); - cosTheta = -cosTheta; - } - - sinTheta = sqrtf(1.0f - cosTheta * cosTheta); - - /* LERP to avoid zero division */ - if (fabsf(sinTheta) < 0.001f) { - glm_quat_lerp(from, to, t, dest); - return; - } - - /* SLERP */ - angle = acosf(cosTheta); - glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); - glm_vec4_scale(to, sinf(t * angle), q2); - - glm_vec4_add(q1, q2, q1); - glm_vec4_scale(q1, 1.0f / sinTheta, dest); -} - -/*! - * @brief interpolates between two quaternions - * using spherical linear interpolation (SLERP) and always takes the long path - * - * @param[in] from from - * @param[in] to to - * @param[in] t amount - * @param[out] dest result quaternion - */ -CGLM_INLINE -void -glm_quat_slerp_longest(versor from, versor to, float t, versor dest) { - CGLM_ALIGN(16) vec4 q1, q2; - float cosTheta, sinTheta, angle; - - cosTheta = glm_quat_dot(from, to); - glm_quat_copy(from, q1); - - if (fabsf(cosTheta) >= 1.0f) { - glm_quat_copy(q1, dest); - return; - } - - /* longest path */ - if (!(cosTheta < 0.0f)) { - glm_vec4_negate(q1); - cosTheta = -cosTheta; - } - - sinTheta = sqrtf(1.0f - cosTheta * cosTheta); - - /* LERP to avoid zero division */ - if (fabsf(sinTheta) < 0.001f) { - glm_quat_lerp(from, to, t, dest); - return; - } - - /* SLERP */ - angle = acosf(cosTheta); - glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1); - glm_vec4_scale(to, sinf(t * angle), q2); - - glm_vec4_add(q1, q2, q1); - glm_vec4_scale(q1, 1.0f / sinTheta, dest); -} - -/*! - * @brief creates view matrix using quaternion as camera orientation - * - * @param[in] eye eye - * @param[in] ori orientation in world space as quaternion - * @param[out] dest view matrix - */ -CGLM_INLINE -void -glm_quat_look(vec3 eye, versor ori, mat4 dest) { - /* orientation */ - glm_quat_mat4t(ori, dest); - - /* translate */ - glm_mat4_mulv3(dest, eye, 1.0f, dest[3]); - glm_vec3_negate(dest[3]); -} - -/*! - * @brief creates look rotation quaternion - * - * @param[in] dir direction to look - * @param[in] up up vector - * @param[out] dest destination quaternion - */ -CGLM_INLINE -void -glm_quat_for(vec3 dir, vec3 up, versor dest) { - CGLM_ALIGN_MAT mat3 m; - - glm_vec3_normalize_to(dir, m[2]); - - /* No need to negate in LH, but we use RH here */ - glm_vec3_negate(m[2]); - - glm_vec3_crossn(up, m[2], m[0]); - glm_vec3_cross(m[2], m[0], m[1]); - - glm_mat3_quat(m, dest); -} - -/*! - * @brief creates look rotation quaternion using source and - * destination positions p suffix stands for position - * - * @param[in] from source point - * @param[in] to destination point - * @param[in] up up vector - * @param[out] dest destination quaternion - */ -CGLM_INLINE -void -glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) { - CGLM_ALIGN(8) vec3 dir; - glm_vec3_sub(to, from, dir); - glm_quat_for(dir, up, dest); -} - -/*! - * @brief rotate vector using using quaternion - * - * @param[in] q quaternion - * @param[in] v vector to rotate - * @param[out] dest rotated vector - */ -CGLM_INLINE -void -glm_quat_rotatev(versor q, vec3 v, vec3 dest) { - CGLM_ALIGN(16) versor p; - CGLM_ALIGN(8) vec3 u, v1, v2; - float s; - - glm_quat_normalize_to(q, p); - glm_quat_imag(p, u); - s = glm_quat_real(p); - - glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1); - glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2); - glm_vec3_add(v1, v2, v1); - - glm_vec3_cross(u, v, v2); - glm_vec3_scale(v2, 2.0f * s, v2); - - glm_vec3_add(v1, v2, dest); -} - -/*! - * @brief rotate existing transform matrix using quaternion - * - * @param[in] m existing transform matrix - * @param[in] q quaternion - * @param[out] dest rotated matrix/transform - */ -CGLM_INLINE -void -glm_quat_rotate(mat4 m, versor q, mat4 dest) { - CGLM_ALIGN_MAT mat4 rot; - glm_quat_mat4(q, rot); - glm_mul_rot(m, rot, dest); -} - -/*! - * @brief rotate existing transform matrix using quaternion at pivot point - * - * @param[in, out] m existing transform matrix - * @param[in] q quaternion - * @param[out] pivot pivot - */ -CGLM_INLINE -void -glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) { - CGLM_ALIGN(8) vec3 pivotInv; - - glm_vec3_negate_to(pivot, pivotInv); - - glm_translate(m, pivot); - glm_quat_rotate(m, q, m); - glm_translate(m, pivotInv); -} - -/*! - * @brief rotate NEW transform matrix using quaternion at pivot point - * - * this creates rotation matrix, it assumes you don't have a matrix - * - * this should work faster than glm_quat_rotate_at because it reduces - * one glm_translate. - * - * @param[out] m existing transform matrix - * @param[in] q quaternion - * @param[in] pivot pivot - */ -CGLM_INLINE -void -glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) { - CGLM_ALIGN(8) vec3 pivotInv; - - glm_vec3_negate_to(pivot, pivotInv); - - glm_translate_make(m, pivot); - glm_quat_rotate(m, q, m); - glm_translate(m, pivotInv); -} - -/*! - * @brief Create quaternion from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest quaternion - */ -CGLM_INLINE -void -glm_quat_make(const float * __restrict src, versor dest) { - dest[0] = src[0]; dest[1] = src[1]; - dest[2] = src[2]; dest[3] = src[3]; -} - -#endif /* cglm_quat_h */ diff --git a/external/cglm/ray.h b/external/cglm/ray.h deleted file mode 100644 index d7831bc..0000000 --- a/external/cglm/ray.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE bool glm_ray_triangle(vec3 origin, - vec3 direction, - vec3 v0, - vec3 v1, - vec3 v2, - float *d); - CGLM_INLINE bool glm_ray_sphere(vec3 origin, - vec3 dir, - vec4 s, - float * __restrict t1, - float * __restrict t2) - CGLM_INLINE void glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point); -*/ - -#ifndef cglm_ray_h -#define cglm_ray_h - -#include "vec3.h" - -/*! - * @brief Möller–Trumbore ray-triangle intersection algorithm - * - * @param[in] origin origin of ray - * @param[in] direction direction of ray - * @param[in] v0 first vertex of triangle - * @param[in] v1 second vertex of triangle - * @param[in] v2 third vertex of triangle - * @param[in, out] d distance to intersection - * @return whether there is intersection - */ -CGLM_INLINE -bool -glm_ray_triangle(vec3 origin, - vec3 direction, - vec3 v0, - vec3 v1, - vec3 v2, - float *d) { - vec3 edge1, edge2, p, t, q; - float det, inv_det, u, v, dist; - const float epsilon = 0.000001f; - - glm_vec3_sub(v1, v0, edge1); - glm_vec3_sub(v2, v0, edge2); - glm_vec3_cross(direction, edge2, p); - - det = glm_vec3_dot(edge1, p); - if (det > -epsilon && det < epsilon) - return false; - - inv_det = 1.0f / det; - - glm_vec3_sub(origin, v0, t); - - u = inv_det * glm_vec3_dot(t, p); - if (u < 0.0f || u > 1.0f) - return false; - - glm_vec3_cross(t, edge1, q); - - v = inv_det * glm_vec3_dot(direction, q); - if (v < 0.0f || u + v > 1.0f) - return false; - - dist = inv_det * glm_vec3_dot(edge2, q); - - if (d) - *d = dist; - - return dist > epsilon; -} - -/*! - * @brief ray sphere intersection - * - * returns false if there is no intersection if true: - * - * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin - * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 - * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false ) - * - the caller can check if the intersection points (t1 and t2) fall within a - * specific range (for example, tmin < t1, t2 < tmax) to determine if the - * intersections are within a desired segment of the ray - * - * @param[in] origin ray origin - * @param[out] dir normalized ray direction - * @param[in] s sphere [center.x, center.y, center.z, radii] - * @param[in] t1 near point1 (closer to origin) - * @param[in] t2 far point2 (farther from origin) - * - * @returns whether there is intersection - */ -CGLM_INLINE -bool -glm_ray_sphere(vec3 origin, - vec3 dir, - vec4 s, - float * __restrict t1, - float * __restrict t2) { - vec3 dp; - float r2, ddp, dpp, dscr, q, tmp, _t1, _t2; - - glm_vec3_sub(s, origin, dp); - - ddp = glm_vec3_dot(dir, dp); - dpp = glm_vec3_norm2(dp); - - /* compute the remedy term for numerical stability */ - glm_vec3_mulsubs(dir, ddp, dp); /* dp: remedy term */ - - r2 = s[3] * s[3]; - dscr = r2 - glm_vec3_norm2(dp); - - if (dscr < 0.0f) { - /* no intersection */ - return false; - } - - dscr = sqrtf(dscr); - q = (ddp >= 0.0f) ? (ddp + dscr) : (ddp - dscr); - - /* - include Press, William H., Saul A. Teukolsky, - William T. Vetterling, and Brian P. Flannery, - "Numerical Recipes in C," Cambridge University Press, 1992. - */ - _t1 = q; - _t2 = (dpp - r2) / q; - - /* adjust t1 and t2 to ensure t1 is the closer intersection */ - if (_t1 > _t2) { - tmp = _t1; - _t1 = _t2; - _t2 = tmp; - } - - *t1 = _t1; - *t2 = _t2; - - /* check if the closest intersection (t1) is behind the ray's origin */ - if (_t1 < 0.0f && _t2 < 0.0f) { - /* both intersections are behind the ray, no visible intersection */ - return false; - } - - return true; -} - -/*! - * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛 - * - * @param[in] orig origin of ray - * @param[in] dir direction of ray - * @param[in] t parameter - * @param[out] point point at t - */ -CGLM_INLINE -void -glm_ray_at(vec3 orig, vec3 dir, float t, vec3 point) { - vec3 dst; - glm_vec3_scale(dir, t, dst); - glm_vec3_add(orig, dst, point); -} - -#endif diff --git a/external/cglm/simd/arm.h b/external/cglm/simd/arm.h deleted file mode 100644 index 9f51742..0000000 --- a/external/cglm/simd/arm.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_simd_arm_h -#define cglm_simd_arm_h -#include "intrin.h" -#ifdef CGLM_SIMD_ARM - -#if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || defined(__aarch64__) -# define CGLM_ARM64 1 -#else -# define CGLM_ARM64 0 -#endif - -#define glmm_load(p) vld1q_f32(p) -#define glmm_store(p, a) vst1q_f32(p, a) - -#define glmm_set1(x) vdupq_n_f32(x) -#define glmm_set1_ptr(x) vdupq_n_f32(*x) -#define glmm_set1_rval(x) vdupq_n_f32(x) -#define glmm_128 float32x4_t - -#define glmm_splat_x(x) vdupq_lane_f32(vget_low_f32(x), 0) -#define glmm_splat_y(x) vdupq_lane_f32(vget_low_f32(x), 1) -#define glmm_splat_z(x) vdupq_lane_f32(vget_high_f32(x), 0) -#define glmm_splat_w(x) vdupq_lane_f32(vget_high_f32(x), 1) - -#define glmm_xor(a, b) \ - vreinterpretq_f32_s32(veorq_s32(vreinterpretq_s32_f32(a), \ - vreinterpretq_s32_f32(b))) - -#define glmm_swplane(v) vextq_f32(v, v, 2) -#define glmm_low(x) vget_low_f32(x) -#define glmm_high(x) vget_high_f32(x) - -#define glmm_combine_ll(x, y) vcombine_f32(vget_low_f32(x), vget_low_f32(y)) -#define glmm_combine_hl(x, y) vcombine_f32(vget_high_f32(x), vget_low_f32(y)) -#define glmm_combine_lh(x, y) vcombine_f32(vget_low_f32(x), vget_high_f32(y)) -#define glmm_combine_hh(x, y) vcombine_f32(vget_high_f32(x), vget_high_f32(y)) - -#if defined(_WIN32) && defined(_MSC_VER) -/* # define glmm_float32x4_init(x, y, z, w) { .n128_f32 = { x, y, z, w } } */ -CGLM_INLINE -float32x4_t -glmm_float32x4_init(float x, float y, float z, float w) { - CGLM_ALIGN(16) float v[4] = {x, y, z, w}; - return vld1q_f32(v); -} -#else -# define glmm_float32x4_init(x, y, z, w) { x, y, z, w } -#endif - -#define glmm_float32x4_SIGNMASK_PNPN glmm_float32x4_init( 0.f, -0.f, 0.f, -0.f) -#define glmm_float32x4_SIGNMASK_NPNP glmm_float32x4_init(-0.f, 0.f, -0.f, 0.f) -#define glmm_float32x4_SIGNMASK_NPPN glmm_float32x4_init(-0.f, 0.f, 0.f, -0.f) - -static inline float32x4_t glmm_abs(float32x4_t v) { return vabsq_f32(v); } -static inline float32x4_t glmm_min(float32x4_t a, float32x4_t b) { return vminq_f32(a, b); } -static inline float32x4_t glmm_max(float32x4_t a, float32x4_t b) { return vmaxq_f32(a, b); } - -static inline -float32x4_t -glmm_vhadd(float32x4_t v) { -#if CGLM_ARM64 - float32x4_t p; - p = vpaddq_f32(v, v); /* [a+b, c+d, a+b, c+d] */ - return vpaddq_f32(p, p); /* [t, t, t, t] */; -#else - return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)), - vaddq_f32(glmm_splat_z(v), glmm_splat_w(v))); -#endif - /* TODO: measure speed of this compare to above */ - /* return vdupq_n_f32(vaddvq_f32(v)); */ - - /* - return vaddq_f32(vaddq_f32(glmm_splat_x(v), glmm_splat_y(v)), - vaddq_f32(glmm_splat_z(v), glmm_splat_w(v))); - */ - /* - this seems slower: - v = vaddq_f32(v, vrev64q_f32(v)); - return vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); - */ -} - -static inline -float -glmm_hadd(float32x4_t v) { -#if CGLM_ARM64 - return vaddvq_f32(v); -#else - v = vaddq_f32(v, vrev64q_f32(v)); - v = vaddq_f32(v, vcombine_f32(vget_high_f32(v), vget_low_f32(v))); - return vgetq_lane_f32(v, 0); -#endif -} - -static inline -float -glmm_hmin(float32x4_t v) { - float32x2_t t; - t = vpmin_f32(vget_low_f32(v), vget_high_f32(v)); - t = vpmin_f32(t, t); - return vget_lane_f32(t, 0); -} - -static inline -float -glmm_hmax(float32x4_t v) { - float32x2_t t; - t = vpmax_f32(vget_low_f32(v), vget_high_f32(v)); - t = vpmax_f32(t, t); - return vget_lane_f32(t, 0); -} - -static inline -float -glmm_dot(float32x4_t a, float32x4_t b) { - return glmm_hadd(vmulq_f32(a, b)); -} - -static inline -float32x4_t -glmm_vdot(float32x4_t a, float32x4_t b) { - return glmm_vhadd(vmulq_f32(a, b)); -} - -static inline -float -glmm_norm(float32x4_t a) { - return sqrtf(glmm_dot(a, a)); -} - -static inline -float -glmm_norm2(float32x4_t a) { - return glmm_dot(a, a); -} - -static inline -float -glmm_norm_one(float32x4_t a) { - return glmm_hadd(glmm_abs(a)); -} - -static inline -float -glmm_norm_inf(float32x4_t a) { - return glmm_hmax(glmm_abs(a)); -} - -static inline -float32x4_t -glmm_div(float32x4_t a, float32x4_t b) { -#if CGLM_ARM64 - return vdivq_f32(a, b); -#else - /* 2 iterations of Newton-Raphson refinement of reciprocal */ - float32x4_t r0, r1; - r0 = vrecpeq_f32(b); - r1 = vrecpsq_f32(r0, b); - r0 = vmulq_f32(r1, r0); - r1 = vrecpsq_f32(r0, b); - r0 = vmulq_f32(r1, r0); - return vmulq_f32(a, r0); -#endif -} - -static inline -float32x4_t -glmm_fmadd(float32x4_t a, float32x4_t b, float32x4_t c) { -#if CGLM_ARM64 - return vfmaq_f32(c, a, b); /* why vfmaq_f32 is slower than vmlaq_f32 ??? */ -#else - return vmlaq_f32(c, a, b); -#endif -} - -static inline -float32x4_t -glmm_fnmadd(float32x4_t a, float32x4_t b, float32x4_t c) { -#if CGLM_ARM64 - return vfmsq_f32(c, a, b); -#else - return vmlsq_f32(c, a, b); -#endif -} - -static inline -float32x4_t -glmm_fmsub(float32x4_t a, float32x4_t b, float32x4_t c) { - return glmm_fmadd(a, b, vnegq_f32(c)); -} - -static inline -float32x4_t -glmm_fnmsub(float32x4_t a, float32x4_t b, float32x4_t c) { - return vsubq_f32(vdupq_n_f32(0.0f), glmm_fmadd(a, b, c)); -} - -#endif -#endif /* cglm_simd_arm_h */ diff --git a/external/cglm/simd/avx/affine.h b/external/cglm/simd/avx/affine.h deleted file mode 100644 index b02ff0c..0000000 --- a/external/cglm/simd/avx/affine.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_mat_avx_h -#define cglm_affine_mat_avx_h -#ifdef __AVX__ - -#include "../../common.h" -#include "../intrin.h" - -#include - -CGLM_INLINE -void -glm_mul_avx(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9; - - y0 = glmm_load256(m2[0]); /* h g f e d c b a */ - y1 = glmm_load256(m2[2]); /* p o n m l k j i */ - - y2 = glmm_load256(m1[0]); /* h g f e d c b a */ - y3 = glmm_load256(m1[2]); /* p o n m l k j i */ - - /* 0x03: 0b00000011 */ - y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ - y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ - - /* f f f f a a a a */ - /* h h h h c c c c */ - /* e e e e b b b b */ - /* g g g g d d d d */ - y6 = _mm256_permutevar_ps(y0, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); - y7 = _mm256_permutevar_ps(y0, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); - y8 = _mm256_permutevar_ps(y0, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); - y9 = _mm256_permutevar_ps(y0, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); - - glmm_store256(dest[0], - _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), - _mm256_mul_ps(y3, y7)), - _mm256_add_ps(_mm256_mul_ps(y4, y8), - _mm256_mul_ps(y5, y9)))); - - /* n n n n i i i i */ - /* p p p p k k k k */ - /* m m m m j j j j */ - /* o o o o l l l l */ - y6 = _mm256_permutevar_ps(y1, _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0)); - y7 = _mm256_permutevar_ps(y1, _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2)); - y8 = _mm256_permutevar_ps(y1, _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1)); - y9 = _mm256_permutevar_ps(y1, _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3)); - - glmm_store256(dest[2], - _mm256_add_ps(_mm256_add_ps(_mm256_mul_ps(y2, y6), - _mm256_mul_ps(y3, y7)), - _mm256_add_ps(_mm256_mul_ps(y4, y8), - _mm256_mul_ps(y5, y9)))); -} - -#endif -#endif /* cglm_affine_mat_avx_h */ diff --git a/external/cglm/simd/avx/mat4.h b/external/cglm/simd/avx/mat4.h deleted file mode 100644 index 33771c2..0000000 --- a/external/cglm/simd/avx/mat4.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat_simd_avx_h -#define cglm_mat_simd_avx_h -#ifdef __AVX__ - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat4_scale_avx(mat4 m, float s) { - __m256 y0, y1, y2, y3, y4; - - y0 = glmm_load256(m[0]); /* h g f e d c b a */ - y1 = glmm_load256(m[2]); /* p o n m l k j i */ - - y2 = _mm256_broadcast_ss(&s); - - y3 = _mm256_mul_ps(y0, y2); - y4 = _mm256_mul_ps(y1, y2); - - glmm_store256(m[0], y3); - glmm_store256(m[2], y4); -} - -/* TODO: this must be tested and compared to SSE version, may be slower!!! */ -CGLM_INLINE -void -glm_mat4_transp_avx(mat4 m, mat4 dest) { - __m256 y0, y1, y2, y3; - - y0 = glmm_load256(m[0]); /* h g f e d c b a */ - y1 = glmm_load256(m[2]); /* p o n m l k j i */ - - y2 = _mm256_unpacklo_ps(y0, y1); /* n f m e j b i a */ - y3 = _mm256_unpackhi_ps(y0, y1); /* p h o g l d k c */ - - y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* l d k c j b i a */ - y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p h o g n f m e */ - - y2 = _mm256_unpacklo_ps(y0, y1); /* o k g c m i e a */ - y3 = _mm256_unpackhi_ps(y0, y1); /* p l h d n j f b */ - - y0 = _mm256_permute2f128_ps(y2, y3, 0x20); /* n j f b m i e a */ - y1 = _mm256_permute2f128_ps(y2, y3, 0x31); /* p l h d o k g c */ - - glmm_store256(dest[0], y0); - glmm_store256(dest[2], y1); -} - -CGLM_INLINE -void -glm_mat4_mul_avx(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - __m256 y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13; - __m256i yi0, yi1, yi2, yi3; - - y0 = glmm_load256(m2[0]); /* h g f e d c b a */ - y1 = glmm_load256(m2[2]); /* p o n m l k j i */ - - y2 = glmm_load256(m1[0]); /* h g f e d c b a */ - y3 = glmm_load256(m1[2]); /* p o n m l k j i */ - - /* 0x03: 0b00000011 */ - y4 = _mm256_permute2f128_ps(y2, y2, 0x03); /* d c b a h g f e */ - y5 = _mm256_permute2f128_ps(y3, y3, 0x03); /* l k j i p o n m */ - - yi0 = _mm256_set_epi32(1, 1, 1, 1, 0, 0, 0, 0); - yi1 = _mm256_set_epi32(3, 3, 3, 3, 2, 2, 2, 2); - yi2 = _mm256_set_epi32(0, 0, 0, 0, 1, 1, 1, 1); - yi3 = _mm256_set_epi32(2, 2, 2, 2, 3, 3, 3, 3); - - /* f f f f a a a a */ - /* h h h h c c c c */ - /* e e e e b b b b */ - /* g g g g d d d d */ - y6 = _mm256_permutevar_ps(y0, yi0); - y7 = _mm256_permutevar_ps(y0, yi1); - y8 = _mm256_permutevar_ps(y0, yi2); - y9 = _mm256_permutevar_ps(y0, yi3); - - /* n n n n i i i i */ - /* p p p p k k k k */ - /* m m m m j j j j */ - /* o o o o l l l l */ - y10 = _mm256_permutevar_ps(y1, yi0); - y11 = _mm256_permutevar_ps(y1, yi1); - y12 = _mm256_permutevar_ps(y1, yi2); - y13 = _mm256_permutevar_ps(y1, yi3); - - y0 = _mm256_mul_ps(y2, y6); - y1 = _mm256_mul_ps(y2, y10); - - y0 = glmm256_fmadd(y3, y7, y0); - y1 = glmm256_fmadd(y3, y11, y1); - - y0 = glmm256_fmadd(y4, y8, y0); - y1 = glmm256_fmadd(y4, y12, y1); - - y0 = glmm256_fmadd(y5, y9, y0); - y1 = glmm256_fmadd(y5, y13, y1); - - glmm_store256(dest[0], y0); - glmm_store256(dest[2], y1); -} - -#endif -#endif /* cglm_mat_simd_avx_h */ diff --git a/external/cglm/simd/intrin.h b/external/cglm/simd/intrin.h deleted file mode 100644 index c477f34..0000000 --- a/external/cglm/simd/intrin.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_intrin_h -#define cglm_intrin_h - -#if defined(_MSC_VER) && !defined(_M_ARM64EC) -# if (defined(_M_AMD64) || defined(_M_X64)) || _M_IX86_FP == 2 -# ifndef __SSE__ -# define __SSE__ -# endif -# ifndef __SSE2__ -# define __SSE2__ -# endif -# elif _M_IX86_FP == 1 -# ifndef __SSE__ -# define __SSE__ -# endif -# endif -/* do not use alignment for older visual studio versions */ -/* also ARM32 also causes similar error, disable it for now on ARM32 too */ -# if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */ -# define CGLM_ALL_UNALIGNED -# endif -#endif - -#ifdef __AVX__ -# include -# define CGLM_AVX_FP 1 -# ifndef __SSE2__ -# define __SSE2__ -# endif -# ifndef __SSE3__ -# define __SSE3__ -# endif -# ifndef __SSE4__ -# define __SSE4__ -# endif -# ifndef __SSE4_1__ -# define __SSE4_1__ -# endif -# ifndef __SSE4_2__ -# define __SSE4_2__ -# endif -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -#if defined(__SSE__) -# include -# define CGLM_SSE_FP 1 -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -#if defined(__SSE2__) -# include -# define CGLM_SSE2_FP 1 -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -#if defined(__SSE3__) -# include -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -#if defined(__SSE4_1__) -# include -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -#if defined(__SSE4_2__) -# include -# ifndef CGLM_SIMD_x86 -# define CGLM_SIMD_x86 -# endif -#endif - -/* ARM Neon */ -#if defined(_WIN32) && defined(_MSC_VER) -/* TODO: non-ARM stuff already inported, will this be better option */ -/* # include */ - -# if defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) -# include -# include -# ifndef CGLM_NEON_FP -# define CGLM_NEON_FP 1 -# endif -# ifndef CGLM_SIMD_ARM -# define CGLM_SIMD_ARM -# endif -# elif defined(_M_ARM) -# include -# include -# ifndef CGLM_NEON_FP -# define CGLM_NEON_FP 1 -# endif -# ifndef CGLM_SIMD_ARM -# define CGLM_SIMD_ARM -# endif -# endif - -#else /* non-windows */ -# if defined(__ARM_NEON) || defined(__ARM_NEON__) -# include -# if defined(__ARM_NEON_FP) || defined(__ARM_FP) -# define CGLM_NEON_FP 1 -# endif -# ifndef CGLM_SIMD_ARM -# define CGLM_SIMD_ARM -# endif -# endif -#endif - -/* WebAssembly */ -#if defined(__wasm__) && defined(__wasm_simd128__) -# ifndef CGLM_SIMD_WASM -# define CGLM_SIMD_WASM -# endif -#endif - -#if defined(CGLM_SIMD_x86) || defined(CGLM_SIMD_ARM) || defined(CGLM_SIMD_WASM) -# ifndef CGLM_SIMD -# define CGLM_SIMD -# endif -#endif - -#if defined(CGLM_SIMD_x86) && !defined(CGLM_SIMD_WASM) -# include "x86.h" -#endif - -#if defined(CGLM_SIMD_ARM) -# include "arm.h" -#endif - -#if defined(CGLM_SIMD_WASM) -# include "wasm.h" -#endif - -#endif /* cglm_intrin_h */ diff --git a/external/cglm/simd/neon/affine.h b/external/cglm/simd/neon/affine.h deleted file mode 100644 index b0a65a6..0000000 --- a/external/cglm/simd/neon/affine.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_neon_h -#define cglm_affine_neon_h -#if defined(CGLM_NEON_FP) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mul_neon(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = vmulq_f32(glmm_splat_x(r0), l); - v1 = vmulq_f32(glmm_splat_x(r1), l); - v2 = vmulq_f32(glmm_splat_x(r2), l); - v3 = vmulq_f32(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - v3 = glmm_fmadd(glmm_splat_w(r3), glmm_load(m1[3]), v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mul_rot_neon(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, v0, v1, v2; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - - v0 = vmulq_f32(glmm_splat_x(r0), l); - v1 = vmulq_f32(glmm_splat_x(r1), l); - v2 = vmulq_f32(glmm_splat_x(r2), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], glmm_load(m1[3])); -} - -CGLM_INLINE -void -glm_inv_tr_neon(mat4 mat) { - float32x4x4_t vmat; - glmm_128 r0, r1, r2, x0; - - vmat = vld4q_f32(mat[0]); - r0 = vmat.val[0]; - r1 = vmat.val[1]; - r2 = vmat.val[2]; - - x0 = glmm_fmadd(r0, glmm_splat_w(r0), - glmm_fmadd(r1, glmm_splat_w(r1), - vmulq_f32(r2, glmm_splat_w(r2)))); - x0 = vnegq_f32(x0); - - glmm_store(mat[0], r0); - glmm_store(mat[1], r1); - glmm_store(mat[2], r2); - glmm_store(mat[3], x0); - - mat[0][3] = 0.0f; - mat[1][3] = 0.0f; - mat[2][3] = 0.0f; - mat[3][3] = 1.0f; - - /* TODO: ? - zo = vget_high_f32(r3); - vst1_lane_f32(&mat[0][3], zo, 0); - vst1_lane_f32(&mat[1][3], zo, 0); - vst1_lane_f32(&mat[2][3], zo, 0); - vst1_lane_f32(&mat[3][3], zo, 1); - */ -} - -#endif -#endif /* cglm_affine_neon_h */ diff --git a/external/cglm/simd/neon/mat2.h b/external/cglm/simd/neon/mat2.h deleted file mode 100644 index 7d0d9eb..0000000 --- a/external/cglm/simd/neon/mat2.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat2_neon_h -#define cglm_mat2_neon_h -#if defined(CGLM_NEON_FP) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat2_mul_neon(mat2 m1, mat2 m2, mat2 dest) { - float32x4x2_t a1; - glmm_128 x0, x1, x2; - float32x2_t dc, ba; - - x1 = glmm_load(m1[0]); /* d c b a */ - x2 = glmm_load(m2[0]); /* h g f e */ - - dc = vget_high_f32(x1); - ba = vget_low_f32(x1); - - /* g g e e, h h f f */ - a1 = vtrnq_f32(x2, x2); - - /* - dest[0][0] = a * e + c * f; - dest[0][1] = b * e + d * f; - dest[1][0] = a * g + c * h; - dest[1][1] = b * g + d * h; - */ - x0 = glmm_fmadd(vcombine_f32(ba, ba), a1.val[0], - vmulq_f32(vcombine_f32(dc, dc), a1.val[1])); - - glmm_store(dest[0], x0); -} - -#endif -#endif /* cglm_mat2_neon_h */ diff --git a/external/cglm/simd/neon/mat4.h b/external/cglm/simd/neon/mat4.h deleted file mode 100644 index 6cf9811..0000000 --- a/external/cglm/simd/neon/mat4.h +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat4_neon_h -#define cglm_mat4_neon_h -#if defined(CGLM_NEON_FP) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat4_scale_neon(mat4 m, float s) { - float32x4_t v0; - - v0 = vdupq_n_f32(s); - - vst1q_f32(m[0], vmulq_f32(vld1q_f32(m[0]), v0)); - vst1q_f32(m[1], vmulq_f32(vld1q_f32(m[1]), v0)); - vst1q_f32(m[2], vmulq_f32(vld1q_f32(m[2]), v0)); - vst1q_f32(m[3], vmulq_f32(vld1q_f32(m[3]), v0)); -} - -CGLM_INLINE -void -glm_mat4_transp_neon(mat4 m, mat4 dest) { - float32x4x4_t vmat; - - vmat = vld4q_f32(m[0]); - - vst1q_f32(dest[0], vmat.val[0]); - vst1q_f32(dest[1], vmat.val[1]); - vst1q_f32(dest[2], vmat.val[2]); - vst1q_f32(dest[3], vmat.val[3]); -} - -CGLM_INLINE -void -glm_mat4_mul_neon(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = vmulq_f32(glmm_splat_x(r0), l); - v1 = vmulq_f32(glmm_splat_x(r1), l); - v2 = vmulq_f32(glmm_splat_x(r2), l); - v3 = vmulq_f32(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - l = glmm_load(m1[3]); - v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mat4_mulv_neon(mat4 m, vec4 v, vec4 dest) { - float32x4_t l0, l1, l2, l3; - float32x2_t vlo, vhi; - - l0 = vld1q_f32(m[0]); - l1 = vld1q_f32(m[1]); - l2 = vld1q_f32(m[2]); - l3 = vld1q_f32(m[3]); - - vlo = vld1_f32(&v[0]); - vhi = vld1_f32(&v[2]); - - l0 = vmulq_lane_f32(l0, vlo, 0); - l0 = vmlaq_lane_f32(l0, l1, vlo, 1); - l0 = vmlaq_lane_f32(l0, l2, vhi, 0); - l0 = vmlaq_lane_f32(l0, l3, vhi, 1); - - vst1q_f32(dest, l0); -} - -CGLM_INLINE -float -glm_mat4_det_neon(mat4 mat) { - float32x4_t r0, r1, r2, r3, x0, x1, x2; - float32x2_t ij, op, mn, kl, nn, mm, jj, ii, gh, ef, t12, t34; - float32x4x2_t a1; - float32x4_t x3 = glmm_float32x4_SIGNMASK_PNPN; - - /* 127 <- 0, [square] det(A) = det(At) */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = vrev64q_f32(glmm_load(mat[1])); /* g h e f */ - r2 = vrev64q_f32(glmm_load(mat[2])); /* l k i j */ - r3 = vrev64q_f32(glmm_load(mat[3])); /* o p m n */ - - gh = vget_high_f32(r1); - ef = vget_low_f32(r1); - kl = vget_high_f32(r2); - ij = vget_low_f32(r2); - op = vget_high_f32(r3); - mn = vget_low_f32(r3); - mm = vdup_lane_f32(mn, 1); - nn = vdup_lane_f32(mn, 0); - ii = vdup_lane_f32(ij, 1); - jj = vdup_lane_f32(ij, 0); - - /* - t[1] = j * p - n * l; - t[2] = j * o - n * k; - t[3] = i * p - m * l; - t[4] = i * o - m * k; - */ - x0 = glmm_fnmadd(vcombine_f32(kl, kl), vcombine_f32(nn, mm), - vmulq_f32(vcombine_f32(op, op), vcombine_f32(jj, ii))); - - t12 = vget_low_f32(x0); - t34 = vget_high_f32(x0); - - /* 1 3 1 3 2 4 2 4 */ - a1 = vuzpq_f32(x0, x0); - - /* - t[0] = k * p - o * l; - t[0] = k * p - o * l; - t[5] = i * n - m * j; - t[5] = i * n - m * j; - */ - x1 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(kl, 0), jj), - vcombine_f32(vdup_lane_f32(op, 1), mm), - vmulq_f32(vcombine_f32(vdup_lane_f32(op, 0), nn), - vcombine_f32(vdup_lane_f32(kl, 1), ii))); - - /* - a * (f * t[0] - g * t[1] + h * t[2]) - - b * (e * t[0] - g * t[3] + h * t[4]) - + c * (e * t[1] - f * t[3] + h * t[5]) - - d * (e * t[2] - f * t[4] + g * t[5]) - */ - x2 = glmm_fnmadd(vcombine_f32(vdup_lane_f32(gh, 1), vdup_lane_f32(ef, 0)), - vcombine_f32(vget_low_f32(a1.val[0]), t34), - vmulq_f32(vcombine_f32(ef, vdup_lane_f32(ef, 1)), - vcombine_f32(vget_low_f32(x1), t12))); - - x2 = glmm_fmadd(vcombine_f32(vdup_lane_f32(gh, 0), gh), - vcombine_f32(vget_low_f32(a1.val[1]), vget_high_f32(x1)), x2); - - x2 = glmm_xor(x2, x3); - - return glmm_hadd(vmulq_f32(x2, r0)); -} - -/* old one */ -#if 0 -CGLM_INLINE -void -glm_mat4_inv_neon(mat4 mat, mat4 dest) { - float32x4_t r0, r1, r2, r3, - v0, v1, v2, v3, - t0, t1, t2, t3, t4, t5, - x0, x1, x2, x3, x4, x5, x6, x7, x8; - float32x4x2_t a1; - float32x2_t lp, ko, hg, jn, im, fe, ae, bf, cg, dh; - float32x4_t x9 = glmm_float32x4_SIGNMASK_NPNP; - - x8 = vrev64q_f32(x9); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - /* l p k o, j n i m */ - a1 = vzipq_f32(r3, r2); - - jn = vget_high_f32(a1.val[0]); - im = vget_low_f32(a1.val[0]); - lp = vget_high_f32(a1.val[1]); - ko = vget_low_f32(a1.val[1]); - hg = vget_high_f32(r1); - - x1 = vcombine_f32(vdup_lane_f32(lp, 0), lp); /* l p p p */ - x2 = vcombine_f32(vdup_lane_f32(ko, 0), ko); /* k o o o */ - x0 = vcombine_f32(vdup_lane_f32(lp, 1), vdup_lane_f32(hg, 1)); /* h h l l */ - x3 = vcombine_f32(vdup_lane_f32(ko, 1), vdup_lane_f32(hg, 0)); /* g g k k */ - - /* t1[0] = k * p - o * l; - t1[0] = k * p - o * l; - t2[0] = g * p - o * h; - t3[0] = g * l - k * h; */ - t0 = glmm_fnmadd(x2, x0, vmulq_f32(x3, x1)); - - fe = vget_low_f32(r1); - x4 = vcombine_f32(vdup_lane_f32(jn, 0), jn); /* j n n n */ - x5 = vcombine_f32(vdup_lane_f32(jn, 1), vdup_lane_f32(fe, 1)); /* f f j j */ - - /* t1[1] = j * p - n * l; - t1[1] = j * p - n * l; - t2[1] = f * p - n * h; - t3[1] = f * l - j * h; */ - t1 = glmm_fnmadd(x4, x0, vmulq_f32(x5, x1)); - - /* t1[2] = j * o - n * k - t1[2] = j * o - n * k; - t2[2] = f * o - n * g; - t3[2] = f * k - j * g; */ - t2 = glmm_fnmadd(x4, x3, vmulq_f32(x5, x2)); - - x6 = vcombine_f32(vdup_lane_f32(im, 1), vdup_lane_f32(fe, 0)); /* e e i i */ - x7 = vcombine_f32(vdup_lane_f32(im, 0), im); /* i m m m */ - - /* t1[3] = i * p - m * l; - t1[3] = i * p - m * l; - t2[3] = e * p - m * h; - t3[3] = e * l - i * h; */ - t3 = glmm_fnmadd(x7, x0, vmulq_f32(x6, x1)); - - /* t1[4] = i * o - m * k; - t1[4] = i * o - m * k; - t2[4] = e * o - m * g; - t3[4] = e * k - i * g; */ - t4 = glmm_fnmadd(x7, x3, vmulq_f32(x6, x2)); - - /* t1[5] = i * n - m * j; - t1[5] = i * n - m * j; - t2[5] = e * n - m * f; - t3[5] = e * j - i * f; */ - t5 = glmm_fnmadd(x7, x5, vmulq_f32(x6, x4)); - - /* h d f b, g c e a */ - a1 = vtrnq_f32(r0, r1); - - x4 = vrev64q_f32(a1.val[0]); /* c g a e */ - x5 = vrev64q_f32(a1.val[1]); /* d h b f */ - - ae = vget_low_f32(x4); - cg = vget_high_f32(x4); - bf = vget_low_f32(x5); - dh = vget_high_f32(x5); - - x0 = vcombine_f32(ae, vdup_lane_f32(ae, 1)); /* a a a e */ - x1 = vcombine_f32(bf, vdup_lane_f32(bf, 1)); /* b b b f */ - x2 = vcombine_f32(cg, vdup_lane_f32(cg, 1)); /* c c c g */ - x3 = vcombine_f32(dh, vdup_lane_f32(dh, 1)); /* d d d h */ - - /* - dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; - dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); - dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; - dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ - v0 = glmm_xor(glmm_fmadd(x3, t2, glmm_fnmadd(x2, t1, vmulq_f32(x1, t0))), x8); - - /* - dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; - dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); - dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; - dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ - v2 = glmm_xor(glmm_fmadd(x3, t5, glmm_fnmadd(x1, t3, vmulq_f32(x0, t1))), x8); - - /* - dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); - dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; - dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); - dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ - v1 = glmm_xor(glmm_fmadd(x3, t4, glmm_fnmadd(x2, t3, vmulq_f32(x0, t0))), x9); - - /* - dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); - dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; - dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); - dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ - v3 = glmm_xor(glmm_fmadd(x2, t5, glmm_fnmadd(x1, t4, vmulq_f32(x0, t2))), x9); - - /* determinant */ - x0 = vcombine_f32(vget_low_f32(vzipq_f32(v0, v1).val[0]), - vget_low_f32(vzipq_f32(v2, v3).val[0])); - - /* - x0 = glmm_div(glmm_set1_rval(1.0f), glmm_vhadd(vmulq_f32(x0, r0))); - - glmm_store(dest[0], vmulq_f32(v0, x0)); - glmm_store(dest[1], vmulq_f32(v1, x0)); - glmm_store(dest[2], vmulq_f32(v2, x0)); - glmm_store(dest[3], vmulq_f32(v3, x0)); - */ - - x0 = glmm_vhadd(vmulq_f32(x0, r0)); - - glmm_store(dest[0], glmm_div(v0, x0)); - glmm_store(dest[1], glmm_div(v1, x0)); - glmm_store(dest[2], glmm_div(v2, x0)); - glmm_store(dest[3], glmm_div(v3, x0)); -} -#endif - -CGLM_INLINE -void -glm_mat4_inv_neon(mat4 mat, mat4 dest) { - float32x4_t r0, r1, r2, r3, - v0, v1, v2, v3, v4, v5, - t0, t1, t2; - float32x4x2_t a0, a1, a2, a3, a4; - float32x4_t s1 = glmm_float32x4_SIGNMASK_PNPN, s2; - -#if !CGLM_ARM64 - float32x2_t l0, l1; -#endif - - s2 = vrev64q_f32(s1); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - a1 = vzipq_f32(r0, r2); /* l d k c, j b i a */ - a2 = vzipq_f32(r1, r3); /* p h o g, n f m e */ - a3 = vzipq_f32(a2.val[0], a1.val[0]); /* j n b f, i m a e */ - a4 = vzipq_f32(a2.val[1], a1.val[1]); /* l p d h, k o c g */ - - v0 = vextq_f32(a1.val[0], a1.val[1], 2); /* k c j b */ - v1 = vextq_f32(a2.val[0], a2.val[1], 2); /* o g n f */ - v2 = vextq_f32(a1.val[1], a2.val[0], 2); /* m e l d */ - v3 = vextq_f32(a2.val[1], a1.val[0], 2); /* i a p h */ - v4 = vextq_f32(v1, v2, 2); /* l d o g */ - v5 = vextq_f32(v0, v3, 2); /* p h k c */ - - /* c2 = c * h - g * d c12 = a * g - c * e c8 = a * f - b * e - c1 = k * p - o * l c11 = i * o - k * m c7 = i * n - j * m - c4 = h * a - d * e c6 = b * h - d * f c10 = b * g - c * f - c3 = p * i - l * m c5 = j * p - l * n c9 = j * o - k * n */ - t0 = vmulq_f32(v5, v3); - t1 = vmulq_f32(a1.val[0], a2.val[1]); - t2 = vmulq_f32(a1.val[0], v1); - - t0 = glmm_fnmadd(v4, v2, t0); - t1 = glmm_fnmadd(a1.val[1], a2.val[0], t1); - t2 = glmm_fnmadd(v0, a2.val[0], t2); - - t0 = vrev64q_f32(t0); - t1 = vrev64q_f32(t1); - t2 = vrev64q_f32(t2); - - /* det */ - v0 = vrev64q_f32(t2); - v1 = vextq_f32(t1, t1, 2); - v0 = vmulq_f32(t0, v0); - v1 = vrev64q_f32(v1); - v1 = vmulq_f32(v1, t1); - - /* c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */ -#if CGLM_ARM64 - v0 = vpaddq_f32(v0, v0); - v0 = vpaddq_f32(v0, v0); -#else - l0 = vget_low_f32(v0); - l1 = vget_high_f32(v0); - - l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */ - l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */ - l0 = vadd_f32(l0, l1); /* [sum, sum] */ - - v0 = vcombine_f32(l0, l0); -#endif - - /* c5 * c12 + c6 * c11 */ -#if CGLM_ARM64 - v1 = vpaddq_f32(v1, v1); -#else - l0 = vget_low_f32(v1); - l1 = vget_high_f32(v1); - - l0 = vpadd_f32(l0, l0); /* [a+b, a+b] */ - l1 = vpadd_f32(l1, l1); /* [c+d, c+d] */ - - v1 = vcombine_f32(l0, l1); -#endif - - v0 = vsubq_f32(v0, v1); /* det */ - - /* inv div */ - v1 = vdupq_n_f32(1.0f); - v0 = glmm_div(v1, v0); /* inv div */ - - /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */ - t0 = vmulq_f32(t0, v0); - t1 = vmulq_f32(t1, v0); - t2 = vmulq_f32(t2, v0); - - a0 = vzipq_f32(t0, t0); /* c4 c4 c3 c3, c2 c2 c1 c1 */ - a1 = vzipq_f32(t1, t1); /* c6 c6 c5 c5, c12 c12 c11 c11 */ - a2 = vzipq_f32(t2, t2); /* c10 c10 c9 c9, c8 c8 c7 c7 */ - - /* result */ - - /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; - dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; - dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; - dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; - - dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; - dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; - dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; - dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; - - dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; - dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; - dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; - dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; - - dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; - dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; - dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; - dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */ - - r0 = vmulq_f32(a3.val[1], a0.val[0]); - r1 = vmulq_f32(a3.val[0], a0.val[0]); - r2 = vmulq_f32(a3.val[0], a1.val[1]); - r3 = vmulq_f32(a3.val[0], a2.val[1]); - - r0 = glmm_fnmadd(a4.val[0], a1.val[1], r0); - r1 = glmm_fnmadd(a4.val[0], a0.val[1], r1); - r2 = glmm_fnmadd(a3.val[1], a0.val[1], r2); - r3 = glmm_fnmadd(a3.val[1], a1.val[0], r3); - - r0 = glmm_fmadd(a4.val[1], a2.val[1], r0); - r1 = glmm_fmadd(a4.val[1], a1.val[0], r1); - r2 = glmm_fmadd(a4.val[1], a2.val[0], r2); - r3 = glmm_fmadd(a4.val[0], a2.val[0], r3); - - /* 4xor may be fastart then 4mul, see above */ - r0 = glmm_xor(r0, s1); - r1 = glmm_xor(r1, s2); - r2 = glmm_xor(r2, s1); - r3 = glmm_xor(r3, s2); - - glmm_store(dest[0], r0); - glmm_store(dest[1], r1); - glmm_store(dest[2], r2); - glmm_store(dest[3], r3); -} - -#endif -#endif /* cglm_mat4_neon_h */ diff --git a/external/cglm/simd/neon/quat.h b/external/cglm/simd/neon/quat.h deleted file mode 100644 index 55dc1da..0000000 --- a/external/cglm/simd/neon/quat.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_quat_neon_h -#define cglm_quat_neon_h -#if defined(CGLM_NEON_FP) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_quat_mul_neon(versor p, versor q, versor dest) { - /* - + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i - + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j - + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k - a1 a2 − b1 b2 − c1 c2 − d1 d2 - */ - - glmm_128 xp, xq, xqr, r, x, y, z, s2, s3; - glmm_128 s1 = glmm_float32x4_SIGNMASK_NPPN; - - float32x2_t qh, ql; - - xp = glmm_load(p); /* 3 2 1 0 */ - xq = glmm_load(q); - - r = vmulq_f32(glmm_splat_w(xp), xq); - x = glmm_splat_x(xp); - y = glmm_splat_y(xp); - z = glmm_splat_z(xp); - - ql = vget_high_f32(s1); - s3 = vcombine_f32(ql, ql); - s2 = vzipq_f32(s3, s3).val[0]; - - xqr = vrev64q_f32(xq); - qh = vget_high_f32(xqr); - ql = vget_low_f32(xqr); - - r = glmm_fmadd(glmm_xor(x, s3), vcombine_f32(qh, ql), r); - - r = glmm_fmadd(glmm_xor(y, s2), vcombine_f32(vget_high_f32(xq), - vget_low_f32(xq)), r); - - r = glmm_fmadd(glmm_xor(z, s1), vcombine_f32(ql, qh), r); - - glmm_store(dest, r); -} - -#endif -#endif /* cglm_quat_neon_h */ diff --git a/external/cglm/simd/sse2/affine.h b/external/cglm/simd/sse2/affine.h deleted file mode 100644 index 0619995..0000000 --- a/external/cglm/simd/sse2/affine.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_mat_sse2_h -#define cglm_affine_mat_sse2_h -#if defined( __SSE__ ) || defined( __SSE2__ ) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = _mm_mul_ps(glmm_splat_x(r0), l); - v1 = _mm_mul_ps(glmm_splat_x(r1), l); - v2 = _mm_mul_ps(glmm_splat_x(r2), l); - v3 = _mm_mul_ps(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - l = glmm_load(m1[3]); - v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mul_rot_sse2(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, v0, v1, v2; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - - v0 = _mm_mul_ps(glmm_splat_x(r0), l); - v1 = _mm_mul_ps(glmm_splat_x(r1), l); - v2 = _mm_mul_ps(glmm_splat_x(r2), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], glmm_load(m1[3])); -} - -CGLM_INLINE -void -glm_inv_tr_sse2(mat4 mat) { - __m128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; - - r0 = glmm_load(mat[0]); - r1 = glmm_load(mat[1]); - r2 = glmm_load(mat[2]); - r3 = glmm_load(mat[3]); - x1 = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f); - - _MM_TRANSPOSE4_PS(r0, r1, r2, x1); - - x2 = glmm_shuff1(r3, 0, 0, 0, 0); - x3 = glmm_shuff1(r3, 1, 1, 1, 1); - x4 = glmm_shuff1(r3, 2, 2, 2, 2); - x5 = glmm_float32x4_SIGNMASK_NEG; - - x0 = glmm_fmadd(r0, x2, glmm_fmadd(r1, x3, _mm_mul_ps(r2, x4))); - x0 = _mm_xor_ps(x0, x5); - - x0 = _mm_add_ps(x0, x1); - - glmm_store(mat[0], r0); - glmm_store(mat[1], r1); - glmm_store(mat[2], r2); - glmm_store(mat[3], x0); -} - -#endif -#endif /* cglm_affine_mat_sse2_h */ diff --git a/external/cglm/simd/sse2/mat2.h b/external/cglm/simd/sse2/mat2.h deleted file mode 100644 index 31b3a29..0000000 --- a/external/cglm/simd/sse2/mat2.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat2_sse_h -#define cglm_mat2_sse_h -#if defined( __SSE__ ) || defined( __SSE2__ ) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat2_mul_sse2(mat2 m1, mat2 m2, mat2 dest) { - __m128 x0, x1, x2, x3, x4; - - x1 = glmm_load(m1[0]); /* d c b a */ - x2 = glmm_load(m2[0]); /* h g f e */ - - x3 = glmm_shuff1(x2, 2, 2, 0, 0); - x4 = glmm_shuff1(x2, 3, 3, 1, 1); - x0 = _mm_movelh_ps(x1, x1); - x2 = _mm_movehl_ps(x1, x1); - - /* - dest[0][0] = a * e + c * f; - dest[0][1] = b * e + d * f; - dest[1][0] = a * g + c * h; - dest[1][1] = b * g + d * h; - */ - x0 = glmm_fmadd(x0, x3, _mm_mul_ps(x2, x4)); - - glmm_store(dest[0], x0); -} - -CGLM_INLINE -void -glm_mat2_transp_sse2(mat2 m, mat2 dest) { - /* d c b a */ - /* d b c a */ - glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); -} - -#endif -#endif /* cglm_mat2_sse_h */ diff --git a/external/cglm/simd/sse2/mat3.h b/external/cglm/simd/sse2/mat3.h deleted file mode 100644 index f07320c..0000000 --- a/external/cglm/simd/sse2/mat3.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat3_sse_h -#define cglm_mat3_sse_h -#if defined( __SSE__ ) || defined( __SSE2__ ) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat3_mul_sse2(mat3 m1, mat3 m2, mat3 dest) { - __m128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - l0 = _mm_loadu_ps(m1[0]); - l1 = _mm_loadu_ps(&m1[1][1]); - - r0 = _mm_loadu_ps(m2[0]); - r1 = _mm_loadu_ps(&m2[1][1]); - - x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ - x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ - x2 = _mm_shuffle_ps(l0, l1, _MM_SHUFFLE(1, 0, 3, 3)); /* a12 a11 a10 a10 */ - x3 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(2, 0, 3, 1)); /* b20 b11 b10 b01 */ - x0 = _mm_mul_ps(x8, x1); - - x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ - x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ - l2 = _mm_load_ss(&m1[2][2]); - r2 = _mm_load_ss(&m2[2][2]); - x1 = _mm_mul_ps(x6, x7); - l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ - r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ - - x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ - x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ - x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ - x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ - - x8 = _mm_unpackhi_ps(x8, x4); /* a10 a00 a12 a02 */ - x9 = _mm_unpackhi_ps(x7, x2); /* b21 b20 b21 b20 */ - - x0 = glmm_fmadd(x4, x6, x0); - x1 = glmm_fmadd(x5, x2, x1); - - x2 = _mm_movehl_ps(l2, l1); /* a22 a22 a21 a20 */ - x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ - x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ - x4 = _mm_shuffle_ps(r0, r1, _MM_SHUFFLE(1, 1, 2, 2)); /* b12 b12 b02 b02 */ - - x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ - x4 = _mm_movehl_ps(r2, x4); /* b22 b22 b12 b12 */ - x0 = glmm_fmadd(x3, x5, x0); - x1 = glmm_fmadd(x2, x4, x1); - - /* - Dot Product : dest[2][2] = a02 * b20 + - a12 * b21 + - a22 * b22 + - 0 * 00 */ - x2 = _mm_movelh_ps(x8, l2); /* 0.f a22 a12 a02 */ - x3 = _mm_movelh_ps(x9, r2); /* 0.f b22 b21 b20 */ - x2 = glmm_vdots(x2, x3); - - _mm_storeu_ps(&dest[0][0], x0); - _mm_storeu_ps(&dest[1][1], x1); - _mm_store_ss (&dest[2][2], x2); -} - -#endif -#endif /* cglm_mat3_sse_h */ diff --git a/external/cglm/simd/sse2/mat4.h b/external/cglm/simd/sse2/mat4.h deleted file mode 100644 index 2127e72..0000000 --- a/external/cglm/simd/sse2/mat4.h +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat_sse_h -#define cglm_mat_sse_h -#if defined( __SSE__ ) || defined( __SSE2__ ) - -#include "../../common.h" -#include "../intrin.h" - -#define glm_mat4_inv_precise_sse2(mat, dest) glm_mat4_inv_sse2(mat, dest) - -CGLM_INLINE -void -glm_mat4_scale_sse2(mat4 m, float s) { - __m128 x0; - x0 = glmm_set1(s); - - glmm_store(m[0], _mm_mul_ps(glmm_load(m[0]), x0)); - glmm_store(m[1], _mm_mul_ps(glmm_load(m[1]), x0)); - glmm_store(m[2], _mm_mul_ps(glmm_load(m[2]), x0)); - glmm_store(m[3], _mm_mul_ps(glmm_load(m[3]), x0)); -} - -CGLM_INLINE -void -glm_mat4_transp_sse2(mat4 m, mat4 dest) { - __m128 r0, r1, r2, r3; - - r0 = glmm_load(m[0]); - r1 = glmm_load(m[1]); - r2 = glmm_load(m[2]); - r3 = glmm_load(m[3]); - - _MM_TRANSPOSE4_PS(r0, r1, r2, r3); - - glmm_store(dest[0], r0); - glmm_store(dest[1], r1); - glmm_store(dest[2], r2); - glmm_store(dest[3], r3); -} - -CGLM_INLINE -void -glm_mat4_mul_sse2(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = _mm_mul_ps(glmm_splat_x(r0), l); - v1 = _mm_mul_ps(glmm_splat_x(r1), l); - v2 = _mm_mul_ps(glmm_splat_x(r2), l); - v3 = _mm_mul_ps(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - l = glmm_load(m1[3]); - v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mat4_mulv_sse2(mat4 m, vec4 v, vec4 dest) { - __m128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; - - m0 = glmm_load(m[0]); - m1 = glmm_load(m[1]); - m2 = glmm_load(m[2]); - m3 = glmm_load(m[3]); - - x0 = glmm_load(v); - v0 = glmm_splat_x(x0); - v1 = glmm_splat_y(x0); - v2 = glmm_splat_z(x0); - v3 = glmm_splat_w(x0); - - x1 = _mm_mul_ps(m3, v3); - x1 = glmm_fmadd(m2, v2, x1); - x1 = glmm_fmadd(m1, v1, x1); - x1 = glmm_fmadd(m0, v0, x1); - - glmm_store(dest, x1); -} - -CGLM_INLINE -float -glm_mat4_det_sse2(mat4 mat) { - __m128 r0, r1, r2, r3, x0, x1, x2; - - /* 127 <- 0, [square] det(A) = det(At) */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - /* - t[1] = j * p - n * l; - t[2] = j * o - n * k; - t[3] = i * p - m * l; - t[4] = i * o - m * k; - */ - x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), - _mm_mul_ps(glmm_shuff1(r2, 0, 0, 1, 1), - glmm_shuff1(r3, 2, 3, 2, 3))); - /* - t[0] = k * p - o * l; - t[0] = k * p - o * l; - t[5] = i * n - m * j; - t[5] = i * n - m * j; - */ - x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), - _mm_mul_ps(glmm_shuff1(r2, 0, 0, 2, 2), - glmm_shuff1(r3, 1, 1, 3, 3))); - - /* - a * (f * t[0] - g * t[1] + h * t[2]) - - b * (e * t[0] - g * t[3] + h * t[4]) - + c * (e * t[1] - f * t[3] + h * t[5]) - - d * (e * t[2] - f * t[4] + g * t[5]) - */ - x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), - _mm_mul_ps(glmm_shuff1(r1, 0, 0, 0, 1), - _mm_shuffle_ps(x1, x0, _MM_SHUFFLE(1, 0, 0, 0)))); - x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), - _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 2, 3, 1)), - x2); - - x2 = _mm_xor_ps(x2, glmm_float32x4_SIGNMASK_NPNP); - - return glmm_hadd(_mm_mul_ps(x2, r0)); -} - -CGLM_INLINE -void -glm_mat4_inv_fast_sse2(mat4 mat, mat4 dest) { - __m128 r0, r1, r2, r3, - v0, v1, v2, v3, - t0, t1, t2, t3, t4, t5, - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ - x8 = glmm_float32x4_SIGNMASK_NPNP; - x9 = glmm_shuff1(x8, 2, 1, 2, 1); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - x0 = _mm_movehl_ps(r3, r2); /* p o l k */ - x3 = _mm_movelh_ps(r2, r3); /* n m j i */ - x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ - x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ - x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ - x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ - - x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ - x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ - x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ - x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ - - t0 = _mm_mul_ps(x3, x1); - t1 = _mm_mul_ps(x5, x1); - t2 = _mm_mul_ps(x5, x2); - t3 = _mm_mul_ps(x6, x1); - t4 = _mm_mul_ps(x6, x2); - t5 = _mm_mul_ps(x6, x4); - - /* t1[0] = k * p - o * l; - t1[0] = k * p - o * l; - t2[0] = g * p - o * h; - t3[0] = g * l - k * h; */ - t0 = glmm_fnmadd(x2, x0, t0); - - /* t1[1] = j * p - n * l; - t1[1] = j * p - n * l; - t2[1] = f * p - n * h; - t3[1] = f * l - j * h; */ - t1 = glmm_fnmadd(x4, x0, t1); - - /* t1[2] = j * o - n * k - t1[2] = j * o - n * k; - t2[2] = f * o - n * g; - t3[2] = f * k - j * g; */ - t2 = glmm_fnmadd(x4, x3, t2); - - /* t1[3] = i * p - m * l; - t1[3] = i * p - m * l; - t2[3] = e * p - m * h; - t3[3] = e * l - i * h; */ - t3 = glmm_fnmadd(x7, x0, t3); - - /* t1[4] = i * o - m * k; - t1[4] = i * o - m * k; - t2[4] = e * o - m * g; - t3[4] = e * k - i * g; */ - t4 = glmm_fnmadd(x7, x3, t4); - - /* t1[5] = i * n - m * j; - t1[5] = i * n - m * j; - t2[5] = e * n - m * f; - t3[5] = e * j - i * f; */ - t5 = glmm_fnmadd(x7, x5, t5); - - x4 = _mm_movelh_ps(r0, r1); /* f e b a */ - x5 = _mm_movehl_ps(r1, r0); /* h g d c */ - - x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ - x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ - x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ - x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ - - v2 = _mm_mul_ps(x0, t1); - v1 = _mm_mul_ps(x0, t0); - v3 = _mm_mul_ps(x0, t2); - v0 = _mm_mul_ps(x1, t0); - - v2 = glmm_fnmadd(x1, t3, v2); - v3 = glmm_fnmadd(x1, t4, v3); - v0 = glmm_fnmadd(x2, t1, v0); - v1 = glmm_fnmadd(x2, t3, v1); - - v3 = glmm_fmadd(x2, t5, v3); - v0 = glmm_fmadd(x3, t2, v0); - v2 = glmm_fmadd(x3, t5, v2); - v1 = glmm_fmadd(x3, t4, v1); - - /* - dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; - dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); - dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; - dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ - v0 = _mm_xor_ps(v0, x8); - - /* - dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; - dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); - dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; - dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ - v2 = _mm_xor_ps(v2, x8); - - /* - dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); - dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; - dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); - dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ - v1 = _mm_xor_ps(v1, x9); - - /* - dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); - dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; - dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); - dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ - v3 = _mm_xor_ps(v3, x9); - - /* determinant */ - x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); - x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); - x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); - - x0 = _mm_rcp_ps(glmm_vhadd(_mm_mul_ps(x0, r0))); - - glmm_store(dest[0], _mm_mul_ps(v0, x0)); - glmm_store(dest[1], _mm_mul_ps(v1, x0)); - glmm_store(dest[2], _mm_mul_ps(v2, x0)); - glmm_store(dest[3], _mm_mul_ps(v3, x0)); -} - -/* old one */ -#if 0 -CGLM_INLINE -void -glm_mat4_inv_sse2(mat4 mat, mat4 dest) { - __m128 r0, r1, r2, r3, - v0, v1, v2, v3, - t0, t1, t2, t3, t4, t5, - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - /* x8 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ - x8 = glmm_float32x4_SIGNMASK_NPNP; - x9 = glmm_shuff1(x8, 2, 1, 2, 1); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - x0 = _mm_movehl_ps(r3, r2); /* p o l k */ - x3 = _mm_movelh_ps(r2, r3); /* n m j i */ - x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ - x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ - x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ - x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ - - x6 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(0, 0, 0, 0)); /* e e i i */ - x5 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(1, 1, 1, 1)); /* f f j j */ - x3 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(2, 2, 2, 2)); /* g g k k */ - x0 = _mm_shuffle_ps(r2, r1, _MM_SHUFFLE(3, 3, 3, 3)); /* h h l l */ - - t0 = _mm_mul_ps(x3, x1); - t1 = _mm_mul_ps(x5, x1); - t2 = _mm_mul_ps(x5, x2); - t3 = _mm_mul_ps(x6, x1); - t4 = _mm_mul_ps(x6, x2); - t5 = _mm_mul_ps(x6, x4); - - /* t1[0] = k * p - o * l; - t1[0] = k * p - o * l; - t2[0] = g * p - o * h; - t3[0] = g * l - k * h; */ - t0 = glmm_fnmadd(x2, x0, t0); - - /* t1[1] = j * p - n * l; - t1[1] = j * p - n * l; - t2[1] = f * p - n * h; - t3[1] = f * l - j * h; */ - t1 = glmm_fnmadd(x4, x0, t1); - - /* t1[2] = j * o - n * k - t1[2] = j * o - n * k; - t2[2] = f * o - n * g; - t3[2] = f * k - j * g; */ - t2 = glmm_fnmadd(x4, x3, t2); - - /* t1[3] = i * p - m * l; - t1[3] = i * p - m * l; - t2[3] = e * p - m * h; - t3[3] = e * l - i * h; */ - t3 = glmm_fnmadd(x7, x0, t3); - - /* t1[4] = i * o - m * k; - t1[4] = i * o - m * k; - t2[4] = e * o - m * g; - t3[4] = e * k - i * g; */ - t4 = glmm_fnmadd(x7, x3, t4); - - /* t1[5] = i * n - m * j; - t1[5] = i * n - m * j; - t2[5] = e * n - m * f; - t3[5] = e * j - i * f; */ - t5 = glmm_fnmadd(x7, x5, t5); - - x4 = _mm_movelh_ps(r0, r1); /* f e b a */ - x5 = _mm_movehl_ps(r1, r0); /* h g d c */ - - x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ - x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ - x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ - x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ - - v2 = _mm_mul_ps(x0, t1); - v1 = _mm_mul_ps(x0, t0); - v3 = _mm_mul_ps(x0, t2); - v0 = _mm_mul_ps(x1, t0); - - v2 = glmm_fnmadd(x1, t3, v2); - v3 = glmm_fnmadd(x1, t4, v3); - v0 = glmm_fnmadd(x2, t1, v0); - v1 = glmm_fnmadd(x2, t3, v1); - - v3 = glmm_fmadd(x2, t5, v3); - v0 = glmm_fmadd(x3, t2, v0); - v2 = glmm_fmadd(x3, t5, v2); - v1 = glmm_fmadd(x3, t4, v1); - - /* - dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; - dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); - dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; - dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ - v0 = _mm_xor_ps(v0, x8); - - /* - dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; - dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); - dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; - dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ - v2 = _mm_xor_ps(v2, x8); - - /* - dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); - dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; - dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); - dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ - v1 = _mm_xor_ps(v1, x9); - - /* - dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); - dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; - dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); - dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ - v3 = _mm_xor_ps(v3, x9); - - /* determinant */ - x0 = _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(0, 0, 0, 0)); - x1 = _mm_shuffle_ps(v2, v3, _MM_SHUFFLE(0, 0, 0, 0)); - x0 = _mm_shuffle_ps(x0, x1, _MM_SHUFFLE(2, 0, 2, 0)); - - x0 = _mm_div_ps(glmm_set1(1.0f), glmm_vhadd(_mm_mul_ps(x0, r0))); - - glmm_store(dest[0], _mm_mul_ps(v0, x0)); - glmm_store(dest[1], _mm_mul_ps(v1, x0)); - glmm_store(dest[2], _mm_mul_ps(v2, x0)); - glmm_store(dest[3], _mm_mul_ps(v3, x0)); -} -#endif - -CGLM_INLINE -void -glm_mat4_inv_sse2(mat4 mat, mat4 dest) { - __m128 r0, r1, r2, r3, s1, s2, - v0, v1, v2, v3, v4, v5, - t0, t1, t2, - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13; - - /* s1 = _mm_set_ps(-0.f, 0.f, -0.f, 0.f); */ - s1 = glmm_float32x4_SIGNMASK_NPNP; - s2 = glmm_shuff1(s1, 2, 1, 2, 1); - - /* 127 <- 0 */ - r1 = glmm_load(mat[1]); /* h g f e */ - r0 = glmm_load(mat[0]); /* d c b a */ - r3 = glmm_load(mat[3]); /* p o n m */ - r2 = glmm_load(mat[2]); /* l k j i */ - - x4 = _mm_unpackhi_ps(r0, r2); /* l d k c */ - x5 = _mm_unpacklo_ps(r0, r2); /* j b i a */ - x6 = _mm_unpackhi_ps(r1, r3); /* p h o g */ - x7 = _mm_unpacklo_ps(r1, r3); /* n f m e */ - - x0 = _mm_unpackhi_ps(x7, x5); /* j n b f */ - x1 = _mm_unpacklo_ps(x7, x5); /* i m a e */ - x2 = _mm_unpackhi_ps(x6, x4); /* l p d h */ - x3 = _mm_unpacklo_ps(x6, x4); /* k o c g */ - - /* c2 = c * h - d * g c12 = a * g - c * e c8 = a * f - b * e - c1 = k * p - l * o c11 = i * o - k * m c7 = i * n - j * m - c4 = a * h - d * e c6 = b * h - d * f c10 = b * g - c * f - c3 = i * p - l * m c5 = j * p - l * n c9 = j * o - k * n */ - - x8 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(3, 1, 3, 1)); /* k c j b */ - x9 = _mm_shuffle_ps(x0, x3, _MM_SHUFFLE(2, 0, 2, 0)); /* o g n f */ - - x10 = glmm_shuff1(x2, 2, 0, 2, 0); /* p h p h */ - x11 = glmm_shuff1(x2, 3, 1, 3, 1); /* l d l d */ - -#if 0 /* TODO measure both */ - x12 = _mm_shuffle_ps(x4, x5, _MM_SHUFFLE(1, 0, 1, 0)); /* i a k c */ - x13 = _mm_shuffle_ps(x6, x7, _MM_SHUFFLE(1, 0, 1, 0)); /* m e o g */ -#else - x12 = _mm_movelh_ps(x4, x5); /* i a k c */ - x13 = _mm_movelh_ps(x6, x7); /* m e o g */ -#endif - - t0 = _mm_mul_ps(x12, x10); - t1 = _mm_mul_ps(x5, x6); - t2 = _mm_mul_ps(x5, x9); - - t0 = glmm_fnmadd(x11, x13, t0); - t1 = glmm_fnmadd(x4, x7, t1); - t2 = glmm_fnmadd(x8, x7, t2); - - /* det */ - /* v0: c3 * c10 + c4 * c9 + c1 * c8 + c2 * c7 */ - /* v1: c5 * c12 + c6 * c11 */ - - v5 = glmm_set1_rval(1.0f); - v0 = glmm_shuff1(t2, 2, 3, 0, 1); - v1 = glmm_shuff1(t1, 0, 1, 2, 3); - v0 = _mm_mul_ps(t0, v0); - v1 = _mm_mul_ps(t1, v1); - v2 = glmm_shuff1(v1, 1, 0, 0, 1); - v3 = glmm_shuff1(v0, 0, 1, 2, 3); - v1 = _mm_add_ps(v1, v2); - v0 = _mm_add_ps(v0, v3); - v2 = glmm_shuff1(v0, 1, 0, 0, 1); - v0 = _mm_add_ps(v0, v2); - - v0 = _mm_sub_ps(v0, v1); /* det */ - v0 = _mm_div_ps(v5, v0); /* idt */ - - /* multiply t0,t1,t2 by idt to reduce 1mul below: 2eor+4mul vs 3mul+4eor */ - t0 = _mm_mul_ps(t0, v0); - t1 = _mm_mul_ps(t1, v0); - t2 = _mm_mul_ps(t2, v0); - - v0 = glmm_shuff1(t0, 0, 0, 1, 1); /* c2 c2 c1 c1 */ - v1 = glmm_shuff1(t0, 2, 2, 3, 3); /* c4 c4 c3 c3 */ - v2 = glmm_shuff1(t1, 0, 0, 1, 1); /* c12 c12 c11 c11 */ - v3 = glmm_shuff1(t1, 2, 2, 3, 3); /* c6 c6 c5 c5 */ - v4 = glmm_shuff1(t2, 0, 0, 1, 1); /* c8 c8 c7 c7 */ - v5 = glmm_shuff1(t2, 2, 2, 3, 3); /* c10 c10 c9 c9 */ - - /* result */ - - /* dest[0][0] = (f * c1 - g * c5 + h * c9) * idt; - dest[0][1] = (b * c1 - c * c5 + d * c9) * ndt; - dest[0][2] = (n * c2 - o * c6 + p * c10) * idt; - dest[0][3] = (j * c2 - k * c6 + l * c10) * ndt; - - dest[1][0] = (e * c1 - g * c3 + h * c11) * ndt; - dest[1][1] = (a * c1 - c * c3 + d * c11) * idt; - dest[1][2] = (m * c2 - o * c4 + p * c12) * ndt; - dest[1][3] = (i * c2 - k * c4 + l * c12) * idt; - - dest[2][0] = (e * c5 - f * c3 + h * c7) * idt; - dest[2][1] = (a * c5 - b * c3 + d * c7) * ndt; - dest[2][2] = (m * c6 - n * c4 + p * c8) * idt; - dest[2][3] = (i * c6 - j * c4 + l * c8) * ndt; - - dest[3][0] = (e * c9 - f * c11 + g * c7) * ndt; - dest[3][1] = (a * c9 - b * c11 + c * c7) * idt; - dest[3][2] = (m * c10 - n * c12 + o * c8) * ndt; - dest[3][3] = (i * c10 - j * c12 + k * c8) * idt; */ - - r0 = _mm_mul_ps(x0, v0); - r1 = _mm_mul_ps(x1, v0); - r2 = _mm_mul_ps(x1, v3); - r3 = _mm_mul_ps(x1, v5); - - r0 = glmm_fnmadd(x3, v3, r0); - r1 = glmm_fnmadd(x3, v1, r1); - r2 = glmm_fnmadd(x0, v1, r2); - r3 = glmm_fnmadd(x0, v2, r3); - - r0 = glmm_fmadd(x2, v5, r0); - r1 = glmm_fmadd(x2, v2, r1); - r2 = glmm_fmadd(x2, v4, r2); - r3 = glmm_fmadd(x3, v4, r3); - - /* 4xor may be fastart then 4mul, see above */ - r0 = _mm_xor_ps(r0, s1); - r1 = _mm_xor_ps(r1, s2); - r2 = _mm_xor_ps(r2, s1); - r3 = _mm_xor_ps(r3, s2); - - glmm_store(dest[0], r0); - glmm_store(dest[1], r1); - glmm_store(dest[2], r2); - glmm_store(dest[3], r3); -} -#endif -#endif /* cglm_mat_sse_h */ diff --git a/external/cglm/simd/sse2/quat.h b/external/cglm/simd/sse2/quat.h deleted file mode 100644 index def0fe2..0000000 --- a/external/cglm/simd/sse2/quat.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_quat_simd_h -#define cglm_quat_simd_h -#if defined( __SSE__ ) || defined( __SSE2__ ) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_quat_mul_sse2(versor p, versor q, versor dest) { - /* - + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i - + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j - + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k - a1 a2 − b1 b2 − c1 c2 − d1 d2 - */ - - __m128 xp, xq, x1, x2, x3, r, x, y, z; - - xp = glmm_load(p); /* 3 2 1 0 */ - xq = glmm_load(q); - x1 = glmm_float32x4_SIGNMASK_NPNP; /* TODO: _mm_set1_ss() + shuff ? */ - r = _mm_mul_ps(glmm_splat_w(xp), xq); - - x2 = _mm_unpackhi_ps(x1, x1); - x3 = glmm_shuff1(x1, 3, 2, 0, 1); - x = glmm_splat_x(xp); - y = glmm_splat_y(xp); - z = glmm_splat_z(xp); - - x = _mm_xor_ps(x, x1); - y = _mm_xor_ps(y, x2); - z = _mm_xor_ps(z, x3); - - x1 = glmm_shuff1(xq, 0, 1, 2, 3); - x2 = glmm_shuff1(xq, 1, 0, 3, 2); - x3 = glmm_shuff1(xq, 2, 3, 0, 1); - - r = glmm_fmadd(x, x1, r); - r = glmm_fmadd(y, x2, r); - r = glmm_fmadd(z, x3, r); - - glmm_store(dest, r); -} - -#endif -#endif /* cglm_quat_simd_h */ diff --git a/external/cglm/simd/wasm.h b/external/cglm/simd/wasm.h deleted file mode 100644 index 2ced51f..0000000 --- a/external/cglm/simd/wasm.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_simd_wasm_h -#define cglm_simd_wasm_h -#include "intrin.h" -#ifdef CGLM_SIMD_WASM -#include - -#define glmm_load(p) wasm_v128_load(p) -#define glmm_store(p, a) wasm_v128_store(p, (a)) - -#define glmm_set1(x) wasm_f32x4_splat(x) -#define glmm_set1_ptr(x) wasm_f32x4_splat(*x) -#define glmm_set1_rval(x) wasm_f32x4_splat(x) -#define glmm_128 v128_t - -#define glmm_shuff1(xmm, z, y, x, w) wasm_i32x4_shuffle(xmm, xmm, w, x, y, z) - -#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) - -#define glmm_splat_x(x) glmm_splat(x, 0) -#define glmm_splat_y(x) glmm_splat(x, 1) -#define glmm_splat_z(x) glmm_splat(x, 2) -#define glmm_splat_w(x) glmm_splat(x, 3) - -#define GLMM_NEGZEROf 0x80000000 /* 0x80000000 ---> -0.0f */ - -/* _mm_set_ps(X, Y, Z, W); */ -#define GLMM__SIGNMASKf(X, Y, Z, W) wasm_i32x4_const(X, Y, Z, W) - -#define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(0, GLMM_NEGZEROf, 0, GLMM_NEGZEROf) -#define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, GLMM_NEGZEROf, 0) -#define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, 0, 0, GLMM_NEGZEROf) -#define glmm_float32x4_SIGNMASK_NEG wasm_i32x4_const_splat(GLMM_NEGZEROf) - -static inline glmm_128 glmm_abs(glmm_128 x) { return wasm_f32x4_abs(x); } -static inline glmm_128 glmm_min(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmin(b, a); } -static inline glmm_128 glmm_max(glmm_128 a, glmm_128 b) { return wasm_f32x4_pmax(b, a); } - -static inline -glmm_128 -glmm_vhadd(glmm_128 v) { - glmm_128 x0; - x0 = wasm_f32x4_add(v, glmm_shuff1(v, 0, 1, 2, 3)); - x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 0, 1)); - return x0; -} - -static inline -glmm_128 -glmm_vhadds(glmm_128 v) { - glmm_128 shuf, sums; - shuf = glmm_shuff1(v, 2, 3, 0, 1); - sums = wasm_f32x4_add(v, shuf); - /* shuf = _mm_movehl_ps(shuf, sums); */ - shuf = wasm_i32x4_shuffle(shuf, sums, 6, 7, 2, 3); - sums = wasm_i32x4_shuffle(sums, wasm_f32x4_add(sums, shuf), 4, 1, 2, 3); - return sums; -} - -static inline -float -glmm_hadd(glmm_128 v) { - return wasm_f32x4_extract_lane(glmm_vhadds(v), 0); -} - -static inline -glmm_128 -glmm_vhmin(glmm_128 v) { - glmm_128 x0, x1, x2; - x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ - x1 = wasm_f32x4_pmin(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ - x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ - return wasm_f32x4_pmin(x1, x2); -} - -static inline -float -glmm_hmin(glmm_128 v) { - return wasm_f32x4_extract_lane(glmm_vhmin(v), 0); -} - -static inline -glmm_128 -glmm_vhmax(glmm_128 v) { - glmm_128 x0, x1, x2; - x0 = glmm_shuff1(v, 2, 3, 2, 3); /* [2, 3, 2, 3] */ - x1 = wasm_f32x4_pmax(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ - x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ - /* _mm_max_ss */ - return wasm_i32x4_shuffle(x1, wasm_f32x4_pmax(x1, x2), 4, 1, 2, 3); -} - -static inline -float -glmm_hmax(glmm_128 v) { - return wasm_f32x4_extract_lane(glmm_vhmax(v), 0); -} - -static inline -glmm_128 -glmm_vdots(glmm_128 a, glmm_128 b) { - return glmm_vhadds(wasm_f32x4_mul(a, b)); -} - -static inline -glmm_128 -glmm_vdot(glmm_128 a, glmm_128 b) { - glmm_128 x0; - x0 = wasm_f32x4_mul(a, b); - x0 = wasm_f32x4_add(x0, glmm_shuff1(x0, 1, 0, 3, 2)); - return wasm_f32x4_add(x0, glmm_shuff1(x0, 0, 1, 0, 1)); -} - -static inline -float -glmm_dot(glmm_128 a, glmm_128 b) { - return wasm_f32x4_extract_lane(glmm_vdots(a, b), 0); -} - -static inline -float -glmm_norm(glmm_128 a) { - glmm_128 x0; - x0 = glmm_vhadds(wasm_f32x4_mul(a, a)); - return wasm_f32x4_extract_lane( - wasm_i32x4_shuffle(x0, wasm_f32x4_sqrt(x0),4, 1, 2, 3), 0); -} - -static inline -float -glmm_norm2(glmm_128 a) { - return wasm_f32x4_extract_lane(glmm_vhadds(wasm_f32x4_mul(a, a)), 0); -} - -static inline -float -glmm_norm_one(glmm_128 a) { - return wasm_f32x4_extract_lane(glmm_vhadds(glmm_abs(a)), 0); -} - -static inline -float -glmm_norm_inf(glmm_128 a) { - return wasm_f32x4_extract_lane(glmm_vhmax(glmm_abs(a)), 0); -} - -static inline -glmm_128 -glmm_load3(float v[3]) { - glmm_128 xy = wasm_v128_load64_zero(v); - return wasm_f32x4_replace_lane(xy, 2, v[2]); -} - -static inline -void -glmm_store3(float v[3], glmm_128 vx) { - wasm_v128_store64_lane(v, vx, 0); - wasm_v128_store32_lane(&v[2], vx, 2); -} - -static inline -glmm_128 -glmm_div(glmm_128 a, glmm_128 b) { - return wasm_f32x4_div(a, b); -} - -static inline -glmm_128 -glmm_fmadd(glmm_128 a, glmm_128 b, glmm_128 c) { - return wasm_f32x4_add(c, wasm_f32x4_mul(a, b)); -} - -static inline -glmm_128 -glmm_fnmadd(glmm_128 a, glmm_128 b, glmm_128 c) { - return wasm_f32x4_sub(c, wasm_f32x4_mul(a, b)); -} - -static inline -glmm_128 -glmm_fmsub(glmm_128 a, glmm_128 b, glmm_128 c) { - return wasm_f32x4_sub(wasm_f32x4_mul(a, b), c); -} - -static inline -glmm_128 -glmm_fnmsub(glmm_128 a, glmm_128 b, glmm_128 c) { - return wasm_f32x4_neg(wasm_f32x4_add(wasm_f32x4_mul(a, b), c)); -} - -#endif -#endif /* cglm_simd_wasm_h */ diff --git a/external/cglm/simd/wasm/affine.h b/external/cglm/simd/wasm/affine.h deleted file mode 100644 index 80b98fb..0000000 --- a/external/cglm/simd/wasm/affine.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_affine_mat_wasm_h -#define cglm_affine_mat_wasm_h -#if defined(__wasm__) && defined(__wasm_simd128__) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); - v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); - v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); - v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - l = glmm_load(m1[3]); - v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mul_rot_wasm(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, v0, v1, v2; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - - v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); - v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); - v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], glmm_load(m1[3])); -} - -CGLM_INLINE -void -glm_inv_tr_wasm(mat4 mat) { - glmm_128 r0, r1, r2, r3, x0, x1, x2, x3, x4, x5; - - r0 = glmm_load(mat[0]); - r1 = glmm_load(mat[1]); - r2 = glmm_load(mat[2]); - r3 = glmm_load(mat[3]); - x1 = wasm_f32x4_const(0.0f, 0.0f, 0.0f, 1.0f); - - /* _MM_TRANSPOSE4_PS(r0, r1, r2, x1); */ - x2 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); - x3 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); - x4 = wasm_i32x4_shuffle(r2, x1, 0, 4, 1, 5); - x5 = wasm_i32x4_shuffle(r2, x1, 2, 6, 3, 7); - /* r0 = _mm_movelh_ps(x2, x4); */ - r0 = wasm_i32x4_shuffle(x2, x4, 0, 1, 4, 5); - /* r1 = _mm_movehl_ps(x4, x2); */ - r1 = wasm_i32x4_shuffle(x4, x2, 6, 7, 2, 3); - /* r2 = _mm_movelh_ps(x3, x5); */ - r2 = wasm_i32x4_shuffle(x3, x5, 0, 1, 4, 5); - /* x1 = _mm_movehl_ps(x5, x3); */ - x1 = wasm_i32x4_shuffle(x5, x3, 6, 7, 2, 3); - - x2 = glmm_shuff1(r3, 0, 0, 0, 0); - x3 = glmm_shuff1(r3, 1, 1, 1, 1); - x4 = glmm_shuff1(r3, 2, 2, 2, 2); - - x0 = glmm_fmadd(r0, x2, - glmm_fmadd(r1, x3, wasm_f32x4_mul(r2, x4))); - x0 = wasm_f32x4_neg(x0); - - x0 = wasm_f32x4_add(x0, x1); - - glmm_store(mat[0], r0); - glmm_store(mat[1], r1); - glmm_store(mat[2], r2); - glmm_store(mat[3], x0); -} - -#endif -#endif /* cglm_affine_mat_wasm_h */ diff --git a/external/cglm/simd/wasm/mat2.h b/external/cglm/simd/wasm/mat2.h deleted file mode 100644 index 80ce0fb..0000000 --- a/external/cglm/simd/wasm/mat2.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat2_wasm_h -#define cglm_mat2_wasm_h -#if defined(__wasm__) && defined(__wasm_simd128__) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat2_mul_wasm(mat2 m1, mat2 m2, mat2 dest) { - glmm_128 x0, x1, x2, x3, x4; - - x1 = glmm_load(m1[0]); /* d c b a */ - x2 = glmm_load(m2[0]); /* h g f e */ - - x3 = glmm_shuff1(x2, 2, 2, 0, 0); - x4 = glmm_shuff1(x2, 3, 3, 1, 1); - /* x0 = _mm_movelh_ps(x1, x1); */ - x0 = wasm_i32x4_shuffle(x1, x1, 0, 1, 4, 5); - /* x2 = _mm_movehl_ps(x1, x1); */ - x2 = wasm_i32x4_shuffle(x1, x1, 6, 7, 2, 3); - - /* - dest[0][0] = a * e + c * f; - dest[0][1] = b * e + d * f; - dest[1][0] = a * g + c * h; - dest[1][1] = b * g + d * h; - */ - x0 = glmm_fmadd(x0, x3, wasm_f32x4_mul(x2, x4)); - - glmm_store(dest[0], x0); -} - -CGLM_INLINE -void -glm_mat2_transp_wasm(mat2 m, mat2 dest) { - /* d c b a */ - /* d b c a */ - glmm_store(dest[0], glmm_shuff1(glmm_load(m[0]), 3, 1, 2, 0)); -} - -#endif -#endif /* cglm_mat2_wasm_h */ diff --git a/external/cglm/simd/wasm/mat3.h b/external/cglm/simd/wasm/mat3.h deleted file mode 100644 index dfe192d..0000000 --- a/external/cglm/simd/wasm/mat3.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat3_wasm_h -#define cglm_mat3_wasm_h -#if defined(__wasm__) && defined(__wasm_simd128__) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_mat3_mul_wasm(mat3 m1, mat3 m2, mat3 dest) { - glmm_128 l0, l1, l2, r0, r1, r2, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - l0 = wasm_v128_load(m1[0]); - l1 = wasm_v128_load(&m1[1][1]); - - r0 = wasm_v128_load(m2[0]); - r1 = wasm_v128_load(&m2[1][1]); - - x8 = glmm_shuff1(l0, 0, 2, 1, 0); /* a00 a02 a01 a00 */ - x1 = glmm_shuff1(r0, 3, 0, 0, 0); /* b10 b00 b00 b00 */ - x2 = wasm_i32x4_shuffle(l0, l1, 3, 3, 4, 5); /* a12 a11 a10 a10 */ - x3 = wasm_i32x4_shuffle(r0, r1, 1, 3, 4, 6); /* b20 b11 b10 b01 */ - x0 = wasm_f32x4_mul(x8, x1); - - x6 = glmm_shuff1(l0, 1, 0, 2, 1); /* a01 a00 a02 a01 */ - x7 = glmm_shuff1(x3, 3, 3, 1, 1); /* b20 b20 b10 b10 */ - l2 = wasm_v128_load32_zero(&m1[2][2]); - r2 = wasm_v128_load32_zero(&m2[2][2]); - x1 = wasm_f32x4_mul(x6, x7); - l2 = glmm_shuff1(l2, 0, 0, 1, 0); /* a22 a22 0.f a22 */ - r2 = glmm_shuff1(r2, 0, 0, 1, 0); /* b22 b22 0.f b22 */ - - x4 = glmm_shuff1(x2, 0, 3, 2, 0); /* a10 a12 a11 a10 */ - x5 = glmm_shuff1(x2, 2, 0, 3, 2); /* a11 a10 a12 a11 */ - x6 = glmm_shuff1(x3, 2, 0, 0, 0); /* b11 b01 b01 b01 */ - x2 = glmm_shuff1(r1, 3, 3, 0, 0); /* b21 b21 b11 b11 */ - - /* x8 = _mm_unpackhi_ps(x8, x4); */ - /* x9 = _mm_unpackhi_ps(x7, x2); */ - x8 = wasm_i32x4_shuffle(x8, x4, 2, 6, 3, 7); /* a10 a00 a12 a02 */ - x9 = wasm_i32x4_shuffle(x7, x2, 2, 6, 3, 7); /* b21 b20 b21 b20 */ - - x0 = glmm_fmadd(x4, x6, x0); - x1 = glmm_fmadd(x5, x2, x1); - - /* x2 = _mm_movehl_ps(l2, l1); */ - x2 = wasm_i32x4_shuffle(l2, l1, 6, 7, 2, 3); /* a22 a22 a21 a20 */ - x3 = glmm_shuff1(x2, 0, 2, 1, 0); /* a20 a22 a21 a20 */ - x2 = glmm_shuff1(x2, 1, 0, 2, 1); /* a21 a20 a22 a21 */ - x4 = wasm_i32x4_shuffle(r0, r1, 2, 2, 5, 5); /* b12 b12 b02 b02 */ - - x5 = glmm_shuff1(x4, 3, 0, 0, 0); /* b12 b02 b02 b02 */ - /* x4 = _mm_movehl_ps(r2, x4); */ - x4 = wasm_i32x4_shuffle(r2, x4, 6, 7, 2, 3); /* b22 b22 b12 b12 */ - x0 = glmm_fmadd(x3, x5, x0); - x1 = glmm_fmadd(x2, x4, x1); - - /* - Dot Product : dest[2][2] = a02 * b20 + - a12 * b21 + - a22 * b22 + - 0 * 00 */ - /* x2 = _mm_movelh_ps(x8, l2); */ - /* x3 = _mm_movelh_ps(x9, r2); */ - x2 = wasm_i32x4_shuffle(x8, l2, 0, 1, 4, 5); /* 0.f a22 a12 a02 */ - x3 = wasm_i32x4_shuffle(x9, r2, 0, 1, 4, 5); /* 0.f b22 b21 b20 */ - x2 = glmm_vdots(x2, x3); - - /* _mm_storeu_ps(&dest[0][0], x0); */ - wasm_v128_store(&dest[0][0], x0); - /* _mm_storeu_ps(&dest[1][1], x1); */ - wasm_v128_store(&dest[1][1], x1); - /* _mm_store_ss (&dest[2][2], x2); */ - wasm_v128_store32_lane(&dest[2][2], x2, 0); -} - -#endif -#endif /* cglm_mat3_wasm_h */ diff --git a/external/cglm/simd/wasm/mat4.h b/external/cglm/simd/wasm/mat4.h deleted file mode 100644 index 79ed688..0000000 --- a/external/cglm/simd/wasm/mat4.h +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_mat_wasm_h -#define cglm_mat_wasm_h -#if defined(__wasm__) && defined(__wasm_simd128__) - -#include "../../common.h" -#include "../intrin.h" - -#define glm_mat4_inv_precise_wasm(mat, dest) glm_mat4_inv_wasm(mat, dest) - -CGLM_INLINE -void -glm_mat4_scale_wasm(mat4 m, float s) { - glmm_128 x0; - x0 = wasm_f32x4_splat(s); - - glmm_store(m[0], wasm_f32x4_mul(glmm_load(m[0]), x0)); - glmm_store(m[1], wasm_f32x4_mul(glmm_load(m[1]), x0)); - glmm_store(m[2], wasm_f32x4_mul(glmm_load(m[2]), x0)); - glmm_store(m[3], wasm_f32x4_mul(glmm_load(m[3]), x0)); -} - -CGLM_INLINE -void -glm_mat4_transp_wasm(mat4 m, mat4 dest) { - glmm_128 r0, r1, r2, r3, tmp0, tmp1, tmp2, tmp3; - - r0 = glmm_load(m[0]); - r1 = glmm_load(m[1]); - r2 = glmm_load(m[2]); - r3 = glmm_load(m[3]); - - /* _MM_TRANSPOSE4_PS(r0, r1, r2, r3); */ - tmp0 = wasm_i32x4_shuffle(r0, r1, 0, 4, 1, 5); - tmp1 = wasm_i32x4_shuffle(r0, r1, 2, 6, 3, 7); - tmp2 = wasm_i32x4_shuffle(r2, r3, 0, 4, 1, 5); - tmp3 = wasm_i32x4_shuffle(r2, r3, 2, 6, 3, 7); - /* r0 = _mm_movelh_ps(tmp0, tmp2); */ - r0 = wasm_i32x4_shuffle(tmp0, tmp2, 0, 1, 4, 5); - /* r1 = _mm_movehl_ps(tmp2, tmp0); */ - r1 = wasm_i32x4_shuffle(tmp2, tmp0, 6, 7, 2, 3); - /* r2 = _mm_movelh_ps(tmp1, tmp3); */ - r2 = wasm_i32x4_shuffle(tmp1, tmp3, 0, 1, 4, 5); - /* r3 = _mm_movehl_ps(tmp3, tmp1); */ - r3 = wasm_i32x4_shuffle(tmp3, tmp1, 6, 7, 2, 3); - - glmm_store(dest[0], r0); - glmm_store(dest[1], r1); - glmm_store(dest[2], r2); - glmm_store(dest[3], r3); -} - -CGLM_INLINE -void -glm_mat4_mul_wasm(mat4 m1, mat4 m2, mat4 dest) { - /* D = R * L (Column-Major) */ - - glmm_128 l, r0, r1, r2, r3, v0, v1, v2, v3; - - l = glmm_load(m1[0]); - r0 = glmm_load(m2[0]); - r1 = glmm_load(m2[1]); - r2 = glmm_load(m2[2]); - r3 = glmm_load(m2[3]); - - v0 = wasm_f32x4_mul(glmm_splat_x(r0), l); - v1 = wasm_f32x4_mul(glmm_splat_x(r1), l); - v2 = wasm_f32x4_mul(glmm_splat_x(r2), l); - v3 = wasm_f32x4_mul(glmm_splat_x(r3), l); - - l = glmm_load(m1[1]); - v0 = glmm_fmadd(glmm_splat_y(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_y(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_y(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_y(r3), l, v3); - - l = glmm_load(m1[2]); - v0 = glmm_fmadd(glmm_splat_z(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_z(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_z(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_z(r3), l, v3); - - l = glmm_load(m1[3]); - v0 = glmm_fmadd(glmm_splat_w(r0), l, v0); - v1 = glmm_fmadd(glmm_splat_w(r1), l, v1); - v2 = glmm_fmadd(glmm_splat_w(r2), l, v2); - v3 = glmm_fmadd(glmm_splat_w(r3), l, v3); - - glmm_store(dest[0], v0); - glmm_store(dest[1], v1); - glmm_store(dest[2], v2); - glmm_store(dest[3], v3); -} - -CGLM_INLINE -void -glm_mat4_mulv_wasm(mat4 m, vec4 v, vec4 dest) { - glmm_128 x0, x1, m0, m1, m2, m3, v0, v1, v2, v3; - - m0 = glmm_load(m[0]); - m1 = glmm_load(m[1]); - m2 = glmm_load(m[2]); - m3 = glmm_load(m[3]); - - x0 = glmm_load(v); - v0 = glmm_splat_x(x0); - v1 = glmm_splat_y(x0); - v2 = glmm_splat_z(x0); - v3 = glmm_splat_w(x0); - - x1 = wasm_f32x4_mul(m3, v3); - x1 = glmm_fmadd(m2, v2, x1); - x1 = glmm_fmadd(m1, v1, x1); - x1 = glmm_fmadd(m0, v0, x1); - - glmm_store(dest, x1); -} - -CGLM_INLINE -float -glm_mat4_det_wasm(mat4 mat) { - glmm_128 r0, r1, r2, r3, x0, x1, x2; - - /* 127 <- 0, [square] det(A) = det(At) */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - - /* - t[1] = j * p - n * l; - t[2] = j * o - n * k; - t[3] = i * p - m * l; - t[4] = i * o - m * k; - */ - x0 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 1, 1), glmm_shuff1(r2, 2, 3, 2, 3), - wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 1, 1), - glmm_shuff1(r3, 2, 3, 2, 3))); - /* - t[0] = k * p - o * l; - t[0] = k * p - o * l; - t[5] = i * n - m * j; - t[5] = i * n - m * j; - */ - x1 = glmm_fnmadd(glmm_shuff1(r3, 0, 0, 2, 2), glmm_shuff1(r2, 1, 1, 3, 3), - wasm_f32x4_mul(glmm_shuff1(r2, 0, 0, 2, 2), - glmm_shuff1(r3, 1, 1, 3, 3))); - - /* - a * (f * t[0] - g * t[1] + h * t[2]) - - b * (e * t[0] - g * t[3] + h * t[4]) - + c * (e * t[1] - f * t[3] + h * t[5]) - - d * (e * t[2] - f * t[4] + g * t[5]) - */ - x2 = glmm_fnmadd(glmm_shuff1(r1, 1, 1, 2, 2), glmm_shuff1(x0, 3, 2, 2, 0), - wasm_f32x4_mul(glmm_shuff1(r1, 0, 0, 0, 1), - wasm_i32x4_shuffle(x1, x0, 0, 0, 4, 5))); - x2 = glmm_fmadd(glmm_shuff1(r1, 2, 3, 3, 3), - wasm_i32x4_shuffle(x0, x1, 1, 3, 6, 6), - x2); - /* x2 = wasm_v128_xor(x2, wasm_f32x4_const(0.f, -0.f, 0.f, -0.f)); */ - x2 = wasm_v128_xor(x2, glmm_float32x4_SIGNMASK_PNPN); - - return glmm_hadd(wasm_f32x4_mul(x2, r0)); -} - -CGLM_INLINE -void -glm_mat4_inv_fast_wasm(mat4 mat, mat4 dest) { - glmm_128 r0, r1, r2, r3, - v0, v1, v2, v3, - t0, t1, t2, t3, t4, t5, - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ - x8 = glmm_float32x4_SIGNMASK_PNPN; - x9 = glmm_shuff1(x8, 2, 1, 2, 1); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - /* x0 = _mm_movehl_ps(r3, r2); */ - x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ - /* x3 = _mm_movelh_ps(r2, r3); */ - x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ - x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ - x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ - x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ - x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ - - x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ - x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ - x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ - x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ - - t0 = wasm_f32x4_mul(x3, x1); - t1 = wasm_f32x4_mul(x5, x1); - t2 = wasm_f32x4_mul(x5, x2); - t3 = wasm_f32x4_mul(x6, x1); - t4 = wasm_f32x4_mul(x6, x2); - t5 = wasm_f32x4_mul(x6, x4); - - /* t1[0] = k * p - o * l; - t1[0] = k * p - o * l; - t2[0] = g * p - o * h; - t3[0] = g * l - k * h; */ - t0 = glmm_fnmadd(x2, x0, t0); - - /* t1[1] = j * p - n * l; - t1[1] = j * p - n * l; - t2[1] = f * p - n * h; - t3[1] = f * l - j * h; */ - t1 = glmm_fnmadd(x4, x0, t1); - - /* t1[2] = j * o - n * k - t1[2] = j * o - n * k; - t2[2] = f * o - n * g; - t3[2] = f * k - j * g; */ - t2 = glmm_fnmadd(x4, x3, t2); - - /* t1[3] = i * p - m * l; - t1[3] = i * p - m * l; - t2[3] = e * p - m * h; - t3[3] = e * l - i * h; */ - t3 = glmm_fnmadd(x7, x0, t3); - - /* t1[4] = i * o - m * k; - t1[4] = i * o - m * k; - t2[4] = e * o - m * g; - t3[4] = e * k - i * g; */ - t4 = glmm_fnmadd(x7, x3, t4); - - /* t1[5] = i * n - m * j; - t1[5] = i * n - m * j; - t2[5] = e * n - m * f; - t3[5] = e * j - i * f; */ - t5 = glmm_fnmadd(x7, x5, t5); - /* x4 = _mm_movelh_ps(r0, r1); */ - x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ - /* x5 = _mm_movehl_ps(r1, r0); */ - x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ - - x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ - x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ - x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ - x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ - - v2 = wasm_f32x4_mul(x0, t1); - v1 = wasm_f32x4_mul(x0, t0); - v3 = wasm_f32x4_mul(x0, t2); - v0 = wasm_f32x4_mul(x1, t0); - - v2 = glmm_fnmadd(x1, t3, v2); - v3 = glmm_fnmadd(x1, t4, v3); - v0 = glmm_fnmadd(x2, t1, v0); - v1 = glmm_fnmadd(x2, t3, v1); - - v3 = glmm_fmadd(x2, t5, v3); - v0 = glmm_fmadd(x3, t2, v0); - v2 = glmm_fmadd(x3, t5, v2); - v1 = glmm_fmadd(x3, t4, v1); - - /* - dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; - dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); - dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; - dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ - v0 = wasm_v128_xor(v0, x8); - - /* - dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; - dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); - dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; - dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ - v2 = wasm_v128_xor(v2, x8); - - /* - dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); - dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; - dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); - dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ - v1 = wasm_v128_xor(v1, x9); - - /* - dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); - dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; - dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); - dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ - v3 = wasm_v128_xor(v3, x9); - - /* determinant */ - x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); - x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); - x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); - - /* x0 = _mm_rcp_ps(glmm_vhadd(wasm_f32x4_mul(x0, r0))); */ - x0 = wasm_f32x4_div(wasm_f32x4_const_splat(1.0f), - glmm_vhadd(wasm_f32x4_mul(x0, r0))); - - glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); - glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); - glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); - glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); -} - -CGLM_INLINE -void -glm_mat4_inv_wasm(mat4 mat, mat4 dest) { - glmm_128 r0, r1, r2, r3, - v0, v1, v2, v3, - t0, t1, t2, t3, t4, t5, - x0, x1, x2, x3, x4, x5, x6, x7, x8, x9; - - /* x8 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ - x8 = glmm_float32x4_SIGNMASK_PNPN; - x9 = glmm_shuff1(x8, 2, 1, 2, 1); - - /* 127 <- 0 */ - r0 = glmm_load(mat[0]); /* d c b a */ - r1 = glmm_load(mat[1]); /* h g f e */ - r2 = glmm_load(mat[2]); /* l k j i */ - r3 = glmm_load(mat[3]); /* p o n m */ - /* x0 = _mm_movehl_ps(r3, r2); */ - x0 = wasm_i32x4_shuffle(r3, r2, 6, 7, 2, 3); /* p o l k */ - /* x3 = _mm_movelh_ps(r2, r3); */ - x3 = wasm_i32x4_shuffle(r2, r3, 0, 1, 4, 5); /* n m j i */ - x1 = glmm_shuff1(x0, 1, 3, 3 ,3); /* l p p p */ - x2 = glmm_shuff1(x0, 0, 2, 2, 2); /* k o o o */ - x4 = glmm_shuff1(x3, 1, 3, 3, 3); /* j n n n */ - x7 = glmm_shuff1(x3, 0, 2, 2, 2); /* i m m m */ - - x6 = wasm_i32x4_shuffle(r2, r1, 0, 0, 4, 4); /* e e i i */ - x5 = wasm_i32x4_shuffle(r2, r1, 1, 1, 5, 5); /* f f j j */ - x3 = wasm_i32x4_shuffle(r2, r1, 2, 2, 6, 6); /* g g k k */ - x0 = wasm_i32x4_shuffle(r2, r1, 3, 3, 7, 7); /* h h l l */ - - t0 = wasm_f32x4_mul(x3, x1); - t1 = wasm_f32x4_mul(x5, x1); - t2 = wasm_f32x4_mul(x5, x2); - t3 = wasm_f32x4_mul(x6, x1); - t4 = wasm_f32x4_mul(x6, x2); - t5 = wasm_f32x4_mul(x6, x4); - - /* t1[0] = k * p - o * l; - t1[0] = k * p - o * l; - t2[0] = g * p - o * h; - t3[0] = g * l - k * h; */ - t0 = glmm_fnmadd(x2, x0, t0); - - /* t1[1] = j * p - n * l; - t1[1] = j * p - n * l; - t2[1] = f * p - n * h; - t3[1] = f * l - j * h; */ - t1 = glmm_fnmadd(x4, x0, t1); - - /* t1[2] = j * o - n * k - t1[2] = j * o - n * k; - t2[2] = f * o - n * g; - t3[2] = f * k - j * g; */ - t2 = glmm_fnmadd(x4, x3, t2); - - /* t1[3] = i * p - m * l; - t1[3] = i * p - m * l; - t2[3] = e * p - m * h; - t3[3] = e * l - i * h; */ - t3 = glmm_fnmadd(x7, x0, t3); - - /* t1[4] = i * o - m * k; - t1[4] = i * o - m * k; - t2[4] = e * o - m * g; - t3[4] = e * k - i * g; */ - t4 = glmm_fnmadd(x7, x3, t4); - - /* t1[5] = i * n - m * j; - t1[5] = i * n - m * j; - t2[5] = e * n - m * f; - t3[5] = e * j - i * f; */ - t5 = glmm_fnmadd(x7, x5, t5); - /* x4 = _mm_movelh_ps(r0, r1); */ - x4 = wasm_i32x4_shuffle(r0, r1, 0, 1, 4, 5); /* f e b a */ - /* x5 = _mm_movehl_ps(r1, r0); */ - x5 = wasm_i32x4_shuffle(r1, r0, 6, 7, 2, 3); /* h g d c */ - - x0 = glmm_shuff1(x4, 0, 0, 0, 2); /* a a a e */ - x1 = glmm_shuff1(x4, 1, 1, 1, 3); /* b b b f */ - x2 = glmm_shuff1(x5, 0, 0, 0, 2); /* c c c g */ - x3 = glmm_shuff1(x5, 1, 1, 1, 3); /* d d d h */ - - v2 = wasm_f32x4_mul(x0, t1); - v1 = wasm_f32x4_mul(x0, t0); - v3 = wasm_f32x4_mul(x0, t2); - v0 = wasm_f32x4_mul(x1, t0); - - v2 = glmm_fnmadd(x1, t3, v2); - v3 = glmm_fnmadd(x1, t4, v3); - v0 = glmm_fnmadd(x2, t1, v0); - v1 = glmm_fnmadd(x2, t3, v1); - - v3 = glmm_fmadd(x2, t5, v3); - v0 = glmm_fmadd(x3, t2, v0); - v2 = glmm_fmadd(x3, t5, v2); - v1 = glmm_fmadd(x3, t4, v1); - - /* - dest[0][0] = f * t1[0] - g * t1[1] + h * t1[2]; - dest[0][1] =-(b * t1[0] - c * t1[1] + d * t1[2]); - dest[0][2] = b * t2[0] - c * t2[1] + d * t2[2]; - dest[0][3] =-(b * t3[0] - c * t3[1] + d * t3[2]); */ - v0 = wasm_v128_xor(v0, x8); - - /* - dest[2][0] = e * t1[1] - f * t1[3] + h * t1[5]; - dest[2][1] =-(a * t1[1] - b * t1[3] + d * t1[5]); - dest[2][2] = a * t2[1] - b * t2[3] + d * t2[5]; - dest[2][3] =-(a * t3[1] - b * t3[3] + d * t3[5]);*/ - v2 = wasm_v128_xor(v2, x8); - - /* - dest[1][0] =-(e * t1[0] - g * t1[3] + h * t1[4]); - dest[1][1] = a * t1[0] - c * t1[3] + d * t1[4]; - dest[1][2] =-(a * t2[0] - c * t2[3] + d * t2[4]); - dest[1][3] = a * t3[0] - c * t3[3] + d * t3[4]; */ - v1 = wasm_v128_xor(v1, x9); - - /* - dest[3][0] =-(e * t1[2] - f * t1[4] + g * t1[5]); - dest[3][1] = a * t1[2] - b * t1[4] + c * t1[5]; - dest[3][2] =-(a * t2[2] - b * t2[4] + c * t2[5]); - dest[3][3] = a * t3[2] - b * t3[4] + c * t3[5]; */ - v3 = wasm_v128_xor(v3, x9); - - /* determinant */ - x0 = wasm_i32x4_shuffle(v0, v1, 0, 0, 4, 4); - x1 = wasm_i32x4_shuffle(v2, v3, 0, 0, 4, 4); - x0 = wasm_i32x4_shuffle(x0, x1, 0, 2, 4, 6); - - x0 = wasm_f32x4_div(wasm_f32x4_splat(1.0f), glmm_vhadd(wasm_f32x4_mul(x0, r0))); - - glmm_store(dest[0], wasm_f32x4_mul(v0, x0)); - glmm_store(dest[1], wasm_f32x4_mul(v1, x0)); - glmm_store(dest[2], wasm_f32x4_mul(v2, x0)); - glmm_store(dest[3], wasm_f32x4_mul(v3, x0)); -} - -#endif -#endif /* cglm_mat_wasm_h */ diff --git a/external/cglm/simd/wasm/quat.h b/external/cglm/simd/wasm/quat.h deleted file mode 100644 index 8d72546..0000000 --- a/external/cglm/simd/wasm/quat.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_quat_wasm_h -#define cglm_quat_wasm_h -#if defined(__wasm__) && defined(__wasm_simd128__) - -#include "../../common.h" -#include "../intrin.h" - -CGLM_INLINE -void -glm_quat_mul_wasm(versor p, versor q, versor dest) { - /* - + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i - + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j - + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k - a1 a2 − b1 b2 − c1 c2 − d1 d2 - */ - - glmm_128 xp, xq, x1, x2, x3, r, x, y, z; - - xp = glmm_load(p); /* 3 2 1 0 */ - xq = glmm_load(q); - /* x1 = wasm_f32x4_const(0.f, -0.f, 0.f, -0.f); */ - x1 = glmm_float32x4_SIGNMASK_PNPN; /* TODO: _mm_set1_ss() + shuff ? */ - r = wasm_f32x4_mul(glmm_splat_w(xp), xq); - /* x2 = _mm_unpackhi_ps(x1, x1); */ - x2 = wasm_i32x4_shuffle(x1, x1, 2, 6, 3, 7); - x3 = glmm_shuff1(x1, 3, 2, 0, 1); - x = glmm_splat_x(xp); - y = glmm_splat_y(xp); - z = glmm_splat_z(xp); - - x = wasm_v128_xor(x, x1); - y = wasm_v128_xor(y, x2); - z = wasm_v128_xor(z, x3); - - x1 = glmm_shuff1(xq, 0, 1, 2, 3); - x2 = glmm_shuff1(xq, 1, 0, 3, 2); - x3 = glmm_shuff1(xq, 2, 3, 0, 1); - - r = glmm_fmadd(x, x1, r); - r = glmm_fmadd(y, x2, r); - r = glmm_fmadd(z, x3, r); - - glmm_store(dest, r); -} - -#endif -#endif /* cglm_quat_wasm_h */ diff --git a/external/cglm/simd/x86.h b/external/cglm/simd/x86.h deleted file mode 100644 index 2410d0f..0000000 --- a/external/cglm/simd/x86.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_simd_x86_h -#define cglm_simd_x86_h -#include "intrin.h" -#ifdef CGLM_SIMD_x86 - -#ifdef CGLM_ALL_UNALIGNED -# define glmm_load(p) _mm_loadu_ps(p) -# define glmm_store(p, a) _mm_storeu_ps(p, a) -#else -# define glmm_load(p) _mm_load_ps(p) -# define glmm_store(p, a) _mm_store_ps(p, a) -#endif - -#define glmm_128 __m128 - -#ifdef __AVX__ -# define glmm_shuff1(xmm, z, y, x, w) \ - _mm_permute_ps((xmm), _MM_SHUFFLE(z, y, x, w)) -#else -# if !defined(CGLM_NO_INT_DOMAIN) && defined(__SSE2__) -# define glmm_shuff1(xmm, z, y, x, w) \ - _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xmm), \ - _MM_SHUFFLE(z, y, x, w))) -# else -# define glmm_shuff1(xmm, z, y, x, w) \ - _mm_shuffle_ps(xmm, xmm, _MM_SHUFFLE(z, y, x, w)) -# endif -#endif - -#define glmm_splat(x, lane) glmm_shuff1(x, lane, lane, lane, lane) - -#ifdef __AVX__ -# define glmm_set1(x) _mm_broadcast_ss(&x) -# define glmm_set1_ptr(x) _mm_broadcast_ss(x) -# define glmm_set1_rval(x) _mm_set1_ps(x) -# ifdef __AVX2__ -# define glmm_splat_x(x) _mm_broadcastss_ps(x) -# else -# define glmm_splat_x(x) _mm_permute_ps(x, _MM_SHUFFLE(0, 0, 0, 0)) -# endif -# define glmm_splat_y(x) _mm_permute_ps(x, _MM_SHUFFLE(1, 1, 1, 1)) -# define glmm_splat_z(x) _mm_permute_ps(x, _MM_SHUFFLE(2, 2, 2, 2)) -# define glmm_splat_w(x) _mm_permute_ps(x, _MM_SHUFFLE(3, 3, 3, 3)) -#else -# define glmm_set1(x) _mm_set1_ps(x) -# define glmm_set1_ptr(x) _mm_set1_ps(*x) -# define glmm_set1_rval(x) _mm_set1_ps(x) - -# define glmm_splat_x(x) glmm_splat(x, 0) -# define glmm_splat_y(x) glmm_splat(x, 1) -# define glmm_splat_z(x) glmm_splat(x, 2) -# define glmm_splat_w(x) glmm_splat(x, 3) -#endif - -#ifdef __AVX__ -# ifdef CGLM_ALL_UNALIGNED -# define glmm_load256(p) _mm256_loadu_ps(p) -# define glmm_store256(p, a) _mm256_storeu_ps(p, a) -# else -# define glmm_load256(p) _mm256_load_ps(p) -# define glmm_store256(p, a) _mm256_store_ps(p, a) -# endif -#endif - -/* Note that `0x80000000` corresponds to `INT_MIN` for a 32-bit int. */ - -#if defined(__SSE2__) -# define GLMM_NEGZEROf ((int)0x80000000) /* 0x80000000 ---> -0.0f */ -# define GLMM_POSZEROf ((int)0x00000000) /* 0x00000000 ---> +0.0f */ -#else -# ifdef CGLM_FAST_MATH - union { int i; float f; } static GLMM_NEGZEROf_TU = { .i = (int)0x80000000 }; -# define GLMM_NEGZEROf GLMM_NEGZEROf_TU.f -# define GLMM_POSZEROf 0.0f -# else -# define GLMM_NEGZEROf -0.0f -# define GLMM_POSZEROf 0.0f -# endif -#endif - -#if defined(__SSE2__) -# define GLMM__SIGNMASKf(X, Y, Z, W) \ - _mm_castsi128_ps(_mm_set_epi32(X, Y, Z, W)) - /* _mm_set_ps(X, Y, Z, W); */ -#else -# define GLMM__SIGNMASKf(X, Y, Z, W) _mm_set_ps(X, Y, Z, W) -#endif - -#define glmm_float32x4_SIGNMASK_PNPN GLMM__SIGNMASKf(GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf) -#define glmm_float32x4_SIGNMASK_NPNP GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_NEGZEROf, GLMM_POSZEROf) -#define glmm_float32x4_SIGNMASK_NPPN GLMM__SIGNMASKf(GLMM_NEGZEROf, GLMM_POSZEROf, GLMM_POSZEROf, GLMM_NEGZEROf) - -/* fasth math prevents -0.0f to work */ -#if defined(__SSE2__) -# define glmm_float32x4_SIGNMASK_NEG _mm_castsi128_ps(_mm_set1_epi32(GLMM_NEGZEROf)) /* _mm_set1_ps(-0.0f) */ -#else -# define glmm_float32x4_SIGNMASK_NEG glmm_set1(GLMM_NEGZEROf) -#endif - -#define glmm_float32x8_SIGNMASK_NEG _mm256_castsi256_ps(_mm256_set1_epi32(GLMM_NEGZEROf)) - -static inline -__m128 -glmm_abs(__m128 x) { - return _mm_andnot_ps(glmm_float32x4_SIGNMASK_NEG, x); -} - -static inline __m128 glmm_min(__m128 a, __m128 b) { return _mm_min_ps(a, b); } -static inline __m128 glmm_max(__m128 a, __m128 b) { return _mm_max_ps(a, b); } - -static inline -__m128 -glmm_vhadd(__m128 v) { - __m128 x0; - x0 = _mm_add_ps(v, glmm_shuff1(v, 0, 1, 2, 3)); - x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 0, 1)); - return x0; -} - -static inline -__m128 -glmm_vhadds(__m128 v) { -#if defined(__SSE3__) - __m128 shuf, sums; - shuf = _mm_movehdup_ps(v); - sums = _mm_add_ps(v, shuf); - shuf = _mm_movehl_ps(shuf, sums); - sums = _mm_add_ss(sums, shuf); - return sums; -#else - __m128 shuf, sums; - shuf = glmm_shuff1(v, 2, 3, 0, 1); - sums = _mm_add_ps(v, shuf); - shuf = _mm_movehl_ps(shuf, sums); - sums = _mm_add_ss(sums, shuf); - return sums; -#endif -} - -static inline -float -glmm_hadd(__m128 v) { - return _mm_cvtss_f32(glmm_vhadds(v)); -} - -static inline -__m128 -glmm_vhmin(__m128 v) { - __m128 x0, x1, x2; - x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ - x1 = _mm_min_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ - x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ - return _mm_min_ss(x1, x2); -} - -static inline -float -glmm_hmin(__m128 v) { - return _mm_cvtss_f32(glmm_vhmin(v)); -} - -static inline -__m128 -glmm_vhmax(__m128 v) { - __m128 x0, x1, x2; - x0 = _mm_movehl_ps(v, v); /* [2, 3, 2, 3] */ - x1 = _mm_max_ps(x0, v); /* [0|2, 1|3, 2|2, 3|3] */ - x2 = glmm_splat(x1, 1); /* [1|3, 1|3, 1|3, 1|3] */ - return _mm_max_ss(x1, x2); -} - -static inline -float -glmm_hmax(__m128 v) { - return _mm_cvtss_f32(glmm_vhmax(v)); -} - -static inline -__m128 -glmm_vdots(__m128 a, __m128 b) { -#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) - return _mm_dp_ps(a, b, 0xFF); -#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) - __m128 x0, x1; - x0 = _mm_mul_ps(a, b); - x1 = _mm_hadd_ps(x0, x0); - return _mm_hadd_ps(x1, x1); -#else - return glmm_vhadds(_mm_mul_ps(a, b)); -#endif -} - -static inline -__m128 -glmm_vdot(__m128 a, __m128 b) { -#if (defined(__SSE4_1__) || defined(__SSE4_2__)) && defined(CGLM_SSE4_DOT) - return _mm_dp_ps(a, b, 0xFF); -#elif defined(__SSE3__) && defined(CGLM_SSE3_DOT) - __m128 x0, x1; - x0 = _mm_mul_ps(a, b); - x1 = _mm_hadd_ps(x0, x0); - return _mm_hadd_ps(x1, x1); -#else - __m128 x0; - x0 = _mm_mul_ps(a, b); - x0 = _mm_add_ps(x0, glmm_shuff1(x0, 1, 0, 3, 2)); - return _mm_add_ps(x0, glmm_shuff1(x0, 0, 1, 0, 1)); -#endif -} - -static inline -float -glmm_dot(__m128 a, __m128 b) { - return _mm_cvtss_f32(glmm_vdots(a, b)); -} - -static inline -float -glmm_norm(__m128 a) { - return _mm_cvtss_f32(_mm_sqrt_ss(glmm_vhadds(_mm_mul_ps(a, a)))); -} - -static inline -float -glmm_norm2(__m128 a) { - return _mm_cvtss_f32(glmm_vhadds(_mm_mul_ps(a, a))); -} - -static inline -float -glmm_norm_one(__m128 a) { - return _mm_cvtss_f32(glmm_vhadds(glmm_abs(a))); -} - -static inline -float -glmm_norm_inf(__m128 a) { - return _mm_cvtss_f32(glmm_vhmax(glmm_abs(a))); -} - -#if defined(__SSE2__) -static inline -__m128 -glmm_load3(float v[3]) { - __m128i xy; - __m128 z; - - xy = _mm_loadl_epi64(CGLM_CASTPTR_ASSUME_ALIGNED(v, const __m128i)); - z = _mm_load_ss(&v[2]); - - return _mm_movelh_ps(_mm_castsi128_ps(xy), z); -} - -static inline -void -glmm_store3(float v[3], __m128 vx) { - _mm_storel_pi(CGLM_CASTPTR_ASSUME_ALIGNED(v, __m64), vx); - _mm_store_ss(&v[2], glmm_shuff1(vx, 2, 2, 2, 2)); -} -#endif - -static inline -__m128 -glmm_div(__m128 a, __m128 b) { - return _mm_div_ps(a, b); -} - -/* enable FMA macro for MSVC? */ -#if defined(_MSC_VER) && !defined(__FMA__) && defined(__AVX2__) -# define __FMA__ 1 -#endif - -static inline -__m128 -glmm_fmadd(__m128 a, __m128 b, __m128 c) { -#ifdef __FMA__ - return _mm_fmadd_ps(a, b, c); -#else - return _mm_add_ps(c, _mm_mul_ps(a, b)); -#endif -} - -static inline -__m128 -glmm_fnmadd(__m128 a, __m128 b, __m128 c) { -#ifdef __FMA__ - return _mm_fnmadd_ps(a, b, c); -#else - return _mm_sub_ps(c, _mm_mul_ps(a, b)); -#endif -} - -static inline -__m128 -glmm_fmsub(__m128 a, __m128 b, __m128 c) { -#ifdef __FMA__ - return _mm_fmsub_ps(a, b, c); -#else - return _mm_sub_ps(_mm_mul_ps(a, b), c); -#endif -} - -static inline -__m128 -glmm_fnmsub(__m128 a, __m128 b, __m128 c) { -#ifdef __FMA__ - return _mm_fnmsub_ps(a, b, c); -#else - return _mm_xor_ps(_mm_add_ps(_mm_mul_ps(a, b), c), - glmm_float32x4_SIGNMASK_NEG); -#endif -} - -#if defined(__AVX__) -static inline -__m256 -glmm256_fmadd(__m256 a, __m256 b, __m256 c) { -#ifdef __FMA__ - return _mm256_fmadd_ps(a, b, c); -#else - return _mm256_add_ps(c, _mm256_mul_ps(a, b)); -#endif -} - -static inline -__m256 -glmm256_fnmadd(__m256 a, __m256 b, __m256 c) { -#ifdef __FMA__ - return _mm256_fnmadd_ps(a, b, c); -#else - return _mm256_sub_ps(c, _mm256_mul_ps(a, b)); -#endif -} - -static inline -__m256 -glmm256_fmsub(__m256 a, __m256 b, __m256 c) { -#ifdef __FMA__ - return _mm256_fmsub_ps(a, b, c); -#else - return _mm256_sub_ps(_mm256_mul_ps(a, b), c); -#endif -} - -static inline -__m256 -glmm256_fnmsub(__m256 a, __m256 b, __m256 c) { -#ifdef __FMA__ - return _mm256_fmsub_ps(a, b, c); -#else - return _mm256_xor_ps(_mm256_sub_ps(_mm256_mul_ps(a, b), c), - glmm_float32x8_SIGNMASK_NEG); -#endif -} -#endif - -#endif -#endif /* cglm_simd_x86_h */ diff --git a/external/cglm/sphere.h b/external/cglm/sphere.h deleted file mode 100644 index 334b83a..0000000 --- a/external/cglm/sphere.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_sphere_h -#define cglm_sphere_h - -#include "common.h" -#include "mat4.h" - -/* - Sphere Representation in cglm: [center.x, center.y, center.z, radii] - - You could use this representation or you can convert it to vec4 before call - any function - */ - -/*! - * @brief helper for getting sphere radius - * - * @param[in] s sphere - * - * @return returns radii - */ -CGLM_INLINE -float -glm_sphere_radii(vec4 s) { - return s[3]; -} - -/*! - * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 - * - * @param[in] s sphere - * @param[in] m transform matrix - * @param[out] dest transformed sphere - */ -CGLM_INLINE -void -glm_sphere_transform(vec4 s, mat4 m, vec4 dest) { - glm_mat4_mulv3(m, s, 1.0f, dest); - dest[3] = s[3]; -} - -/*! - * @brief merges two spheres and creates a new one - * - * two sphere must be in same space, for instance if one in world space then - * the other must be in world space too, not in local space. - * - * @param[in] s1 sphere 1 - * @param[in] s2 sphere 2 - * @param[out] dest merged/extended sphere - */ -CGLM_INLINE -void -glm_sphere_merge(vec4 s1, vec4 s2, vec4 dest) { - float dist, radii; - - dist = glm_vec3_distance(s1, s2); - radii = dist + s1[3] + s2[3]; - - radii = glm_max(radii, s1[3]); - radii = glm_max(radii, s2[3]); - - glm_vec3_center(s1, s2, dest); - dest[3] = radii; -} - -/*! - * @brief check if two sphere intersects - * - * @param[in] s1 sphere - * @param[in] s2 other sphere - */ -CGLM_INLINE -bool -glm_sphere_sphere(vec4 s1, vec4 s2) { - return glm_vec3_distance2(s1, s2) <= glm_pow2(s1[3] + s2[3]); -} - -/*! - * @brief check if sphere intersects with point - * - * @param[in] s sphere - * @param[in] point point - */ -CGLM_INLINE -bool -glm_sphere_point(vec4 s, vec3 point) { - float rr; - rr = s[3] * s[3]; - return glm_vec3_distance2(point, s) <= rr; -} - -#endif /* cglm_sphere_h */ diff --git a/external/cglm/struct.h b/external/cglm/struct.h deleted file mode 100644 index 31ca4e2..0000000 --- a/external/cglm/struct.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_structs_h -#define cglm_structs_h -#ifdef __cplusplus -extern "C" { -#endif - -#include "cglm.h" -#include "types-struct.h" -#include "struct/vec2.h" -#include "struct/vec3.h" -#include "struct/vec4.h" -#include "struct/ivec2.h" -#include "struct/ivec3.h" -#include "struct/ivec4.h" -#include "struct/mat2.h" -#include "struct/mat2x3.h" -#include "struct/mat2x4.h" -#include "struct/mat3.h" -#include "struct/mat3x2.h" -#include "struct/mat3x4.h" -#include "struct/mat4.h" -#include "struct/mat4x2.h" -#include "struct/mat4x3.h" -#include "struct/affine.h" -#include "struct/frustum.h" -#include "struct/plane.h" -#include "struct/noise.h" -#include "struct/box.h" -#include "struct/color.h" -#include "struct/io.h" -#include "struct/cam.h" -#include "struct/quat.h" -#include "struct/euler.h" -#include "struct/project.h" -#include "struct/sphere.h" -#include "struct/curve.h" -#include "struct/affine2d.h" -#include "struct/ray.h" - -#ifdef __cplusplus -} -#endif -#endif /* cglm_structs_h */ diff --git a/external/cglm/struct/aabb2d.h b/external/cglm/struct/aabb2d.h deleted file mode 100644 index 9077069..0000000 --- a/external/cglm/struct/aabb2d.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_aabb2ds_h -#define cglms_aabb2ds_h - -#include "../common.h" -#include "../types-struct.h" -#include "../aabb2d.h" -#include "vec2.h" -#include "vec4.h" -#include "mat4.h" - -/* api definition */ -#define glms_aabb2d_(NAME) CGLM_STRUCTAPI(aabb2d, NAME) - -/*! - * @brief apply transform to Axis-Aligned Bounding Box - * - * @param[in] aabb bounding box - * @param[in] m transform matrix - * @param[out] dest transformed bounding box - */ -CGLM_INLINE -void -glms_aabb2d_(transform)(vec2s aabb[2], mat3s m, vec2s dest[2]) { - vec2 rawAabb[2]; - vec2 rawDest[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - glm_aabb2d_transform(rawAabb, m.raw, rawDest); - glms_vec2_(pack)(dest, rawDest, 2); -} - -/*! - * @brief merges two AABB bounding box and creates new one - * - * two box must be in same space, if one of box is in different space then - * you should consider to convert it's space by glm_box_space - * - * @param[in] aabb1 bounding box 1 - * @param[in] aabb2 bounding box 2 - * @param[out] dest merged bounding box - */ -CGLM_INLINE -void -glms_aabb2d_(merge)(vec2s aabb1[2], vec2s aabb2[2], vec2s dest[2]) { - vec2 rawAabb1[2]; - vec2 rawAabb2[2]; - vec2 rawDest[2]; - - glms_vec2_(unpack)(rawAabb1, aabb1, 2); - glms_vec2_(unpack)(rawAabb2, aabb2, 2); - glm_aabb2d_merge(rawAabb1, rawAabb2, rawDest); - glms_vec2_(pack)(dest, rawDest, 2); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] aabb bounding box 1 - * @param[in] cropAabb crop box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glms_aabb2d_(crop)(vec2s aabb[2], vec2s cropAabb[2], vec2s dest[2]) { - vec2 rawAabb[2]; - vec2 rawCropAabb[2]; - vec2 rawDest[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - glms_vec2_(unpack)(rawCropAabb, cropAabb, 2); - glm_aabb2d_crop(rawAabb, rawCropAabb, rawDest); - glms_vec2_(pack)(dest, rawDest, 2); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] aabb bounding box - * @param[in] cropAabb crop box - * @param[in] clampAabb minimum box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glms_aabb2d_(crop_until)(vec2s aabb[2], - vec2s cropAabb[2], - vec2s clampAabb[2], - vec2s dest[2]) { - glms_aabb2d_(crop)(aabb, cropAabb, dest); - glms_aabb2d_(merge)(clampAabb, dest, dest); -} - -/*! - * @brief invalidate AABB min and max values - * - * @param[in, out] aabb bounding box - */ -CGLM_INLINE -void -glms_aabb2d_(invalidate)(vec2s box[2]) { - box[0] = glms_vec2_(fill)(FLT_MAX); - box[1] = glms_vec2_(fill)(-FLT_MAX); -} - -/*! - * @brief check if AABB is valid or not - * - * @param[in] aabb bounding box - */ -CGLM_INLINE -bool -glms_aabb2d_(isvalid)(vec2s aabb[2]) { - vec2 rawAabb[2]; - glms_vec2_(unpack)(rawAabb, aabb, 2); - return glm_aabb2d_isvalid(rawAabb); -} - -/*! - * @brief distance between of min and max - * - * @param[in] aabb bounding box - */ -CGLM_INLINE -float -glms_aabb2d_(diag)(vec2s aabb[2]) { - vec2 rawAabb[2]; - glms_vec2_(unpack)(rawAabb, aabb, 2); - return glm_aabb2d_diag(rawAabb); -} - - -/*! - * @brief size of aabb - * - * @param[in] aabb bounding aabb - * @param[out] dest size - */ -CGLM_INLINE -vec2s -glms_aabb2d_(sizev)(vec2s aabb[2]) { - vec2s size; - vec2 rawAabb[2]; - glms_vec2_(unpack)(rawAabb, aabb, 2); - glm_aabb2d_sizev(rawAabb, size.raw); - return size; -} - -/*! - * @brief radius of sphere which surrounds AABB - * - * @param[in] aabb bounding box - */ -CGLM_INLINE -float -glms_aabb2d_(radius)(vec2s aabb[2]) { - return glms_aabb2d_(size)(aabb) * 0.5f; -} - -/*! - * @brief computes center point of AABB - * - * @param[in] aabb bounding box - * @returns center of bounding box - */ -CGLM_INLINE -vec2s -glms_aabb2d_(center)(vec2s aabb[2]) { - return glms_vec2_(center)(aabb[0], aabb[1]); -} - -/*! - * @brief check if two AABB intersects - * - * @param[in] aabb bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glms_aabb2d_(aabb)(vec2s aabb[2], vec2s other[2]) { - vec2 rawAabb[2]; - vec2 rawOther[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - glms_vec2_(unpack)(rawOther, other, 2); - return glm_aabb2d_aabb(rawAabb, rawOther); -} - -/*! - * @brief check if AABB intersects with a circle - * - * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c - * Solid Box - Solid Sphere test. - * - * @param[in] aabb solid bounding box - * @param[in] s solid sphere - */ -CGLM_INLINE -bool -glms_aabb2d_(circle)(vec2s aabb[2], vec3s c) { - vec2 rawAabb[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - return glm_aabb2d_circle(rawAabb, c.raw); -} - -/*! - * @brief check if point is inside of AABB - * - * @param[in] aabb bounding box - * @param[in] point point - */ -CGLM_INLINE -bool -glms_aabb2d_(point)(vec2s aabb[2], vec2s point) { - vec2 rawAabb[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - return glm_aabb2d_point(rawAabb, point.raw); -} - -/*! - * @brief check if AABB contains other AABB - * - * @param[in] box bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glms_aabb2d_(contains)(vec2s aabb[2], vec2s other[2]) { - vec2 rawAabb[2]; - vec2 rawOther[2]; - - glms_vec2_(unpack)(rawAabb, aabb, 2); - glms_vec2_(unpack)(rawOther, other, 2); - return glm_aabb2d_contains(rawAabb, rawOther); -} - -#endif /* cglms_aabb2ds_h */ diff --git a/external/cglm/struct/affine-mat.h b/external/cglm/struct/affine-mat.h deleted file mode 100644 index e1d4ff3..0000000 --- a/external/cglm/struct/affine-mat.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_mul(mat4 m1, mat4 m2); - CGLM_INLINE mat4s glms_mul_rot(mat4 m1, mat4 m2); - CGLM_INLINE mat4s glms_inv_tr(); - */ - -#ifndef cglms_affine_mat_h -#define cglms_affine_mat_h - -#include "../common.h" -#include "../types-struct.h" -#include "../affine-mat.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -/*! - * @brief this is similar to glms_mat4_mul but specialized to affine transform - * - * Matrix format should be: - * R R R X - * R R R Y - * R R R Z - * 0 0 0 W - * - * this reduces some multiplications. It should be faster than mat4_mul. - * if you are not sure about matrix format then DON'T use this! use mat4_mul - * - * @param[in] m1 affine matrix 1 - * @param[in] m2 affine matrix 2 - * @returns destination matrix - */ -CGLM_INLINE -mat4s -glms_mul(mat4s m1, mat4s m2){ - mat4s r; - glm_mul(m1.raw, m2.raw, r.raw); - return r; -} - -/*! - * @brief this is similar to glm_mat4_mul but specialized to affine transform - * - * Right Matrix format should be: - * R R R 0 - * R R R 0 - * R R R 0 - * 0 0 0 1 - * - * this reduces some multiplications. It should be faster than mat4_mul. - * if you are not sure about matrix format then DON'T use this! use mat4_mul - * - * @param[in] m1 affine matrix 1 - * @param[in] m2 affine matrix 2 - * @returns destination matrix - */ -CGLM_INLINE -mat4s -glms_mul_rot(mat4s m1, mat4s m2){ - mat4s r; - glm_mul_rot(m1.raw, m2.raw, r.raw); - return r; -} - -/*! - * @brief inverse orthonormal rotation + translation matrix (ridig-body) - * - * @code - * X = | R T | X' = | R' -R'T | - * | 0 1 | | 0 1 | - * @endcode - * - * @param[in] m matrix - * @returns destination matrix - */ -CGLM_INLINE -mat4s -glms_inv_tr(mat4s m){ - glm_inv_tr(m.raw); - return m; -} -#endif /* cglms_affine_mat_h */ diff --git a/external/cglm/struct/affine-post.h b/external/cglm/struct/affine-post.h deleted file mode 100644 index e155660..0000000 --- a/external/cglm/struct/affine-post.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_translated(mat4s m, vec3s v); - CGLM_INLINE mat4s glms_translated_x(mat4s m, float x); - CGLM_INLINE mat4s glms_translated_y(mat4s m, float y); - CGLM_INLINE mat4s glms_translated_z(mat4s m, float z); - CGLM_INLINE mat4s glms_rotated_x(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotated_y(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotated_z(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotated(mat4s m, float angle, vec3s axis); - CGLM_INLINE mat4s glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis); - CGLM_INLINE mat4s glms_spinned(mat4s m, float angle, vec3s axis); - */ - -#ifndef cglms_affines_post_h -#define cglms_affines_post_h - -#include "../common.h" -#include "../types-struct.h" -#include "../affine.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -/*! - * @brief translate existing transform matrix by v vector - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translated(mat4s m, vec3s v) { - glm_translated(m.raw, v.raw); - return m; -} - -/*! - * @brief translate existing transform matrix by x factor - * - * @param[in] m affine transform - * @param[in] x x factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translated_x(mat4s m, float x) { - glm_translated_x(m.raw, x); - return m; -} - -/*! - * @brief translate existing transform matrix by y factor - * - * @param[in] m affine transform - * @param[in] y y factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translated_y(mat4s m, float y) { - glm_translated_y(m.raw, y); - return m; -} - -/*! - * @brief translate existing transform matrix by z factor - * - * @param[in] m affine transform - * @param[in] z z factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translated_z(mat4s m, float z) { - glm_translated_z(m.raw, z); - return m; -} - -/*! - * @brief rotate existing transform matrix around X axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotated_x(mat4s m, float angle) { - mat4s r; - glm_rotated_x(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around Y axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotated_y(mat4s m, float angle) { - mat4s r; - glm_rotated_y(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around Z axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotated_z(mat4s m, float angle) { - mat4s r; - glm_rotated_z(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around given axis by angle - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotated(mat4s m, float angle, vec3s axis) { - glm_rotated(m.raw, angle, axis.raw); - return m; -} - -/*! - * @brief rotate existing transform - * around given axis by angle at given pivot point (rotation center) - * - * @param[in] m affine transform - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotated_at(mat4s m, vec3s pivot, float angle, vec3s axis) { - glm_rotated_at(m.raw, pivot.raw, angle, axis.raw); - return m; -} - -/*! - * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_spinned(mat4s m, float angle, vec3s axis) { - glm_spinned(m.raw, angle, axis.raw); - return m; -} - -#endif /* cglms_affines_post_h */ diff --git a/external/cglm/struct/affine-pre.h b/external/cglm/struct/affine-pre.h deleted file mode 100644 index e323ffa..0000000 --- a/external/cglm/struct/affine-pre.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); - CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); - CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); - CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); - CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); - CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); - CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); - */ - -#ifndef cglms_affines_pre_h -#define cglms_affines_pre_h - -#include "../common.h" -#include "../types-struct.h" -#include "../affine.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -/*! - * @brief translate existing transform matrix by v vector - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translate(mat4s m, vec3s v) { - glm_translate(m.raw, v.raw); - return m; -} - -/*! - * @brief translate existing transform matrix by x factor - * - * @param[in] m affine transform - * @param[in] x x factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translate_x(mat4s m, float x) { - glm_translate_x(m.raw, x); - return m; -} - -/*! - * @brief translate existing transform matrix by y factor - * - * @param[in] m affine transform - * @param[in] y y factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translate_y(mat4s m, float y) { - glm_translate_y(m.raw, y); - return m; -} - -/*! - * @brief translate existing transform matrix by z factor - * - * @param[in] m affine transform - * @param[in] z z factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translate_z(mat4s m, float z) { - glm_translate_z(m.raw, z); - return m; -} - -/*! - * @brief rotate existing transform matrix around X axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotate_x(mat4s m, float angle) { - mat4s r; - glm_rotate_x(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around Y axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotate_y(mat4s m, float angle) { - mat4s r; - glm_rotate_y(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around Z axis by angle - * and store result in dest - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns rotated matrix - */ -CGLM_INLINE -mat4s -glms_rotate_z(mat4s m, float angle) { - mat4s r; - glm_rotate_z(m.raw, angle, r.raw); - return r; -} - -/*! - * @brief rotate existing transform matrix around given axis by angle - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotate(mat4s m, float angle, vec3s axis) { - glm_rotate(m.raw, angle, axis.raw); - return m; -} - -/*! - * @brief rotate existing transform - * around given axis by angle at given pivot point (rotation center) - * - * @param[in] m affine transform - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis) { - glm_rotate_at(m.raw, pivot.raw, angle, axis.raw); - return m; -} - -/*! - * @brief rotate existing transform matrix around given axis by angle around self (doesn't affected by position) - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_spin(mat4s m, float angle, vec3s axis) { - glm_spin(m.raw, angle, axis.raw); - return m; -} - -#endif /* cglms_affines_pre_h */ diff --git a/external/cglm/struct/affine.h b/external/cglm/struct/affine.h deleted file mode 100644 index 37f11be..0000000 --- a/external/cglm/struct/affine.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_translate(mat4s m, vec3s v); - CGLM_INLINE mat4s glms_translate_x(mat4s m, float x); - CGLM_INLINE mat4s glms_translate_y(mat4s m, float y); - CGLM_INLINE mat4s glms_translate_z(mat4s m, float z); - CGLM_INLINE mat4s glms_translate_make(vec3s v); - CGLM_INLINE mat4s glms_scale_to(mat4s m, vec3s v); - CGLM_INLINE mat4s glms_scale_make(vec3s v); - CGLM_INLINE mat4s glms_scale(mat4s m, vec3s v); - CGLM_INLINE mat4s glms_scale_uni(mat4s m, float s); - CGLM_INLINE mat4s glms_rotate_x(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate_y(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate_z(mat4s m, float angle); - CGLM_INLINE mat4s glms_rotate_make(float angle, vec3s axis); - CGLM_INLINE mat4s glms_rotate(mat4s m, float angle, vec3s axis); - CGLM_INLINE mat4s glms_rotate_at(mat4s m, vec3s pivot, float angle, vec3s axis); - CGLM_INLINE mat4s glms_rotate_atm(vec3s pivot, float angle, vec3s axis); - CGLM_INLINE mat4s glms_spin(mat4s m, float angle, vec3s axis); - CGLM_INLINE vec3s glms_decompose_scalev(mat4s m); - CGLM_INLINE bool glms_uniscaled(mat4s m); - CGLM_INLINE void glms_decompose_rs(mat4s m, mat4s * r, vec3s * s); - CGLM_INLINE void glms_decompose(mat4s m, vec4s t, mat4s * r, vec3s * s); - */ - -#ifndef cglms_affines_h -#define cglms_affines_h - -#include "../common.h" -#include "../types-struct.h" -#include "../affine.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" -#include "affine-mat.h" - -/*! - * @brief creates NEW translate transform matrix by v vector - * - * @param[in] v translate vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_translate_make(vec3s v) { - mat4s m; - glm_translate_make(m.raw, v.raw); - return m; -} - -/*! - * @brief creates NEW scale matrix by v vector - * - * @param[in] v scale vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_scale_make(vec3s v) { - mat4s m; - glm_scale_make(m.raw, v.raw); - return m; -} - -/*! - * @brief scales existing transform matrix by v vector - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] v scale vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_scale(mat4s m, vec3s v) { - mat4s r; - glm_scale_to(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief applies uniform scale to existing transform matrix v = [s, s, s] - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] s scale factor - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_scale_uni(mat4s m, float s) { - glm_scale_uni(m.raw, s); - return m; -} - -/*! - * @brief creates NEW rotation matrix by angle and axis - * - * axis will be normalized so you don't need to normalize it - * - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotate_make(float angle, vec3s axis) { - mat4s m; - glm_rotate_make(m.raw, angle, axis.raw); - return m; -} - -/*! - * @brief creates NEW rotation matrix by angle and axis at given point - * - * this creates rotation matrix, it assumes you don't have a matrix - * - * this should work faster than glm_rotate_at because it reduces - * one glm_translate. - * - * @param[in] pivot rotation center - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns affine transform - */ -CGLM_INLINE -mat4s -glms_rotate_atm(vec3s pivot, float angle, vec3s axis) { - mat4s m; - glm_rotate_atm(m.raw, pivot.raw, angle, axis.raw); - return m; -} - -/*! - * @brief decompose scale vector - * - * @param[in] m affine transform - * @returns scale vector (Sx, Sy, Sz) - */ -CGLM_INLINE -vec3s -glms_decompose_scalev(mat4s m) { - vec3s r; - glm_decompose_scalev(m.raw, r.raw); - return r; -} - -/*! - * @brief returns true if matrix is uniform scaled. This is helpful for - * creating normal matrix. - * - * @param[in] m m - * - * @return boolean - */ -CGLM_INLINE -bool -glms_uniscaled(mat4s m) { - return glm_uniscaled(m.raw); -} - -/*! - * @brief decompose rotation matrix (mat4) and scale vector [Sx, Sy, Sz] - * DON'T pass projected matrix here - * - * @param[in] m affine transform - * @param[out] r rotation matrix - * @param[out] s scale matrix - */ -CGLM_INLINE -void -glms_decompose_rs(mat4s m, mat4s * __restrict r, vec3s * __restrict s) { - glm_decompose_rs(m.raw, r->raw, s->raw); -} - -/*! - * @brief decompose affine transform, TODO: extract shear factors. - * DON'T pass projected matrix here - * - * @param[in] m affine transform - * @param[out] t translation vector - * @param[out] r rotation matrix (mat4) - * @param[out] s scaling vector [X, Y, Z] - */ -CGLM_INLINE -void -glms_decompose(mat4s m, vec4s * __restrict t, mat4s * __restrict r, vec3s * __restrict s) { - glm_decompose(m.raw, t->raw, r->raw, s->raw); -} - -#include "affine-pre.h" -#include "affine-post.h" - -#endif /* cglms_affines_h */ diff --git a/external/cglm/struct/affine2d.h b/external/cglm/struct/affine2d.h deleted file mode 100644 index ade7c32..0000000 --- a/external/cglm/struct/affine2d.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat3s glms_translate2d(mat3 m, vec2 v) - CGLM_INLINE mat3s glms_translate2d_x(mat3s m, float x) - CGLM_INLINE mat3s glms_translate2d_y(mat3s m, float y) - CGLM_INLINE mat3s glms_translate2d_make(vec2s v) - CGLM_INLINE mat3s glms_scale2d_make(vec2s v) - CGLM_INLINE mat3s glms_scale2d(mat3s m, vec2s v) - CGLM_INLINE mat3s glms_scale2d_uni(mat3s m, float s) - CGLM_INLINE mat3s glms_rotate2d_make(float angle) - CGLM_INLINE mat3s glms_rotate2d(mat3s m, float angle) - CGLM_INLINE mat3s glms_rotate2d_to(mat3s m, float angle) - */ - -#ifndef cglms_affine2ds_h -#define cglms_affine2ds_h - -#include "../common.h" -#include "../types-struct.h" -#include "../affine2d.h" -#include "vec3.h" -#include "mat3.h" - -/*! - * @brief translate existing 2d transform matrix by v vector - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] v translate vector [x, y] - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_translate2d(mat3s m, vec2s v) { - glm_translate2d(m.raw, v.raw); - return m; -} - -/*! - * @brief translate existing 2d transform matrix by x factor - * - * @param[in] m affine transform - * @param[in] x x factor - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_translate2d_x(mat3s m, float x) { - glm_translate2d_x(m.raw, x); - return m; -} - -/*! - * @brief translate existing 2d transform matrix by y factor - * - * @param[in] m affine transform - * @param[in] y y factor - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_translate2d_y(mat3s m, float y) { - glm_translate2d_y(m.raw, y); - return m; -} - -/*! - * @brief creates NEW translate 2d transform matrix by v vector - * - * @param[in] v translate vector [x, y] - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_translate2d_make(vec2s v) { - mat3s m; - glm_translate2d_make(m.raw, v.raw); - return m; -} - -/*! - * @brief creates NEW 2d scale matrix by v vector - * - * @param[in] v scale vector [x, y] - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_scale2d_make(vec2s v) { - mat3s m; - glm_scale2d_make(m.raw, v.raw); - return m; -} - -/*! - * @brief scales existing 2d transform matrix by v vector - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] v scale vector [x, y, z] - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_scale2d(mat3s m, vec2s v) { - mat3s r; - glm_scale2d_to(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief applies uniform scale to existing 2d transform matrix v = [s, s, s] - * and stores result in same matrix - * - * @param[in] m affine transform - * @param[in] s scale factor - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_scale2d_uni(mat3s m, float s) { - glm_scale2d_uni(m.raw, s); - return m; -} - -/*! - * @brief creates NEW 2d rotation matrix by angle and axis - * - * axis will be normalized so you don't need to normalize it - * - * @param[in] angle angle (radians) - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_rotate2d_make(float angle) { - mat3s m; - glm_rotate2d_make(m.raw, angle); - return m; -} - -/*! - * @brief rotate existing 2d transform matrix around given axis by angle - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_rotate2d(mat3s m, float angle) { - glm_rotate2d(m.raw, angle); - return m; -} - -/*! - * @brief rotate existing 2d transform matrix around given axis by angle - * - * @param[in] m affine transform - * @param[in] angle angle (radians) - * @returns affine transform - */ -CGLM_INLINE -mat3s -glms_rotate2d_to(mat3s m, float angle) { - glm_rotate2d(m.raw, angle); - return m; -} - -#endif /* cglms_affine2ds_h */ diff --git a/external/cglm/struct/box.h b/external/cglm/struct/box.h deleted file mode 100644 index ac32328..0000000 --- a/external/cglm/struct/box.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_boxs_h -#define cglms_boxs_h - -#include "../common.h" -#include "../types-struct.h" -#include "../box.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -/* api definition */ -#define glms_aabb_(NAME) CGLM_STRUCTAPI(aabb, NAME) - -/*! - * @brief apply transform to Axis-Aligned Bounding Box - * - * @param[in] box bounding box - * @param[in] m transform matrix - * @param[out] dest transformed bounding box - */ -CGLM_INLINE -void -glms_aabb_(transform)(vec3s box[2], mat4s m, vec3s dest[2]) { - vec3 rawBox[2]; - vec3 rawDest[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_aabb_transform(rawBox, m.raw, rawDest); - glms_vec3_(pack)(dest, rawDest, 2); -} - -/*! - * @brief merges two AABB bounding box and creates new one - * - * two box must be in same space, if one of box is in different space then - * you should consider to convert it's space by glm_box_space - * - * @param[in] box1 bounding box 1 - * @param[in] box2 bounding box 2 - * @param[out] dest merged bounding box - */ -CGLM_INLINE -void -glms_aabb_(merge)(vec3s box1[2], vec3s box2[2], vec3s dest[2]) { - vec3 rawBox1[2]; - vec3 rawBox2[2]; - vec3 rawDest[2]; - - glms_vec3_(unpack)(rawBox1, box1, 2); - glms_vec3_(unpack)(rawBox2, box2, 2); - glm_aabb_merge(rawBox1, rawBox2, rawDest); - glms_vec3_(pack)(dest, rawDest, 2); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] box bounding box 1 - * @param[in] cropBox crop box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glms_aabb_(crop)(vec3s box[2], vec3s cropBox[2], vec3s dest[2]) { - vec3 rawBox[2]; - vec3 rawCropBox[2]; - vec3 rawDest[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glms_vec3_(unpack)(rawCropBox, cropBox, 2); - glm_aabb_crop(rawBox, rawCropBox, rawDest); - glms_vec3_(pack)(dest, rawDest, 2); -} - -/*! - * @brief crops a bounding box with another one. - * - * this could be useful for getting a bbox which fits with view frustum and - * object bounding boxes. In this case you crop view frustum box with objects - * box - * - * @param[in] box bounding box - * @param[in] cropBox crop box - * @param[in] clampBox minimum box - * @param[out] dest cropped bounding box - */ -CGLM_INLINE -void -glms_aabb_(crop_until)(vec3s box[2], - vec3s cropBox[2], - vec3s clampBox[2], - vec3s dest[2]) { - glms_aabb_(crop)(box, cropBox, dest); - glms_aabb_(merge)(clampBox, dest, dest); -} - -/*! - * @brief check if AABB intersects with frustum planes - * - * this could be useful for frustum culling using AABB. - * - * OPTIMIZATION HINT: - * if planes order is similar to LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR - * then this method should run even faster because it would only use two - * planes if object is not inside the two planes - * fortunately cglm extracts planes as this order! just pass what you got! - * - * @param[in] box bounding box - * @param[in] planes frustum planes - */ -CGLM_INLINE -bool -glms_aabb_(frustum)(vec3s box[2], vec4s planes[6]) { - vec3 rawBox[2]; - vec4 rawPlanes[6]; - - glms_vec3_(unpack)(rawBox, box, 2); - glms_vec4_(unpack)(rawPlanes, planes, 6); - return glm_aabb_frustum(rawBox, rawPlanes); -} - -/*! - * @brief invalidate AABB min and max values - * - * @param[in, out] box bounding box - */ -CGLM_INLINE -void -glms_aabb_(invalidate)(vec3s box[2]) { - box[0] = glms_vec3_(broadcast)(FLT_MAX); - box[1] = glms_vec3_(broadcast)(-FLT_MAX); -} - -/*! - * @brief check if AABB is valid or not - * - * @param[in] box bounding box - */ -CGLM_INLINE -bool -glms_aabb_(isvalid)(vec3s box[2]) { - vec3 rawBox[2]; - glms_vec3_(unpack)(rawBox, box, 2); - return glm_aabb_isvalid(rawBox); -} - -/*! - * @brief distance between of min and max - * - * @param[in] box bounding box - */ -CGLM_INLINE -float -glms_aabb_(size)(vec3s box[2]) { - return glm_vec3_distance(box[0].raw, box[1].raw); -} - -/*! - * @brief radius of sphere which surrounds AABB - * - * @param[in] box bounding box - */ -CGLM_INLINE -float -glms_aabb_(radius)(vec3s box[2]) { - return glms_aabb_(size)(box) * 0.5f; -} - -/*! - * @brief computes center point of AABB - * - * @param[in] box bounding box - * @returns center of bounding box - */ -CGLM_INLINE -vec3s -glms_aabb_(center)(vec3s box[2]) { - return glms_vec3_(center)(box[0], box[1]); -} - -/*! - * @brief check if two AABB intersects - * - * @param[in] box bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glms_aabb_(aabb)(vec3s box[2], vec3s other[2]) { - vec3 rawBox[2]; - vec3 rawOther[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glms_vec3_(unpack)(rawOther, other, 2); - return glm_aabb_aabb(rawBox, rawOther); -} - -/*! - * @brief check if AABB intersects with sphere - * - * https://github.com/erich666/GraphicsGems/blob/master/gems/BoxSphere.c - * Solid Box - Solid Sphere test. - * - * @param[in] box solid bounding box - * @param[in] s solid sphere - */ -CGLM_INLINE -bool -glms_aabb_(sphere)(vec3s box[2], vec4s s) { - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - return glm_aabb_sphere(rawBox, s.raw); -} - -/*! - * @brief check if point is inside of AABB - * - * @param[in] box bounding box - * @param[in] point point - */ -CGLM_INLINE -bool -glms_aabb_(point)(vec3s box[2], vec3s point) { - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - return glm_aabb_point(rawBox, point.raw); -} - -/*! - * @brief check if AABB contains other AABB - * - * @param[in] box bounding box - * @param[in] other other bounding box - */ -CGLM_INLINE -bool -glms_aabb_(contains)(vec3s box[2], vec3s other[2]) { - vec3 rawBox[2]; - vec3 rawOther[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glms_vec3_(unpack)(rawOther, other, 2); - return glm_aabb_contains(rawBox, rawOther); -} - -#endif /* cglms_boxs_h */ diff --git a/external/cglm/struct/cam.h b/external/cglm/struct/cam.h deleted file mode 100644 index ab6cbbb..0000000 --- a/external/cglm/struct/cam.h +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_frustum(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho_aabb(vec3s box[2]); - CGLM_INLINE mat4s glms_ortho_aabb_p(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_aabb_pz(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_default(float aspect) - CGLM_INLINE mat4s glms_ortho_default_s(float aspect, float size) - CGLM_INLINE mat4s glms_perspective(float fovy, - float aspect, - float nearZ, - float farZ) - CGLM_INLINE void glms_persp_move_far(mat4s proj, float deltaFar) - CGLM_INLINE mat4s glms_perspective_default(float aspect) - CGLM_INLINE void glms_perspective_resize(mat4s proj, float aspect) - CGLM_INLINE mat4s glms_lookat(vec3s eye, vec3s center, vec3s up) - CGLM_INLINE mat4s glms_look(vec3s eye, vec3s dir, vec3s up) - CGLM_INLINE mat4s glms_look_anyup(vec3s eye, vec3s dir) - CGLM_INLINE void glms_persp_decomp(mat4s proj, - float *nearv, float *farv, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glms_persp_decompv(mat4s proj, float dest[6]) - CGLM_INLINE void glms_persp_decomp_x(mat4s proj, float *left, float *right) - CGLM_INLINE void glms_persp_decomp_y(mat4s proj, float *top, float *bottom) - CGLM_INLINE void glms_persp_decomp_z(mat4s proj, float *nearv, float *farv) - CGLM_INLINE void glms_persp_decomp_far(mat4s proj, float *farZ) - CGLM_INLINE void glms_persp_decomp_near(mat4s proj, float *nearZ) - CGLM_INLINE float glms_persp_fovy(mat4s proj) - CGLM_INLINE float glms_persp_aspect(mat4s proj) - CGLM_INLINE vec4s glms_persp_sizes(mat4s proj, float fovy) - */ - -#ifndef cglms_cam_h -#define cglms_cam_h - -#include "../common.h" -#include "../types-struct.h" -#include "../plane.h" -#include "../cam.h" - -#ifndef CGLM_CLIPSPACE_INCLUDE_ALL -# if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/view_lh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/view_lh_no.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/view_rh_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_rh_no.h" -# endif -#else -# include "clipspace/ortho_lh_zo.h" -# include "clipspace/persp_lh_zo.h" -# include "clipspace/ortho_lh_no.h" -# include "clipspace/persp_lh_no.h" -# include "clipspace/ortho_rh_zo.h" -# include "clipspace/persp_rh_zo.h" -# include "clipspace/ortho_rh_no.h" -# include "clipspace/persp_rh_no.h" -# include "clipspace/view_lh_zo.h" -# include "clipspace/view_lh_no.h" -# include "clipspace/view_rh_zo.h" -# include "clipspace/view_rh_no.h" -#endif - -/*! - * @brief set up perspective peprojection matrix - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_frustum(float left, float right, - float bottom, float top, - float nearZ, float farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_frustum_lh_zo(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_frustum_lh_no(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_frustum_rh_zo(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_frustum_rh_no(left, right, bottom, top, nearZ, farZ); -#endif -} - -/*! - * @brief set up orthographic projection matrix - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho(float left, float right, - float bottom, float top, - float nearZ, float farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_lh_zo(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_lh_no(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_rh_zo(left, right, bottom, top, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_rh_no(left, right, bottom, top, nearZ, farZ); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb(vec3s box[2]) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_aabb_lh_zo(box); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_aabb_lh_no(box); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_aabb_rh_zo(box); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_aabb_rh_no(box); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_p(vec3s box[2], float padding) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_aabb_p_lh_zo(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_aabb_p_lh_no(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_aabb_p_rh_zo(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_aabb_p_rh_no(box, padding); -#endif -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_pz(vec3s box[2], float padding) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_aabb_pz_lh_zo(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_aabb_pz_lh_no(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_aabb_pz_rh_zo(box, padding); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_aabb_pz_rh_no(box, padding); -#endif -} - -/*! - * @brief set up unit orthographic projection matrix - * - * @param[in] aspect aspect ration ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default(float aspect) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_default_lh_zo(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_default_lh_no(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_default_rh_zo(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_default_rh_no(aspect); -#endif -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_s(float aspect, float size) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_ortho_default_s_lh_zo(aspect, size); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_ortho_default_s_lh_no(aspect, size); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_ortho_default_s_rh_zo(aspect, size); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_ortho_default_s_rh_no(aspect, size); -#endif -} - -/*! - * @brief set up perspective projection matrix - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective(float fovy, float aspect, float nearZ, float farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_perspective_lh_zo(fovy, aspect, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_perspective_lh_no(fovy, aspect, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_perspective_rh_zo(fovy, aspect, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_perspective_rh_no(fovy, aspect, nearZ, farZ); -#endif -} - -/*! - * @brief extend perspective projection matrix's far distance - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glm_persp_move_far(prooj.raw, deltaFar) to avoid create new mat4 - * each time - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -mat4s -glms_persp_move_far(mat4s proj, float deltaFar) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_persp_move_far_lh_zo(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_persp_move_far_lh_no(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_persp_move_far_rh_zo(proj, deltaFar); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_persp_move_far_rh_no(proj, deltaFar); -#endif -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values - * - * @param[in] aspect aspect ratio ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_default(float aspect) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_perspective_default_lh_zo(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_perspective_default_lh_no(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_perspective_default_rh_zo(aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_perspective_default_rh_no(aspect); -#endif -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_perspective_resize(proj.raw, aspect) to avoid create new mat4 - * each time - * - * @param[in, out] proj perspective projection matrix - * @param[in] aspect aspect ratio ( width / height ) - */ -CGLM_INLINE -mat4s -glms_perspective_resize(mat4s proj, float aspect) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_perspective_resize_lh_zo(proj, aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_perspective_resize_lh_no(proj, aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_perspective_resize_rh_zo(proj, aspect); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_perspective_resize_rh_no(proj, aspect); -#endif -} - -/*! - * @brief set up view matrix - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_lookat(vec3s eye, vec3s center, vec3s up) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_lookat_lh_zo(eye, center, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_lookat_lh_no(eye, center, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_lookat_rh_zo(eye, center, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_lookat_rh_no(eye, center, up); -#endif -} - -/*! - * @brief set up view matrix - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look(vec3s eye, vec3s dir, vec3s up) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_look_lh_zo(eye, dir, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_look_lh_no(eye, dir, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_look_rh_zo(eye, dir, up); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_look_rh_no(eye, dir, up); -#endif -} - -/*! - * @brief set up view matrix - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_anyup(vec3s eye, vec3s dir) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_look_anyup_lh_zo(eye, dir); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_look_anyup_lh_no(eye, dir); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_look_anyup_rh_zo(eye, dir); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_look_anyup_rh_no(eye, dir); -#endif -} - -/*! - * @brief decomposes frustum values of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp(mat4s proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_lh_zo(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_lh_no(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_rh_zo(proj, nearZ, farZ, top, bottom, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_rh_no(proj, nearZ, farZ, top, bottom, left, right); -#endif -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glms_persp_decompv(mat4s proj, float dest[6]) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decompv_lh_zo(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decompv_lh_no(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decompv_rh_zo(proj, dest); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decompv_rh_no(proj, dest); -#endif -} - -/*! - * @brief decomposes left and right values of perspective projection. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_x(mat4s proj, - float * __restrict left, - float * __restrict right) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_x_lh_zo(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_x_lh_no(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_x_rh_zo(proj, left, right); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_x_rh_no(proj, left, right); -#endif -} - -/*! - * @brief decomposes top and bottom values of perspective projection. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glms_persp_decomp_y(mat4s proj, - float * __restrict top, - float * __restrict bottom) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_y_lh_zo(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_y_lh_no(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_y_rh_zo(proj, top, bottom); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_y_rh_no(proj, top, bottom); -#endif -} - -/*! - * @brief decomposes near and far values of perspective projection. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_z(mat4s proj, - float * __restrict nearZ, - float * __restrict farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_z_lh_zo(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_z_lh_no(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_z_rh_zo(proj, nearZ, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_z_rh_no(proj, nearZ, farZ); -#endif -} - -/*! - * @brief decomposes far value of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_far(mat4s proj, float * __restrict farZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_far_lh_zo(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_far_lh_no(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_far_rh_zo(proj, farZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_far_rh_no(proj, farZ); -#endif -} - -/*! - * @brief decomposes near value of perspective projection. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glms_persp_decomp_near(mat4s proj, float * __restrict nearZ) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - glms_persp_decomp_near_lh_zo(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - glms_persp_decomp_near_lh_no(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - glms_persp_decomp_near_rh_zo(proj, nearZ); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - glms_persp_decomp_near_rh_no(proj, nearZ); -#endif -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_fovy(mat4s proj) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_persp_fovy_lh_zo(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_persp_fovy_lh_no(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_persp_fovy_rh_zo(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_persp_fovy_rh_no(proj); -#endif -} - -/*! - * @brief returns aspect ratio of perspective projection - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_aspect(mat4s proj) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_persp_aspect_lh_zo(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_persp_aspect_lh_no(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_persp_aspect_rh_zo(proj); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_persp_aspect_rh_no(proj); -#endif -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -vec4s -glms_persp_sizes(mat4s proj, float fovy) { -#if CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_ZO - return glms_persp_sizes_lh_zo(proj, fovy); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_LH_NO - return glms_persp_sizes_lh_no(proj, fovy); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_ZO - return glms_persp_sizes_rh_zo(proj, fovy); -#elif CGLM_CONFIG_CLIP_CONTROL == CGLM_CLIP_CONTROL_RH_NO - return glms_persp_sizes_rh_no(proj, fovy); -#endif -} - -#endif /* cglms_cam_h */ diff --git a/external/cglm/struct/clipspace/ortho_lh_no.h b/external/cglm/struct/clipspace/ortho_lh_no.h deleted file mode 100644 index a743fdf..0000000 --- a/external/cglm/struct/clipspace/ortho_lh_no.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_ortho_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho_aabb_lh_no(vec3s box[2]); - CGLM_INLINE mat4s glms_ortho_aabb_p_lh_no(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_default_lh_no(float aspect) - CGLM_INLINE mat4s glms_ortho_default_s_lh_no(float aspect, float size) - */ - -#ifndef cglms_ortho_lh_no_h -#define cglms_ortho_lh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../vec3.h" -#include "../../clipspace/ortho_lh_no.h" - -/*! - * @brief set up orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_ortho_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_lh_no(vec3s box[2]) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_lh_no(rawBox, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_p_lh_no(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_p_lh_no(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_pz_lh_no(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_pz_lh_no(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up unit orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_lh_no(float aspect) { - mat4s dest; - glm_ortho_default_lh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_s_lh_no(float aspect, float size) { - mat4s dest; - glm_ortho_default_s_lh_no(aspect, size, dest.raw); - return dest; -} - -#endif /* cglms_ortho_lh_no_h */ diff --git a/external/cglm/struct/clipspace/ortho_lh_zo.h b/external/cglm/struct/clipspace/ortho_lh_zo.h deleted file mode 100644 index 4f15656..0000000 --- a/external/cglm/struct/clipspace/ortho_lh_zo.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_ortho_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho_aabb_lh_zo(vec3s box[2]); - CGLM_INLINE mat4s glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_default_lh_zo(float aspect) - CGLM_INLINE mat4s glms_ortho_default_s_lh_zo(float aspect, float size) - */ - -#ifndef cglms_ortho_lh_zo_h -#define cglms_ortho_lh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../vec3.h" -#include "../../clipspace/ortho_lh_zo.h" - -/*! - * @brief set up orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_ortho_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_lh_zo(vec3s box[2]) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_lh_zo(rawBox, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_p_lh_zo(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_p_lh_zo(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_pz_lh_zo(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_pz_lh_zo(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up unit orthographic projection matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_lh_zo(float aspect) { - mat4s dest; - glm_ortho_default_lh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_s_lh_zo(float aspect, float size) { - mat4s dest; - glm_ortho_default_s_lh_zo(aspect, size, dest.raw); - return dest; -} - -#endif /* cglms_ortho_lh_zo_h */ diff --git a/external/cglm/struct/clipspace/ortho_rh_no.h b/external/cglm/struct/clipspace/ortho_rh_no.h deleted file mode 100644 index ecb4d32..0000000 --- a/external/cglm/struct/clipspace/ortho_rh_no.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_ortho_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho_aabb_rh_no(vec3s box[2]); - CGLM_INLINE mat4s glms_ortho_aabb_p_rh_no(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_default_rh_no(float aspect) - CGLM_INLINE mat4s glms_ortho_default_s_rh_no(float aspect, float size) - */ - -#ifndef cglms_ortho_rh_no_h -#define cglms_ortho_rh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../vec3.h" -#include "../../clipspace/ortho_rh_no.h" - -/*! - * @brief set up orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_ortho_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_rh_no(vec3s box[2]) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_rh_no(rawBox, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_p_rh_no(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_p_rh_no(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_pz_rh_no(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_pz_rh_no(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up unit orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_rh_no(float aspect) { - mat4s dest; - glm_ortho_default_rh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_s_rh_no(float aspect, float size) { - mat4s dest; - glm_ortho_default_s_rh_no(aspect, size, dest.raw); - return dest; -} - -#endif /* cglms_ortho_rh_no_h */ diff --git a/external/cglm/struct/clipspace/ortho_rh_zo.h b/external/cglm/struct/clipspace/ortho_rh_zo.h deleted file mode 100644 index 2d50ee1..0000000 --- a/external/cglm/struct/clipspace/ortho_rh_zo.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_ortho_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_ortho_aabb_rh_zo(vec3s box[2]); - CGLM_INLINE mat4s glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding); - CGLM_INLINE mat4s glms_ortho_default_rh_zo(float aspect) - CGLM_INLINE mat4s glms_ortho_default_s_rh_zo(float aspect, float size) - */ - -#ifndef cglms_ortho_rh_zo_h -#define cglms_ortho_rh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../vec3.h" -#include "../../clipspace/ortho_rh_zo.h" - -/*! - * @brief set up orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_ortho_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_rh_zo(vec3s box[2]) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_rh_zo(rawBox, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_p_rh_zo(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_p_rh_zo(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up orthographic projection matrix using bounding box - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * bounding box (AABB) must be in view space - * - * @param[in] box AABB - * @param[in] padding padding for near and far - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_aabb_pz_rh_zo(vec3s box[2], float padding) { - mat4s dest; - vec3 rawBox[2]; - - glms_vec3_(unpack)(rawBox, box, 2); - glm_ortho_aabb_pz_rh_zo(rawBox, padding, dest.raw); - - return dest; -} - -/*! - * @brief set up unit orthographic projection matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ration ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_rh_zo(float aspect) { - mat4s dest; - glm_ortho_default_rh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief set up orthographic projection matrix with given CUBE size - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] size cube size - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_ortho_default_s_rh_zo(float aspect, float size) { - mat4s dest; - glm_ortho_default_s_rh_zo(aspect, size, dest.raw); - return dest; -} - -#endif /* cglms_ortho_rh_zo_h */ diff --git a/external/cglm/struct/clipspace/persp_lh_no.h b/external/cglm/struct/clipspace/persp_lh_no.h deleted file mode 100644 index bc35ca0..0000000 --- a/external/cglm/struct/clipspace/persp_lh_no.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_frustum_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_perspective_lh_no(float fovy, - float aspect, - float nearZ, - float farZ) - CGLM_INLINE void glms_persp_move_far_lh_no(mat4s proj, float deltaFar) - CGLM_INLINE mat4s glms_perspective_default_lh_no(float aspect) - CGLM_INLINE void glms_perspective_resize_lh_no(mat4s proj, float aspect) - CGLM_INLINE void glms_persp_decomp_lh_no(mat4s proj, - float *nearv, float *farv, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glms_persp_decompv_lh_no(mat4s proj, float dest[6]) - CGLM_INLINE void glms_persp_decomp_x_lh_no(mat4s proj, float *left, float *right) - CGLM_INLINE void glms_persp_decomp_y_lh_no(mat4s proj, float *top, float *bottom) - CGLM_INLINE void glms_persp_decomp_z_lh_no(mat4s proj, float *nearv, float *farv) - CGLM_INLINE void glms_persp_decomp_far_lh_no(mat4s proj, float *farZ) - CGLM_INLINE void glms_persp_decomp_near_lh_no(mat4s proj, float *nearZ) - CGLM_INLINE float glms_persp_fovy_lh_no(mat4s proj) - CGLM_INLINE float glms_persp_aspect_lh_no(mat4s proj) - CGLM_INLINE vec4s glms_persp_sizes_lh_no(mat4s proj, float fovy) - */ - -#ifndef cglms_persp_lh_no_h -#define cglms_persp_lh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/persp_lh_no.h" - -/*! - * @brief set up perspective peprojection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_frustum_lh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_frustum_lh_no(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up perspective projection matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_lh_no(float fovy, float aspect, float nearZ, float farZ) { - mat4s dest; - glm_perspective_lh_no(fovy, aspect, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_persp_move_far_lh_no(prooj.raw, deltaFar) to avoid create new mat4 - * each time - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -mat4s -glms_persp_move_far_lh_no(mat4s proj, float deltaFar) { - mat4s dest; - dest = proj; - glm_persp_move_far_lh_no(dest.raw, deltaFar); - return dest; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_default_lh_no(float aspect) { - mat4s dest; - glm_perspective_default_lh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glm_perspective_resize_lh_no(proj.raw, aspect) to avoid create new mat4 - * each time - * - * @param[in, out] proj perspective projection matrix - * @param[in] aspect aspect ratio ( width / height ) - */ -CGLM_INLINE -mat4s -glms_perspective_resize_lh_no(mat4s proj, float aspect) { - mat4s dest; - dest = proj; - glm_perspective_resize_lh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief decomposes frustum values of perspective projection. - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_lh_no(mat4s proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - glm_persp_decomp_lh_no(proj.raw, nearZ, farZ, top, bottom, left, right); -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glms_persp_decompv_lh_no(mat4s proj, float dest[6]) { - glm_persp_decompv_lh_no(proj.raw, dest); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_x_lh_no(mat4s proj, - float * __restrict left, - float * __restrict right) { - glm_persp_decomp_x_lh_no(proj.raw, left, right); -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glms_persp_decomp_y_lh_no(mat4s proj, - float * __restrict top, - float * __restrict bottom) { - glm_persp_decomp_y_lh_no(proj.raw, top, bottom); -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_z_lh_no(mat4s proj, - float * __restrict nearZ, - float * __restrict farZ) { - glm_persp_decomp_z_lh_no(proj.raw, nearZ, farZ); -} - -/*! - * @brief decomposes far value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_far_lh_no(mat4s proj, float * __restrict farZ) { - glm_persp_decomp_far_lh_no(proj.raw, farZ); -} - -/*! - * @brief decomposes near value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glms_persp_decomp_near_lh_no(mat4s proj, float * __restrict nearZ) { - glm_persp_decomp_near_lh_no(proj.raw, nearZ); -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_fovy_lh_no(mat4s proj) { - return glm_persp_fovy_lh_no(proj.raw); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_aspect_lh_no(mat4s proj) { - return glm_persp_aspect_lh_no(proj.raw); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -vec4s -glms_persp_sizes_lh_no(mat4s proj, float fovy) { - vec4s dest; - glm_persp_sizes_lh_no(proj.raw, fovy, dest.raw); - return dest; -} - -#endif /* cglms_persp_lh_no_h */ diff --git a/external/cglm/struct/clipspace/persp_lh_zo.h b/external/cglm/struct/clipspace/persp_lh_zo.h deleted file mode 100644 index 29af065..0000000 --- a/external/cglm/struct/clipspace/persp_lh_zo.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_frustum_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_perspective_lh_zo(float fovy, - float aspect, - float nearZ, - float farZ) - CGLM_INLINE void glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) - CGLM_INLINE mat4s glms_perspective_default_lh_zo(float aspect) - CGLM_INLINE void glms_perspective_resize_lh_zo(mat4s proj, float aspect) - CGLM_INLINE void glms_persp_decomp_lh_zo(mat4s proj, - float *nearv, float *farv, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) - CGLM_INLINE void glms_persp_decomp_x_lh_zo(mat4s proj, float *left, float *right) - CGLM_INLINE void glms_persp_decomp_y_lh_zo(mat4s proj, float *top, float *bottom) - CGLM_INLINE void glms_persp_decomp_z_lh_zo(mat4s proj, float *nearv, float *farv) - CGLM_INLINE void glms_persp_decomp_far_lh_zo(mat4s proj, float *farZ) - CGLM_INLINE void glms_persp_decomp_near_lh_zo(mat4s proj, float *nearZ) - CGLM_INLINE float glms_persp_fovy_lh_zo(mat4s proj) - CGLM_INLINE float glms_persp_aspect_lh_zo(mat4s proj) - CGLM_INLINE vec4s glms_persp_sizes_lh_zo(mat4s proj, float fovy) - */ - -#ifndef cglms_persp_lh_zo_h -#define cglms_persp_lh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/persp_lh_zo.h" - -/*! - * @brief set up perspective peprojection matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_frustum_lh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_frustum_lh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up perspective projection matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_lh_zo(float fovy, float aspect, float nearZ, float farZ) { - mat4s dest; - glm_perspective_lh_zo(fovy, aspect, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_persp_move_far_lh_zo(prooj.raw, deltaFar) to avoid create new mat4 - * each time - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -mat4s -glms_persp_move_far_lh_zo(mat4s proj, float deltaFar) { - mat4s dest; - dest = proj; - glm_persp_move_far_lh_zo(dest.raw, deltaFar); - return dest; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_default_lh_zo(float aspect) { - mat4s dest; - glm_perspective_default_lh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_perspective_resize_lh_zo(proj.raw, aspect) to avoid create new mat4 - * each time - * - * @param[in, out] proj perspective projection matrix - * @param[in] aspect aspect ratio ( width / height ) - */ -CGLM_INLINE -mat4s -glms_perspective_resize_lh_zo(mat4s proj, float aspect) { - mat4s dest; - dest = proj; - glm_perspective_resize_lh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief decomposes frustum values of perspective projection. - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_lh_zo(mat4s proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - glm_persp_decomp_lh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glms_persp_decompv_lh_zo(mat4s proj, float dest[6]) { - glm_persp_decompv_lh_zo(proj.raw, dest); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_x_lh_zo(mat4s proj, - float * __restrict left, - float * __restrict right) { - glm_persp_decomp_x_lh_zo(proj.raw, left, right); -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glms_persp_decomp_y_lh_zo(mat4s proj, - float * __restrict top, - float * __restrict bottom) { - glm_persp_decomp_y_lh_zo(proj.raw, top, bottom); -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_z_lh_zo(mat4s proj, - float * __restrict nearZ, - float * __restrict farZ) { - glm_persp_decomp_z_lh_zo(proj.raw, nearZ, farZ); -} - -/*! - * @brief decomposes far value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_far_lh_zo(mat4s proj, float * __restrict farZ) { - glm_persp_decomp_far_lh_zo(proj.raw, farZ); -} - -/*! - * @brief decomposes near value of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glms_persp_decomp_near_lh_zo(mat4s proj, float * __restrict nearZ) { - glm_persp_decomp_near_lh_zo(proj.raw, nearZ); -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_fovy_lh_zo(mat4s proj) { - return glm_persp_fovy_lh_zo(proj.raw); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_aspect_lh_zo(mat4s proj) { - return glm_persp_aspect_lh_zo(proj.raw); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -vec4s -glms_persp_sizes_lh_zo(mat4s proj, float fovy) { - vec4s dest; - glm_persp_sizes_lh_zo(proj.raw, fovy, dest.raw); - return dest; -} - -#endif /* cglms_persp_lh_zo_h */ diff --git a/external/cglm/struct/clipspace/persp_rh_no.h b/external/cglm/struct/clipspace/persp_rh_no.h deleted file mode 100644 index 7120fdf..0000000 --- a/external/cglm/struct/clipspace/persp_rh_no.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_frustum_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_perspective_rh_no(float fovy, - float aspect, - float nearZ, - float farZ) - CGLM_INLINE void glms_persp_move_far_rh_no(mat4s proj, float deltaFar) - CGLM_INLINE mat4s glms_perspective_default_rh_no(float aspect) - CGLM_INLINE void glms_perspective_resize_rh_no(mat4s proj, float aspect) - CGLM_INLINE void glms_persp_decomp_rh_no(mat4s proj, - float *nearv, float *farv, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glms_persp_decompv_rh_no(mat4s proj, float dest[6]) - CGLM_INLINE void glms_persp_decomp_x_rh_no(mat4s proj, float *left, float *right) - CGLM_INLINE void glms_persp_decomp_y_rh_no(mat4s proj, float *top, float *bottom) - CGLM_INLINE void glms_persp_decomp_z_rh_no(mat4s proj, float *nearv, float *farv) - CGLM_INLINE void glms_persp_decomp_far_rh_no(mat4s proj, float *farZ) - CGLM_INLINE void glms_persp_decomp_near_rh_no(mat4s proj, float *nearZ) - CGLM_INLINE float glms_persp_fovy_rh_no(mat4s proj) - CGLM_INLINE float glms_persp_aspect_rh_no(mat4s proj) - CGLM_INLINE vec4s glms_persp_sizes_rh_no(mat4s proj, float fovy) - */ - -#ifndef cglms_persp_rh_no_h -#define cglms_persp_rh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/persp_rh_no.h" - -/*! - * @brief set up perspective peprojection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_frustum_rh_no(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_frustum_rh_no(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up perspective projection matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_rh_no(float fovy, float aspect, float nearZ, float farZ) { - mat4s dest; - glm_perspective_rh_no(fovy, aspect, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_persp_move_far_rh_no(prooj.raw, deltaFar) to avoid create new mat4 - * each time - * s - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -mat4s -glms_persp_move_far_rh_no(mat4s proj, float deltaFar) { - mat4s dest; - dest = proj; - glm_persp_move_far_rh_no(dest.raw, deltaFar); - return dest; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_default_rh_no(float aspect) { - mat4s dest; - glm_perspective_default_rh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glm_perspective_resize_rh_no(proj.raw, aspect) to avoid create new mat4 - * each time - * - * @param[in, out] proj perspective projection matrix - * @param[in] aspect aspect ratio ( width / height ) - */ -CGLM_INLINE -mat4s -glms_perspective_resize_rh_no(mat4s proj, float aspect) { - mat4s dest; - dest = proj; - glm_perspective_resize_rh_no(aspect, dest.raw); - return dest; -} - -/*! - * @brief decomposes frustum values of perspective projection. - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_rh_no(mat4s proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - glm_persp_decomp_rh_no(proj.raw, nearZ, farZ, top, bottom, left, right); -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glms_persp_decompv_rh_no(mat4s proj, float dest[6]) { - glm_persp_decompv_rh_no(proj.raw, dest); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_x_rh_no(mat4s proj, - float * __restrict left, - float * __restrict right) { - glm_persp_decomp_x_rh_no(proj.raw, left, right); -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glms_persp_decomp_y_rh_no(mat4s proj, - float * __restrict top, - float * __restrict bottom) { - glm_persp_decomp_y_rh_no(proj.raw, top, bottom); -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_z_rh_no(mat4s proj, - float * __restrict nearZ, - float * __restrict farZ) { - glm_persp_decomp_z_rh_no(proj.raw, nearZ, farZ); -} - -/*! - * @brief decomposes far value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_far_rh_no(mat4s proj, float * __restrict farZ) { - glm_persp_decomp_far_rh_no(proj.raw, farZ); -} - -/*! - * @brief decomposes near value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glms_persp_decomp_near_rh_no(mat4s proj, float * __restrict nearZ) { - glm_persp_decomp_near_rh_no(proj.raw, nearZ); -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_fovy_rh_no(mat4s proj) { - return glm_persp_fovy_rh_no(proj.raw); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_aspect_rh_no(mat4s proj) { - return glm_persp_aspect_rh_no(proj.raw); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -vec4s -glms_persp_sizes_rh_no(mat4s proj, float fovy) { - vec4s dest; - glm_persp_sizes_rh_no(proj.raw, fovy, dest.raw); - return dest; -} - -#endif /* cglms_persp_rh_no_h */ diff --git a/external/cglm/struct/clipspace/persp_rh_zo.h b/external/cglm/struct/clipspace/persp_rh_zo.h deleted file mode 100644 index e3585a2..0000000 --- a/external/cglm/struct/clipspace/persp_rh_zo.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_frustum_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) - CGLM_INLINE mat4s glms_perspective_rh_zo(float fovy, - float aspect, - float nearZ, - float farZ) - CGLM_INLINE void glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) - CGLM_INLINE mat4s glms_perspective_default_rh_zo(float aspect) - CGLM_INLINE void glms_perspective_resize_rh_zo(mat4s proj, float aspect) - CGLM_INLINE void glms_persp_decomp_rh_zo(mat4s proj, - float *nearv, float *farv, - float *top, float *bottom, - float *left, float *right) - CGLM_INLINE void glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) - CGLM_INLINE void glms_persp_decomp_x_rh_zo(mat4s proj, float *left, float *right) - CGLM_INLINE void glms_persp_decomp_y_rh_zo(mat4s proj, float *top, float *bottom) - CGLM_INLINE void glms_persp_decomp_z_rh_zo(mat4s proj, float *nearv, float *farv) - CGLM_INLINE void glms_persp_decomp_far_rh_zo(mat4s proj, float *farZ) - CGLM_INLINE void glms_persp_decomp_near_rh_zo(mat4s proj, float *nearZ) - CGLM_INLINE float glms_persp_fovy_rh_zo(mat4s proj) - CGLM_INLINE float glms_persp_aspect_rh_zo(mat4s proj) - CGLM_INLINE vec4s glms_persp_sizes_rh_zo(mat4s proj, float fovy) - */ - -#ifndef cglms_persp_rh_zo_h -#define cglms_persp_rh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/persp_rh_zo.h" - -/*! - * @brief set up perspective peprojection matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] left viewport.left - * @param[in] right viewport.right - * @param[in] bottom viewport.bottom - * @param[in] top viewport.top - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping plane - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_frustum_rh_zo(float left, float right, - float bottom, float top, - float nearZ, float farZ) { - mat4s dest; - glm_frustum_rh_zo(left, right, bottom, top, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief set up perspective projection matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] fovy field of view angle - * @param[in] aspect aspect ratio ( width / height ) - * @param[in] nearZ near clipping plane - * @param[in] farZ far clipping planes - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_rh_zo(float fovy, float aspect, float nearZ, float farZ) { - mat4s dest; - glm_perspective_rh_zo(fovy, aspect, nearZ, farZ, dest.raw); - return dest; -} - -/*! - * @brief extend perspective projection matrix's far distance - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glms_persp_move_far_rh_zo(prooj.raw, deltaFar) to avoid create new mat4 - * each time - * - * this function does not guarantee far >= near, be aware of that! - * - * @param[in, out] proj projection matrix to extend - * @param[in] deltaFar distance from existing far (negative to shink) - */ -CGLM_INLINE -mat4s -glms_persp_move_far_rh_zo(mat4s proj, float deltaFar) { - mat4s dest; - dest = proj; - glm_persp_move_far_rh_zo(dest.raw, deltaFar); - return dest; -} - -/*! - * @brief set up perspective projection matrix with default near/far - * and angle values with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] aspect aspect ratio ( width / height ) - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_perspective_default_rh_zo(float aspect) { - mat4s dest; - glm_perspective_default_rh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief resize perspective matrix by aspect ratio ( width / height ) - * this makes very easy to resize proj matrix when window /viewport - * reized with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: if you dodn't want to create new matrix then use array api on struct.raw - * like glm_perspective_resize_rh_zo(proj.raw, aspect) to avoid create new mat4 - * each time - * - * @param[in, out] proj perspective projection matrix - * @param[in] aspect aspect ratio ( width / height ) - */ -CGLM_INLINE -mat4s -glms_perspective_resize_rh_zo(mat4s proj, float aspect) { - mat4s dest; - dest = proj; - glm_perspective_resize_rh_zo(aspect, dest.raw); - return dest; -} - -/*! - * @brief decomposes frustum values of perspective projection. - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - * @param[out] top top - * @param[out] bottom bottom - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_rh_zo(mat4s proj, - float * __restrict nearZ, float * __restrict farZ, - float * __restrict top, float * __restrict bottom, - float * __restrict left, float * __restrict right) { - glm_persp_decomp_rh_zo(proj.raw, nearZ, farZ, top, bottom, left, right); -} - -/*! - * @brief decomposes frustum values of perspective projection. - * this makes easy to get all values at once - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] dest array - */ -CGLM_INLINE -void -glms_persp_decompv_rh_zo(mat4s proj, float dest[6]) { - glm_persp_decompv_rh_zo(proj.raw, dest); -} - -/*! - * @brief decomposes left and right values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * x stands for x axis (left / right axis) - * - * @param[in] proj perspective projection matrix - * @param[out] left left - * @param[out] right right - */ -CGLM_INLINE -void -glms_persp_decomp_x_rh_zo(mat4s proj, - float * __restrict left, - float * __restrict right) { - glm_persp_decomp_x_rh_zo(proj.raw, left, right); -} - -/*! - * @brief decomposes top and bottom values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * y stands for y axis (top / bottom axis) - * - * @param[in] proj perspective projection matrix - * @param[out] top top - * @param[out] bottom bottom - */ -CGLM_INLINE -void -glms_persp_decomp_y_rh_zo(mat4s proj, - float * __restrict top, - float * __restrict bottom) { - glm_persp_decomp_y_rh_zo(proj.raw, top, bottom); -} - -/*! - * @brief decomposes near and far values of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * z stands for z axis (near / far axis) - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_z_rh_zo(mat4s proj, - float * __restrict nearZ, - float * __restrict farZ) { - glm_persp_decomp_z_rh_zo(proj.raw, nearZ, farZ); -} - -/*! - * @brief decomposes far value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] farZ far - */ -CGLM_INLINE -void -glms_persp_decomp_far_rh_zo(mat4s proj, float * __restrict farZ) { - glm_persp_decomp_far_rh_zo(proj.raw, farZ); -} - -/*! - * @brief decomposes near value of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[out] nearZ near - */ -CGLM_INLINE -void -glms_persp_decomp_near_rh_zo(mat4s proj, float * __restrict nearZ) { - glm_persp_decomp_near_rh_zo(proj.raw, nearZ); -} - -/*! - * @brief returns field of view angle along the Y-axis (in radians) - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * if you need to degrees, use glm_deg to convert it or use this: - * fovy_deg = glm_deg(glm_persp_fovy(projMatrix)) - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_fovy_rh_zo(mat4s proj) { - return glm_persp_fovy_rh_zo(proj.raw); -} - -/*! - * @brief returns aspect ratio of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - */ -CGLM_INLINE -float -glms_persp_aspect_rh_zo(mat4s proj) { - return glm_persp_aspect_rh_zo(proj.raw); -} - -/*! - * @brief returns sizes of near and far planes of perspective projection - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * @param[in] proj perspective projection matrix - * @param[in] fovy fovy (see brief) - * @returns sizes as vector, sizes order: [Wnear, Hnear, Wfar, Hfar] - */ -CGLM_INLINE -vec4s -glms_persp_sizes_rh_zo(mat4s proj, float fovy) { - vec4s dest; - glm_persp_sizes_rh_zo(proj.raw, fovy, dest.raw); - return dest; -} - -#endif /* cglms_persp_rh_zo_h */ diff --git a/external/cglm/struct/clipspace/project_no.h b/external/cglm/struct/clipspace/project_no.h deleted file mode 100644 index 1a28d47..0000000 --- a/external/cglm/struct/clipspace/project_no.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) - CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp) - CGLM_INLINE float glms_project_z_no(vec3s v, mat4s m) - */ - -#ifndef cglms_project_no_h -#define cglms_project_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/project_no.h" - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * - * @returns unprojected coordinates - */ -CGLM_INLINE -vec3s -glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) { - vec3s dest; - glm_unprojecti_no(pos.raw, invMat.raw, vp.raw, dest.raw); - return dest; -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * - * @returns projected coordinates - */ -CGLM_INLINE -vec3s -glms_project_no(vec3s pos, mat4s m, vec4s vp) { - vec3s dest; - glm_project_no(pos.raw, m.raw, vp.raw, dest.raw); - return dest; -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glms_project_z_no(vec3s v, mat4s m) { - return glm_project_z_no(v.raw, m.raw); -} - -#endif /* cglms_project_rh_no_h */ diff --git a/external/cglm/struct/clipspace/project_zo.h b/external/cglm/struct/clipspace/project_zo.h deleted file mode 100644 index 13065f1..0000000 --- a/external/cglm/struct/clipspace/project_zo.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE vec3s glms_unprojecti_no(vec3s pos, mat4s invMat, vec4s vp) - CGLM_INLINE vec3s glms_project_no(vec3s pos, mat4s m, vec4s vp) - CGLM_INLINE float glms_project_z_zo(vec3s v, mat4s m) - */ - -#ifndef cglms_project_zo_h -#define cglms_project_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/project_zo.h" - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * - * @returns unprojected coordinates - */ -CGLM_INLINE -vec3s -glms_unprojecti_zo(vec3s pos, mat4s invMat, vec4s vp) { - vec3s dest; - glm_unprojecti_zo(pos.raw, invMat.raw, vp.raw, dest.raw); - return dest; -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * - * @returns projected coordinates - */ -CGLM_INLINE -vec3s -glms_project_zo(vec3s pos, mat4s m, vec4s vp) { - vec3s dest; - glm_project_zo(pos.raw, m.raw, vp.raw, dest.raw); - return dest; -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glms_project_z_zo(vec3s v, mat4s m) { - return glm_project_z_zo(v.raw, m.raw); -} - -#endif /* cglm_project_zo_h */ diff --git a/external/cglm/struct/clipspace/view_lh_no.h b/external/cglm/struct/clipspace/view_lh_no.h deleted file mode 100644 index e4ca5ba..0000000 --- a/external/cglm/struct/clipspace/view_lh_no.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) - CGLM_INLINE mat4s glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) - CGLM_INLINE mat4s glms_look_anyup_lh_no(vec3s eye, vec3s dir) - */ - -#ifndef cglms_view_lh_no_h -#define cglms_view_lh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/view_lh_no.h" - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_lookat_lh_no(vec3s eye, vec3s center, vec3s up) { - mat4s dest; - glm_lookat_lh_no(eye.raw, center.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_lh_no(vec3s eye, vec3s dir, vec3s up) { - mat4s dest; - glm_look_lh_no(eye.raw, dir.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [-1, 1]. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_anyup_lh_no(vec3s eye, vec3s dir) { - mat4s dest; - glm_look_anyup_lh_no(eye.raw, dir.raw, dest.raw); - return dest; -} - -#endif /* cglms_view_lh_no_h */ diff --git a/external/cglm/struct/clipspace/view_lh_zo.h b/external/cglm/struct/clipspace/view_lh_zo.h deleted file mode 100644 index ac1ada9..0000000 --- a/external/cglm/struct/clipspace/view_lh_zo.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) - CGLM_INLINE mat4s glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) - CGLM_INLINE mat4s glms_look_anyup_lh_zo(vec3s eye, vec3s dir) - */ - -#ifndef cglms_view_lh_zo_h -#define cglms_view_lh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/view_lh_zo.h" - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_lookat_lh_zo(vec3s eye, vec3s center, vec3s up) { - mat4s dest; - glm_lookat_lh_zo(eye.raw, center.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_lh_zo(vec3s eye, vec3s dir, vec3s up) { - mat4s dest; - glm_look_lh_zo(eye.raw, dir.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a left-hand coordinate system and a - * clip-space of [0, 1]. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_anyup_lh_zo(vec3s eye, vec3s dir) { - mat4s dest; - glm_look_anyup_lh_zo(eye.raw, dir.raw, dest.raw); - return dest; -} - -#endif /* cglms_view_lh_zo_h */ diff --git a/external/cglm/struct/clipspace/view_rh_no.h b/external/cglm/struct/clipspace/view_rh_no.h deleted file mode 100644 index 99b03c3..0000000 --- a/external/cglm/struct/clipspace/view_rh_no.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) - CGLM_INLINE mat4s glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) - CGLM_INLINE mat4s glms_look_anyup_rh_no(vec3s eye, vec3s dir) - */ - -#ifndef cglms_view_rh_no_h -#define cglms_view_rh_no_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/view_rh_no.h" - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_lookat_rh_no(vec3s eye, vec3s center, vec3s up) { - mat4s dest; - glm_lookat_rh_no(eye.raw, center.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_rh_no(vec3s eye, vec3s dir, vec3s up) { - mat4s dest; - glm_look_rh_no(eye.raw, dir.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [-1, 1]. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_anyup_rh_no(vec3s eye, vec3s dir) { - mat4s dest; - glm_look_anyup_rh_no(eye.raw, dir.raw, dest.raw); - return dest; -} - -#endif /* cglms_view_rh_no_h */ diff --git a/external/cglm/struct/clipspace/view_rh_zo.h b/external/cglm/struct/clipspace/view_rh_zo.h deleted file mode 100644 index 14ffe32..0000000 --- a/external/cglm/struct/clipspace/view_rh_zo.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE mat4s glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) - CGLM_INLINE mat4s glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) - CGLM_INLINE mat4s glms_look_anyup_rh_zo(vec3s eye, vec3s dir) - */ - -#ifndef cglms_view_rh_zo_h -#define cglms_view_rh_zo_h - -#include "../../common.h" -#include "../../types-struct.h" -#include "../../plane.h" -#include "../../cam.h" -#include "../../clipspace/view_rh_zo.h" - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] center center vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_lookat_rh_zo(vec3s eye, vec3s center, vec3s up) { - mat4s dest; - glm_lookat_rh_zo(eye.raw, center.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * convenient wrapper for lookat: if you only have direction not target self - * then this might be useful. Because you need to get target from direction. - * - * NOTE: The UP vector must not be parallel to the line of sight from - * the eye point to the reference point - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @param[in] up up vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_rh_zo(vec3s eye, vec3s dir, vec3s up) { - mat4s dest; - glm_look_rh_zo(eye.raw, dir.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief set up view matrix - * with a right-hand coordinate system and a - * clip-space of [0, 1]. - * - * convenient wrapper for look: if you only have direction and if you don't - * care what UP vector is then this might be useful to create view matrix - * - * @param[in] eye eye vector - * @param[in] dir direction vector - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_look_anyup_rh_zo(vec3s eye, vec3s dir) { - mat4s dest; - glm_look_anyup_rh_zo(eye.raw, dir.raw, dest.raw); - return dest; -} - -#endif /* cglms_view_rh_zo_h */ diff --git a/external/cglm/struct/color.h b/external/cglm/struct/color.h deleted file mode 100644 index 3ce78da..0000000 --- a/external/cglm/struct/color.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_colors_h -#define cglms_colors_h - -#include "../common.h" -#include "../types-struct.h" -#include "../color.h" -#include "vec3.h" - -/*! - * @brief averages the color channels into one value - * - * @param[in] rgb RGB color - */ -CGLM_INLINE -float -glms_luminance(vec3s rgb) { - return glm_luminance(rgb.raw); -} - -#endif /* cglms_colors_h */ diff --git a/external/cglm/struct/curve.h b/external/cglm/struct/curve.h deleted file mode 100644 index 53ea359..0000000 --- a/external/cglm/struct/curve.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_curves_h -#define cglms_curves_h - -#include "../common.h" -#include "../types-struct.h" -#include "../curve.h" -#include "vec4.h" -#include "mat4.h" - -/*! - * @brief helper function to calculate S*M*C multiplication for curves - * - * This function does not encourage you to use SMC, - * instead it is a helper if you use SMC. - * - * if you want to specify S as vector then use more generic glm_mat4_rmc() func. - * - * Example usage: - * B(s) = glm_smc(s, GLM_BEZIER_MAT, (vec4){p0, c0, c1, p1}) - * - * @param[in] s parameter between 0 and 1 (this will be [s3, s2, s, 1]) - * @param[in] m basis matrix - * @param[in] c position/control vector - * - * @return B(s) - */ -CGLM_INLINE -float -glms_smc(float s, mat4s m, vec4s c) { - return glm_smc(s, m.raw, c.raw); -} - -#endif /* cglms_curves_h */ diff --git a/external/cglm/struct/euler.h b/external/cglm/struct/euler.h deleted file mode 100644 index 19697f7..0000000 --- a/external/cglm/struct/euler.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - NOTE: - angles must be passed as [X-Angle, Y-Angle, Z-angle] order - For instance you don't pass angles as [Z-Angle, X-Angle, Y-angle] to - glm_euler_zxy function, All RELATED functions accept angles same order - which is [X, Y, Z]. - */ - -/* - Types: - enum glm_euler_seq - - Functions: - CGLM_INLINE vec3s glms_euler_angles(mat4s m) - CGLM_INLINE mat4s glms_euler_xyz(vec3s angles) - CGLM_INLINE mat4s glms_euler_xzy(vec3s angles) - CGLM_INLINE mat4s glms_euler_yxz(vec3s angles) - CGLM_INLINE mat4s glms_euler_yzx(vec3s angles) - CGLM_INLINE mat4s glms_euler_zxy(vec3s angles) - CGLM_INLINE mat4s glms_euler_zyx(vec3s angles) - CGLM_INLINE mat4s glms_euler_by_order(vec3s angles, glm_euler_seq ord) - CGLM_INLINE versors glms_euler_xyz_quat(vec3s angles) - CGLM_INLINE versors glms_euler_xzy_quat(vec3s angles) - CGLM_INLINE versors glms_euler_yxz_quat(vec3s angles) - CGLM_INLINE versors glms_euler_yzx_quat(vec3s angles) - CGLM_INLINE versors glms_euler_zxy_quat(vec3s angles) - CGLM_INLINE versors glms_euler_zyx_quat(vec3s angles) - */ - -#ifndef cglms_euler_h -#define cglms_euler_h - -#include "../common.h" -#include "../types-struct.h" -#include "../euler.h" - -/*! - * @brief extract euler angles (in radians) using xyz order - * - * @param[in] m affine transform - * @returns angles vector [x, y, z] - */ -CGLM_INLINE -vec3s -glms_euler_angles(mat4s m) { - vec3s dest; - glm_euler_angles(m.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_xyz(vec3s angles) { - mat4s dest; - glm_euler_xyz(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_xzy(vec3s angles) { - mat4s dest; - glm_euler_xzy(angles.raw, dest.raw); - return dest; -} - - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_yxz(vec3s angles) { - mat4s dest; - glm_euler_yxz(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_yzx(vec3s angles) { - mat4s dest; - glm_euler_yzx(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_zxy(vec3s angles) { - mat4s dest; - glm_euler_zxy(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_zyx(vec3s angles) { - mat4s dest; - glm_euler_zyx(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief build rotation matrix from euler angles - * - * @param[in] angles angles as vector [Xangle, Yangle, Zangle] - * @param[in] ord euler order - * @returns rotation matrix - */ -CGLM_INLINE -mat4s -glms_euler_by_order(vec3s angles, glm_euler_seq ord) { - mat4s dest; - glm_euler_by_order(angles.raw, ord, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_xyz_quat(vec3s angles) { - versors dest; - glm_euler_xyz_quat(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_xzy_quat(vec3s angles) { - versors dest; - glm_euler_xzy_quat(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_yxz_quat(vec3s angles) { - versors dest; - glm_euler_yxz_quat(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_yzx_quat(vec3s angles) { - versors dest; - glm_euler_yzx_quat(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_zxy_quat(vec3s angles) { - versors dest; - glm_euler_zxy_quat(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_euler_zyx_quat(vec3s angles) { - versors dest; - glm_euler_zyx_quat(angles.raw, dest.raw); - return dest; -} - - -#endif /* cglms_euler_h */ diff --git a/external/cglm/struct/frustum.h b/external/cglm/struct/frustum.h deleted file mode 100644 index 81b5b7b..0000000 --- a/external/cglm/struct/frustum.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_frustums_h -#define cglms_frustums_h - -#include "../common.h" -#include "../types-struct.h" -#include "../frustum.h" -#include "plane.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -/* you can override clip space coords - but you have to provide all with same name - e.g.: define GLM_CSCOORD_LBN {0.0f, 0.0f, 1.0f, 1.0f} */ -#ifndef GLM_CUSTOM_CLIPSPACE - -/* near */ -#define GLMS_CSCOORD_LBN {-1.0f, -1.0f, -1.0f, 1.0f} -#define GLMS_CSCOORD_LTN {-1.0f, 1.0f, -1.0f, 1.0f} -#define GLMS_CSCOORD_RTN { 1.0f, 1.0f, -1.0f, 1.0f} -#define GLMS_CSCOORD_RBN { 1.0f, -1.0f, -1.0f, 1.0f} - -/* far */ -#define GLMS_CSCOORD_LBF {-1.0f, -1.0f, 1.0f, 1.0f} -#define GLMS_CSCOORD_LTF {-1.0f, 1.0f, 1.0f, 1.0f} -#define GLMS_CSCOORD_RTF { 1.0f, 1.0f, 1.0f, 1.0f} -#define GLMS_CSCOORD_RBF { 1.0f, -1.0f, 1.0f, 1.0f} - -#endif - -/*! - * @brief extracts view frustum planes - * - * planes' space: - * 1- if m = proj: View Space - * 2- if m = viewProj: World Space - * 3- if m = MVP: Object Space - * - * You probably want to extract planes in world space so use viewProj as m - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * - * Exracted planes order: [left, right, bottom, top, near, far] - * - * @param[in] m matrix (see brief) - * @param[out] dest extracted view frustum planes (see brief) - */ -CGLM_INLINE -void -glms_frustum_planes(mat4s m, vec4s dest[6]) { - vec4 rawDest[6]; - glm_frustum_planes(m.raw, rawDest); - glms_vec4_(pack)(dest, rawDest, 6); -} - -/*! - * @brief extracts view frustum corners using clip-space coordinates - * - * corners' space: - * 1- if m = invViewProj: World Space - * 2- if m = invMVP: Object Space - * - * You probably want to extract corners in world space so use invViewProj - * Computing invViewProj: - * glm_mat4_mul(proj, view, viewProj); - * ... - * glm_mat4_inv(viewProj, invViewProj); - * - * if you have a near coord at i index, you can get it's far coord by i + 4 - * - * Find center coordinates: - * for (j = 0; j < 4; j++) { - * glm_vec3_center(corners[i], corners[i + 4], centerCorners[i]); - * } - * - * @param[in] invMat matrix (see brief) - * @param[out] dest exracted view frustum corners (see brief) - */ -CGLM_INLINE -void -glms_frustum_corners(mat4s invMat, vec4s dest[8]) { - vec4 rawDest[8]; - glm_frustum_corners(invMat.raw, rawDest); - glms_vec4_(pack)(dest, rawDest, 8); -} - -/*! - * @brief finds center of view frustum - * - * @param[in] corners view frustum corners - * @returns view frustum center - */ -CGLM_INLINE -vec4s -glms_frustum_center(vec4s corners[8]) { - vec4 rawCorners[8]; - vec4s r; - - glms_vec4_(unpack)(rawCorners, corners, 8); - glm_frustum_center(rawCorners, r.raw); - return r; -} - -/*! - * @brief finds bounding box of frustum relative to given matrix e.g. view mat - * - * @param[in] corners view frustum corners - * @param[in] m matrix to convert existing conners - * @param[out] box bounding box as array [min, max] - */ -CGLM_INLINE -void -glms_frustum_box(vec4s corners[8], mat4s m, vec3s box[2]) { - vec4 rawCorners[8]; - vec3 rawBox[2]; - - glms_vec4_(unpack)(rawCorners, corners, 8); - glm_frustum_box(rawCorners, m.raw, rawBox); - glms_vec3_(pack)(box, rawBox, 2); -} - -/*! - * @brief finds planes corners which is between near and far planes (parallel) - * - * this will be helpful if you want to split a frustum e.g. CSM/PSSM. This will - * find planes' corners but you will need to one more plane. - * Actually you have it, it is near, far or created previously with this func ;) - * - * @param[in] corners view frustum corners - * @param[in] splitDist split distance - * @param[in] farDist far distance (zFar) - * @param[out] planeCorners plane corners [LB, LT, RT, RB] - */ -CGLM_INLINE -void -glms_frustum_corners_at(vec4s corners[8], - float splitDist, - float farDist, - vec4s planeCorners[4]) { - vec4 rawCorners[8]; - vec4 rawPlaneCorners[4]; - - glms_vec4_(unpack)(rawCorners, corners, 8); - glm_frustum_corners_at(rawCorners, splitDist, farDist, rawPlaneCorners); - glms_vec4_(pack)(planeCorners, rawPlaneCorners, 8); -} - -#endif /* cglms_frustums_h */ diff --git a/external/cglm/struct/handed/euler_to_quat_lh.h b/external/cglm/struct/handed/euler_to_quat_lh.h deleted file mode 100644 index 3964e51..0000000 --- a/external/cglm/struct/handed/euler_to_quat_lh.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glms_euler_xyz_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_xzy_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_yxz_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_yzx_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_zxy_quat_lh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_zyx_quat_lh(vec3 angles, versor dest); - */ - -#ifndef cglms_euler_to_quat_lh_h -#define cglms_euler_to_quat_lh_h - -#include "../common.h" - - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order in left hand (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_xyz_quat_lh(vec3s angles) { - versors dest; - glm_euler_xyz_quat_lh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order in left hand (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_xzy_quat_lh(vec3s angles) { - versors dest; - glm_euler_xzy_quat_lh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order in left hand (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_yxz_quat_lh(vec3s angles) { - versors dest; - glm_euler_yxz_quat_lh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order in left hand (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_yzx_quat_lh(vec3s angles) { - versors dest; - glm_euler_yzx_quat_lh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order in left hand (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_zxy_quat_lh(vec3s angles) { - versors dest; - glm_euler_zxy_quat_lh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order in left hand (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_zyx_quat_lh(vec3s angles) { - versors dest; - glm_euler_zyx_quat_lh(angles.raw, dest.raw); - return dest; -} - - -#endif /* cglms_euler_to_quat_lh_h */ diff --git a/external/cglm/struct/handed/euler_to_quat_rh.h b/external/cglm/struct/handed/euler_to_quat_rh.h deleted file mode 100644 index 6c7f400..0000000 --- a/external/cglm/struct/handed/euler_to_quat_rh.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glms_euler_xyz_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_xzy_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_yxz_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_yzx_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_zxy_quat_rh(vec3 angles, versor dest); - CGLM_INLINE void glms_euler_zyx_quat_rh(vec3 angles, versor dest); - */ - -#ifndef cglms_euler_to_quat_rh_h -#define cglms_euler_to_quat_rh_h - -#include "../common.h" - - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x y z order in right hand (roll pitch yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_xyz_quat_rh(vec3s angles) { - versors dest; - glm_euler_xyz_quat_rh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in x z y order in right hand (roll yaw pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_xzy_quat_rh(vec3s angles) { - versors dest; - glm_euler_xzy_quat_rh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y x z order in right hand (pitch roll yaw) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_yxz_quat_rh(vec3s angles) { - versors dest; - glm_euler_yxz_quat_rh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in y z x order in right hand (pitch yaw roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_yzx_quat_rh(vec3s angles) { - versors dest; - glm_euler_yzx_quat_rh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z x y order in right hand (yaw roll pitch) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_zxy_quat_rh(vec3s angles) { - versors dest; - glm_euler_zxy_quat_rh(angles.raw, dest.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion using rotation angles and does - * rotations in z y x order in right hand (yaw pitch roll) - * - * @param[in] angles angles x y z (radians) - * @param[out] dest quaternion - */ -CGLM_INLINE -versors -glms_euler_zyx_quat_rh(vec3s angles) { - versors dest; - glm_euler_zyx_quat_rh(angles.raw, dest.raw); - return dest; -} - - -#endif /* cglms_euler_to_quat_rh_h */ diff --git a/external/cglm/struct/io.h b/external/cglm/struct/io.h deleted file mode 100644 index 900c2a8..0000000 --- a/external/cglm/struct/io.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glms_mat4_print(mat4s matrix, FILE *ostream); - CGLM_INLINE void glms_mat3_print(mat3s matrix, FILE *ostream); - CGLM_INLINE void glms_vec4_print(vec4s vec, FILE *ostream); - CGLM_INLINE void glms_ivec4_print(ivec3s vec, FILE *ostream); - CGLM_INLINE void glms_vec3_print(vec3s vec, FILE *ostream); - CGLM_INLINE void glms_ivec3_print(ivec3s vec, FILE *ostream); - CGLM_INLINE void glms_vec2_print(vec2s vec, FILE *ostream); - CGLM_INLINE void glms_ivec2_print(ivec3s vec, FILE *ostream); - CGLM_INLINE void glms_versor_print(versor vec, FILE *ostream); - CGLM_INLINE void glms_aabb_print(vec3s bbox[2], const char *tag, FILE *ostream); - */ - -#ifndef cglms_ios_h -#define cglms_ios_h - -#include "../common.h" -#include "../io.h" -#include "mat4.h" - -#include -#include - -CGLM_INLINE -void -glms_mat4_print(mat4s matrix, - FILE * __restrict ostream) { - - glm_mat4_print(matrix.raw, ostream); -} - -CGLM_INLINE -void -glms_mat3_print(mat3s matrix, - FILE * __restrict ostream) { - glm_mat3_print(matrix.raw, ostream); -} - -CGLM_INLINE -void -glms_vec4_print(vec4s vec, - FILE * __restrict ostream) { - glm_vec4_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_ivec4_print(ivec4s vec, - FILE * __restrict ostream) { - glm_ivec4_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_vec3_print(vec3s vec, - FILE * __restrict ostream) { - glm_vec3_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_ivec3_print(ivec3s vec, - FILE * __restrict ostream) { - glm_ivec3_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_vec2_print(vec2s vec, - FILE * __restrict ostream) { - glm_vec2_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_ivec2_print(ivec2s vec, - FILE * __restrict ostream) { - glm_ivec2_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_versor_print(versors vec, - FILE * __restrict ostream) { - glm_versor_print(vec.raw, ostream); -} - -CGLM_INLINE -void -glms_aabb_print(vec3s bbox[2], - const char * __restrict tag, - FILE * __restrict ostream) { - vec3 rawBbox[2]; - - glms_vec3_(unpack)(rawBbox, bbox, 2); - glm_aabb_print(rawBbox, tag, ostream); -} - -#endif /* cglms_ios_h */ diff --git a/external/cglm/struct/ivec2.h b/external/cglm/struct/ivec2.h deleted file mode 100644 index d53c9f6..0000000 --- a/external/cglm/struct/ivec2.h +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_IVEC2_ONE_INIT - GLMS_IVEC2_ZERO_INIT - GLMS_IVEC2_ONE - GLMS_IVEC2_ZERO - - Functions: - CGLM_INLINE ivec2s glms_ivec2(int * __restrict v) - CGLM_INLINE void glms_ivec2_pack(ivec2s dst[], ivec2s src[], size_t len) - CGLM_INLINE void glms_ivec2_unpack(ivec2 dst[], ivec2 src[], size_t len) - CGLM_INLINE ivec2s glms_ivec2_zero(ivec2s v) - CGLM_INLINE ivec2s glms_ivec2_one(ivec2s v) - CGLM_INLINE int glms_ivec2_dot(ivec2s a, ivec2s b) - CGLM_INLINE int glms_ivec2_cross(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_add(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_adds(ivec2s v, int s) - CGLM_INLINE ivec2s glms_ivec2_sub(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_subs(ivec2s v, int s) - CGLM_INLINE ivec2s glms_ivec2_mul(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_scale(ivec2s v, int s) - CGLM_INLINE ivec2s glms_ivec2_div(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_divs(ivec2s v, int s) - CGLM_INLINE ivec2s glms_ivec2_mod(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_addadd(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_addadds(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_subadd(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_subadds(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_muladd(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_muladds(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_maxadd(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_minadd(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_subsub(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_subsubs(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_addsub(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_addsubs(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_mulsub(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_mulsubs(ivec2s a, int s) - CGLM_INLINE ivec2s glms_ivec2_maxsub(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_minsub(ivec2s a, ivec2s b) - CGLM_INLINE int glms_ivec2_distance2(ivec2s a, ivec2s b) - CGLM_INLINE float glms_ivec2_distance(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_fill(int val) - CGLM_INLINE bool glms_ivec2_eq(ivec2s v, int val); - CGLM_INLINE bool glms_ivec2_eqv(ivec2s a, ivec2s b); - CGLM_INLINE ivec2s glms_ivec2_maxv(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_minv(ivec2s a, ivec2s b) - CGLM_INLINE ivec2s glms_ivec2_clamp(ivec2s v, int minVal, int maxVal) - CGLM_INLINE ivec2s glms_ivec2_abs(ivec2s v) - */ - -#ifndef cglms_ivec2_h -#define cglms_ivec2_h - -#include "../common.h" -#include "../types-struct.h" -#include "../ivec2.h" - -#define glms_ivec2_(NAME) CGLM_STRUCTAPI(ivec2, NAME) - -#define GLMS_IVEC2_ONE_INIT {GLM_IVEC2_ONE_INIT} -#define GLMS_IVEC2_ZERO_INIT {GLM_IVEC2_ZERO_INIT} - -#define GLMS_IVEC2_ONE ((ivec2s)GLMS_IVEC2_ONE_INIT) -#define GLMS_IVEC2_ZERO ((ivec2s)GLMS_IVEC2_ZERO_INIT) - -/*! - * @brief init ivec2 using ivec3 or ivec4 - * - * @param[in] v vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2(int * __restrict v) { - ivec2s r; - glm_ivec2(v, r.raw); - return r; -} - -/*! - * @brief pack an array of ivec2 into an array of ivec2s - * - * @param[out] dst array of ivec2s - * @param[in] src array of ivec2 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec2_(pack)(ivec2s dst[], ivec2 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec2_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of ivec2s into an array of ivec2 - * - * @param[out] dst array of ivec2 - * @param[in] src array of ivec2s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec2_(unpack)(ivec2 dst[], ivec2s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec2_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief set all members of [v] to zero - * - * @returns vector - */ -CGLM_INLINE -ivec2s -glms_ivec2_(zero)(void) { - ivec2s r; - glm_ivec2_zero(r.raw); - return r; -} - -/*! - * @brief set all members of [v] to one - * - * @returns vector - */ -CGLM_INLINE -ivec2s -glms_ivec2_(one)(void) { - ivec2s r; - glm_ivec2_one(r.raw); - return r; -} - -/*! - * @brief ivec2 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -int -glms_ivec2_(dot)(ivec2s a, ivec2s b) { - return glm_ivec2_dot(a.raw, b.raw); -} - -/*! - * @brief ivec2 cross product - * - * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return Z component of cross product - */ -CGLM_INLINE -int -glms_ivec2_(cross)(ivec2s a, ivec2s b) { - return glm_ivec2_cross(a.raw, b.raw); -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(add)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(adds)(ivec2s v, int s) { - ivec2s r; - glm_ivec2_adds(v.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(sub)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(subs)(ivec2s v, int s) { - ivec2s r; - glm_ivec2_subs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(mul)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(scale)(ivec2s v, int s) { - ivec2s r; - glm_ivec2_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]/b[0], a[1]/b[1]) - */ -CGLM_INLINE -ivec2s -glms_ivec2_(div)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_div(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @returns result = (a[0]/s, a[1]/s) - */ -CGLM_INLINE -ivec2s -glms_ivec2_(divs)(ivec2s v, int s) { - ivec2s r; - glm_ivec2_divs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief mod vector with another component-wise modulo: d = a % b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]%b[0], a[1]%b[1]) - */ -CGLM_INLINE -ivec2s -glms_ivec2_(mod)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_mod(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a + b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(addadd)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a + s) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(addadds)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_addadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a - b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(subadd)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[in] dest dest += (a - s) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(subadds)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_subadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a * b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(muladd)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a * s) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(muladds)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(maxadd)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(minadd)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= (a - b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(subsub)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a - s) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(subsubs)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_subsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(addsub)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(addsubs)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_addsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a * b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(mulsub)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a * s) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(mulsubs)(ivec2s a, int s, ivec2s dest) { - glm_ivec2_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(maxsub)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(minsub)(ivec2s a, ivec2s b, ivec2s dest) { - glm_ivec2_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glms_ivec2_(distance2)(ivec2s a, ivec2s b) { - return glm_ivec2_distance2(a.raw, b.raw); -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glms_ivec2_(distance)(ivec2s a, ivec2s b) { - return glm_ivec2_distance(a.raw, b.raw); -} - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @returns dest - */ -CGLM_INLINE -ivec2s -glms_ivec2_(fill)(int val) { - ivec2s r; - glm_ivec2_fill(r.raw, val); - return r; -} - -/*! - * @brief check if vector is equal to value - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_ivec2_(eq)(ivec2s v, int val) { - return glm_ivec2_eq(v.raw, val); -} - -/*! - * @brief check if vector is equal to another - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_ivec2_(eqv)(ivec2s a, ivec2s b) { - return glm_ivec2_eqv(a.raw, b.raw); -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(maxv)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(minv)(ivec2s a, ivec2s b) { - ivec2s r; - glm_ivec2_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -ivec2s -glms_ivec2_(clamp)(ivec2s v, int minVal, int maxVal) { - glm_ivec2_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @returns destination - */ -CGLM_INLINE -ivec2s -glms_ivec2_(abs)(ivec2s v) { - ivec2s r; - glm_ivec2_abs(v.raw, r.raw); - return r; -} - -#endif /* cglms_ivec2_h */ diff --git a/external/cglm/struct/ivec3.h b/external/cglm/struct/ivec3.h deleted file mode 100644 index c2c5f3b..0000000 --- a/external/cglm/struct/ivec3.h +++ /dev/null @@ -1,725 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_IVEC3_ONE_INIT - GLMS_IVEC3_ZERO_INIT - GLMS_IVEC3_ONE - GLMS_IVEC3_ZERO - - Functions: - CGLM_INLINE ivec3s glms_ivec3(ivec4s v4) - CGLM_INLINE void glms_ivec3_pack(ivec3s dst[], ivec3 src[], size_t len) - CGLM_INLINE void glms_ivec3_unpack(ivec3 dst[], ivec3s src[], size_t len) - CGLM_INLINE ivec3s glms_ivec3_zero(void) - CGLM_INLINE ivec3s glms_ivec3_one(void) - CGLM_INLINE int glms_ivec3_dot(ivec3s a, ivec3s b) - CGLM_INLINE int glms_ivec3_norm2(ivec3s v) - CGLM_INLINE int glms_ivec3_norm(ivec3s v) - CGLM_INLINE ivec3s glms_ivec3_add(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_adds(ivec3s v, int s) - CGLM_INLINE ivec3s glms_ivec3_sub(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_subs(ivec3s v, int s) - CGLM_INLINE ivec3s glms_ivec3_mul(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_scale(ivec3s v, int s) - CGLM_INLINE ivec3s glms_ivec3_div(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_divs(ivec3s v, int s) - CGLM_INLINE ivec3s glms_ivec3_mod(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_addadd(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_addadds(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_subadd(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_subadds(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_muladd(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_muladds(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_minadd(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_subsub(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_subsubs(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_addsub(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_addsubs(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_mulsub(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_mulsubs(ivec3s a, int s, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_maxsub(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE ivec3s glms_ivec3_minsub(ivec3s a, ivec3s b, ivec3s dest) - CGLM_INLINE int glms_ivec3_distance2(ivec3s a, ivec3s b) - CGLM_INLINE float glms_ivec3_distance(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_fill(int val) - CGLM_INLINE bool glms_ivec3_eq(ivec3s v, int val) - CGLM_INLINE bool glms_ivec3_eqv(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_maxv(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_minv(ivec3s a, ivec3s b) - CGLM_INLINE ivec3s glms_ivec3_clamp(ivec3s v, int minVal, int maxVal) - CGLM_INLINE ivec3s glms_ivec3_abs(ivec3s v) - */ - -#ifndef cglms_ivec3_h -#define cglms_ivec3_h - -#include "../common.h" -#include "../types-struct.h" -#include "../ivec3.h" - -#define glms_ivec3_(NAME) CGLM_STRUCTAPI(ivec3, NAME) - -#define GLMS_IVEC3_ONE_INIT {GLM_IVEC3_ONE_INIT} -#define GLMS_IVEC3_ZERO_INIT {GLM_IVEC3_ZERO_INIT} - -#define GLMS_IVEC3_ONE ((ivec3s)GLMS_IVEC3_ONE_INIT) -#define GLMS_IVEC3_ZERO ((ivec3s)GLMS_IVEC3_ZERO_INIT) - -/*! - * @brief init ivec3 using ivec4 - * - * @param[in] v4 vector4 - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3(ivec4s v4) { - ivec3s r; - glm_ivec3(v4.raw, r.raw); - return r; -} - -/*! - * @brief pack an array of ivec3 into an array of ivec3s - * - * @param[out] dst array of ivec3s - * @param[in] src array of ivec3 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec3_(pack)(ivec3s dst[], ivec3 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec3_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of ivec3s into an array of ivec3 - * - * @param[out] dst array of ivec3 - * @param[in] src array of ivec3s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec3_(unpack)(ivec3 dst[], ivec3s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec3_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief set all members of [v] to zero - * - * @returns vector - */ -CGLM_INLINE -ivec3s -glms_ivec3_(zero)(void) { - ivec3s r; - glm_ivec3_zero(r.raw); - return r; -} - -/*! - * @brief set all members of [v] to one - * - * @returns vector - */ -CGLM_INLINE -ivec3s -glms_ivec3_(one)(void) { - ivec3s r; - glm_ivec3_one(r.raw); - return r; -} - -/*! - * @brief ivec3 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -int -glms_ivec3_(dot)(ivec3s a, ivec3s b) { - return glm_ivec3_dot(a.raw, b.raw); -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -int -glms_ivec3_(norm2)(ivec3s v) { - return glm_ivec3_norm2(v.raw); -} - -/*! - * @brief euclidean norm (magnitude), also called L2 norm - * this will give magnitude of vector in euclidean space - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -int -glms_ivec3_(norm)(ivec3s v) { - return glm_ivec3_norm(v.raw); -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(add)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(adds)(ivec3s v, int s) { - ivec3s r; - glm_ivec3_adds(v.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(sub)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(subs)(ivec3s v, int s) { - ivec3s r; - glm_ivec3_subs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(mul)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(scale)(ivec3s v, int s) { - ivec3s r; - glm_ivec3_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) - */ -CGLM_INLINE -ivec3s -glms_ivec3_(div)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_div(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @returns result = (a[0]/s, a[1]/s, a[2]/s) - */ -CGLM_INLINE -ivec3s -glms_ivec3_(divs)(ivec3s v, int s) { - ivec3s r; - glm_ivec3_divs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief Element-wise modulo operation on ivec3 vectors: dest = a % b - * - * Performs element-wise modulo on each component of vectors `a` and `b`. - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]%b[0], a[1]%b[1], a[2]%b[2]) - */ -CGLM_INLINE -ivec3s -glms_ivec3_(mod)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_mod(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a + b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(addadd)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a + s) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(addadds)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_addadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a - b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(subadd)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[in] dest dest += (a - s) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(subadds)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_subadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a * b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(muladd)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a * s) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(muladds)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(maxadd)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(minadd)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= (a - b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(subsub)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a - s) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(subsubs)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_subsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(addsub)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(addsubs)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_addsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a * b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(mulsub)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a * s) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(mulsubs)(ivec3s a, int s, ivec3s dest) { - glm_ivec3_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(maxsub)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec3s -glms_ivec3_(minsub)(ivec3s a, ivec3s b, ivec3s dest) { - glm_ivec3_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glms_ivec3_(distance2)(ivec3s a, ivec3s b) { - return glm_ivec3_distance2(a.raw, b.raw); -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glms_ivec3_(distance)(ivec3s a, ivec3s b) { - return glm_ivec3_distance(a.raw, b.raw); -} - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(fill)(int val) { - ivec3s r; - glm_ivec3_fill(r.raw, val); - return r; -} - -/*! - * @brief check if vector is equal to value - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_ivec3_(eq)(ivec3s v, int val) { - return glm_ivec3_eq(v.raw, val); -} - -/*! - * @brief check if vector is equal to another - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_ivec3_(eqv)(ivec3s a, ivec3s b) { - return glm_ivec3_eqv(a.raw, b.raw); -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(maxv)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(minv)(ivec3s a, ivec3s b) { - ivec3s r; - glm_ivec3_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -ivec3s -glms_ivec3_(clamp)(ivec3s v, int minVal, int maxVal) { - glm_ivec3_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @returns destination - */ -CGLM_INLINE -ivec3s -glms_ivec3_(abs)(ivec3s v) { - ivec3s r; - glm_ivec3_abs(v.raw, r.raw); - return r; -} - -#endif /* cglms_ivec3_h */ diff --git a/external/cglm/struct/ivec4.h b/external/cglm/struct/ivec4.h deleted file mode 100644 index 103e887..0000000 --- a/external/cglm/struct/ivec4.h +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_IVEC4_ONE_INIT - GLMS_IVEC4_ZERO_INIT - GLMS_IVEC4_ONE - GLMS_IVEC4_ZERO - - Functions: - CGLM_INLINE ivec4s glms_ivec4(ivec3s v3, int last) - CGLM_INLINE void glms_ivec4_pack(ivec4s dst[], ivec4 src[], size_t len) - CGLM_INLINE void glms_ivec4_unpack(ivec4 dst[], ivec4s src[], size_t len) - CGLM_INLINE ivec4s glms_ivec4_zero(void) - CGLM_INLINE ivec4s glms_ivec4_one(void) - CGLM_INLINE ivec4s glms_ivec4_add(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_adds(ivec4s v, int s) - CGLM_INLINE ivec4s glms_ivec4_sub(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_subs(ivec4s v, int s) - CGLM_INLINE ivec4s glms_ivec4_mul(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_scale(ivec4s v, int s) - CGLM_INLINE ivec4s glms_ivec4_addadd(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_addadds(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_subadd(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_subadds(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_muladd(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_muladds(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_maxadd(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_minadd(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_subsub(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_subsubs(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_addsub(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_addsubs(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_mulsub(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_mulsubs(ivec4s a, int s, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_maxsub(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE ivec4s glms_ivec4_minsub(ivec4s a, ivec4s b, ivec4s dest) - CGLM_INLINE int glms_ivec4_distance2(ivec4s a, ivec4s b) - CGLM_INLINE float glms_ivec4_distance(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_maxv(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_minv(ivec4s a, ivec4s b) - CGLM_INLINE ivec4s glms_ivec4_clamp(ivec4s v, int minVal, int maxVal) - CGLM_INLINE ivec4s glms_ivec4_abs(ivec4s v) - */ - -#ifndef cglms_ivec4_h -#define cglms_ivec4_h - -#include "../common.h" -#include "../types-struct.h" -#include "../ivec4.h" - -#define glms_ivec4_(NAME) CGLM_STRUCTAPI(ivec4, NAME) - -#define GLMS_IVEC4_ONE_INIT {GLM_IVEC4_ONE_INIT} -#define GLMS_IVEC4_ZERO_INIT {GLM_IVEC4_ZERO_INIT} - -#define GLMS_IVEC4_ONE ((ivec4s)GLMS_IVEC4_ONE_INIT) -#define GLMS_IVEC4_ZERO ((ivec4s)GLMS_IVEC4_ZERO_INIT) - -/*! - * @brief init ivec4 using ivec3 - * - * @param[in] v3 vector3 - * @param[in] last last item - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4(ivec3s v3, int last) { - ivec4s r; - glm_ivec4(v3.raw, last, r.raw); - return r; -} - -/*! - * @brief pack an array of ivec4 into an array of ivec4s - * - * @param[out] dst array of ivec4s - * @param[in] src array of ivec4 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec4_(pack)(ivec4s dst[], ivec4 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec4_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of ivec4s into an array of ivec4 - * - * @param[out] dst array of ivec4 - * @param[in] src array of ivec4s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_ivec4_(unpack)(ivec4 dst[], ivec4s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_ivec4_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief set all members of [v] to zero - * - * @returns vector - */ -CGLM_INLINE -ivec4s -glms_ivec4_(zero)(void) { - ivec4s r; - glm_ivec4_zero(r.raw); - return r; -} - -/*! - * @brief set all members of [v] to one - * - * @returns vector - */ -CGLM_INLINE -ivec4s -glms_ivec4_(one)(void) { - ivec4s r; - glm_ivec4_one(r.raw); - return r; -} - -/*! - * @brief add vector [a] to vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(add)(ivec4s a, ivec4s b) { - ivec4s r; - glm_ivec4_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar s to vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(adds)(ivec4s v, int s) { - ivec4s r; - glm_ivec4_adds(v.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract vector [b] from vector [a] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(sub)(ivec4s a, ivec4s b) { - ivec4s r; - glm_ivec4_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar s from vector [v] and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(subs)(ivec4s v, int s) { - ivec4s r; - glm_ivec4_subs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with vector [b] and store result in [dest] - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(mul)(ivec4s a, ivec4s b) { - ivec4s r; - glm_ivec4_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply vector [a] with scalar s and store result in [dest] - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(scale)(ivec4s v, int s) { - ivec4s r; - glm_ivec4_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief add vector [a] with vector [b] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a + b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(addadd)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] onto vector [a] and add result to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a + s) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(addadds)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_addadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a - b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(subadd)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first - * @param[in] s scalar - * @param[in] dest dest += (a - s) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(subadds)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_subadds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with vector [b] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += (a * b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(muladd)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and add result to [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest += (a * s) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(muladds)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add maximum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(maxadd)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add minimum of vector [a] and vector [b] to vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest += min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(minadd)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract vector [a] from vector [b] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= (a - b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(subsub)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract scalar [s] from vector [a] and subtract result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a - s) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(subsubs)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_subsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add vector [a] to vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(addsub)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add scalar [s] to vector [a] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a + b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(addsubs)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_addsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] and vector [b] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] b scalar - * @param[in] dest dest -= (a * b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(mulsub)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply vector [a] with scalar [s] and subtract the result from [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[in] dest dest -= (a * s) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(mulsubs)(ivec4s a, int s, ivec4s dest) { - glm_ivec4_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief subtract maximum of vector [a] and vector [b] from vector [dest] - * - * applies += operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= max(a, b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(maxsub)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract minimum of vector [a] and vector [b] from vector [dest] - * - * applies -= operator so dest must be initialized - * - * @param[in] a first vector - * @param[in] b second vector - * @param[in] dest dest -= min(a, b) - * @returns dest - */ -CGLM_INLINE -ivec4s -glms_ivec4_(minsub)(ivec4s a, ivec4s b, ivec4s dest) { - glm_ivec4_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief squared distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -int -glms_ivec4_(distance2)(ivec4s a, ivec4s b) { - return glm_ivec4_distance2(a.raw, b.raw); -} - -/*! - * @brief distance between two vectors - * - * @param[in] a first vector - * @param[in] b second vector - * @return returns distance - */ -CGLM_INLINE -float -glms_ivec4_(distance)(ivec4s a, ivec4s b) { - return glm_ivec4_distance(a.raw, b.raw); -} - -/*! - * @brief set each member of dest to greater of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(maxv)(ivec4s a, ivec4s b) { - ivec4s r; - glm_ivec4_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief set each member of dest to lesser of vector a and b - * - * @param[in] a first vector - * @param[in] b second vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(minv)(ivec4s a, ivec4s b) { - ivec4s r; - glm_ivec4_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief clamp each member of [v] between minVal and maxVal (inclusive) - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -ivec4s -glms_ivec4_(clamp)(ivec4s v, int minVal, int maxVal) { - glm_ivec4_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @returns destination - */ -CGLM_INLINE -ivec4s -glms_ivec4_(abs)(ivec4s v) { - ivec4s r; - glm_ivec4_abs(v.raw, r.raw); - return r; -} - -#endif /* cglms_ivec4_h */ diff --git a/external/cglm/struct/mat2.h b/external/cglm/struct/mat2.h deleted file mode 100644 index 915c1be..0000000 --- a/external/cglm/struct/mat2.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_MAT2_IDENTITY_INIT - GLM_MAT2_ZERO_INIT - GLM_MAT2_IDENTITY - GLM_MAT2_ZERO - - Functions: - CGLM_INLINE mat2s glms_mat2_make(const float * __restrict src); - CGLM_INLINE mat2s glms_mat2_identity(void) - CGLM_INLINE void glms_mat2_identity_array(mat2 * restrict mats, size_t count) - CGLM_INLINE mat2s glms_mat2_zero(void) - CGLM_INLINE mat2s glms_mat2_mul(mat2 m1, mat2 m2) - CGLM_INLINE vec2s glms_mat2_mulv(mat2 m, vec2 v) - CGLM_INLINE mat2s glms_mat2_transpose(mat2 m) - CGLM_INLINE mat2s glms_mat2_scale(mat2 m, float s) - CGLM_INLINE mat2s glms_mat2_inv(mat2 m) - CGLM_INLINE mat2s glms_mat2_swap_col(mat2 mat, int col1, int col2) - CGLM_INLINE mat2s glms_mat2_swap_row(mat2 mat, int row1, int row2) - CGLM_INLINE float glms_mat2_det(mat2 m) - CGLM_INLINE float glms_mat2_trace(mat2 m) - CGLM_INLINE float glms_mat2_rmc(vec2 r, mat2 m, vec2 c) - */ - -#ifndef cglms_mat2_h -#define cglms_mat2_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat2.h" - -/* api definition */ -#define glms_mat2_(NAME) CGLM_STRUCTAPI(mat2, NAME) - -#define GLMS_MAT2_IDENTITY_INIT {GLM_MAT2_IDENTITY_INIT} -#define GLMS_MAT2_ZERO_INIT {GLM_MAT2_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT2_IDENTITY ((mat2s)GLMS_MAT2_IDENTITY_INIT) -#define GLMS_MAT2_ZERO ((mat2s)GLMS_MAT2_ZERO_INIT) - -/*! - * @brief Returns mat2s (r) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] r constructed mat2s from raw pointer - */ -CGLM_INLINE -mat2s -glms_mat2_(make)(const float * __restrict src) { - mat2s r; - glm_mat2_make(src, r.raw); - return r; -} - -/*! - * @brief Return a identity mat2s (r). - * - * The same thing may be achieved with either of bellow methods, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat2_identity(aStruct->aMatrix); - * - * @code - * glm_mat2_copy(GLM_MAT2_IDENTITY, mat); // C only - * - * // or - * mat2 mat = GLM_MAT2_IDENTITY_INIT; - * @endcode - * - * @return[out] r constructed mat2s from raw pointer - */ -CGLM_INLINE -mat2s -glms_mat2_(identity)(void) { - mat2s r; - glm_mat2_identity(r.raw); - return r; -} - -/*! - * @brief Given an array of mat2s’s (mats) make each matrix an identity matrix. - * - * @param[in, out] mats Array of mat2s’s (must be aligned (16/32) if alignment is not disabled) - * @param[in] count Array size of mats or number of matrices - */ -CGLM_INLINE -void -glms_mat2_(identity_array)(mat2s * __restrict mats, size_t count) { - CGLM_ALIGN_MAT mat2s t = GLMS_MAT2_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat2_copy(t.raw, mats[i].raw); - } -} - -/*! - * @brief Return zero'd out mat2 (r). - * - * @return[out] r constructed mat2s from raw pointer - */ -CGLM_INLINE -mat2s -glms_mat2_(zero)(void) { - mat2s r; - glm_mat2_zero(r.raw); - return r; -} - -/*! - * @brief Multiply mat2 (m1) by mat2 (m2) and return in mat2s (r) - * - * m1 and m2 matrices can be the same matrix, it is possible to write this: - * - * @code - * mat2 m = GLM_MAT2_IDENTITY_INIT; - * mat2s r = glms_mat2_mul(m, m); - * @endcode - * - * @param[in] m1 mat2s (left) - * @param[in] m2 mat2s (right) - * @return[out] r constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat2_(mul)(mat2s m1, mat2s m2) { - mat2s r; - glm_mat2_mul(m1.raw, m2.raw, r.raw); - return r; -} - -/* - * @brief Multiply mat2s (m) by vec2s (v) and return in vec2s (r). - * - * @param[in] m mat2s (left) - * @param[in] v vec2s (right, column vector) - * @return[out] r constructed vec2s from raw pointers - */ -CGLM_INLINE -vec2s -glms_mat2_(mulv)(mat2s m, vec2s v) { - vec2s r; - glm_mat2_mulv(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief Transpose mat2s (m) and store result in the same matrix. - * - * @param[in] m mat2s (src) - * @return[out] m constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat2_(transpose)(mat2s m) { - glm_mat2_transpose(m.raw); - return m; -} - -/*! - * @brief Multiply mat2s (m) by scalar constant (s) - * - * @param[in] m mat2s (src) - * @param[in] s scalar value - * @return[out] m constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat2_(scale)(mat2s m, float s) { - glm_mat2_scale(m.raw, s); - return m; -} - -/*! - * @brief Inverse mat2s (m) and return in mat2s (r). - * - * @param[in] m mat2s (left, src) - * @return[out] r constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat2_(inv)(mat2s m) { - mat2s r; - glm_mat2_inv(m.raw, r.raw); - return r; -} - -/*! - * @brief Swap two columns in mat2s (mat) and store in same matrix. - * - * @param[in] mat mat2s - * @param[in] col1 column 1 array index - * @param[in] col2 column 2 array index - * @return[out] mat constructed mat2s from raw pointers columns swapped - */ -CGLM_INLINE -mat2s -glms_mat2_(swap_col)(mat2s mat, int col1, int col2) { - glm_mat2_swap_col(mat.raw, col1, col2); - return mat; -} - -/*! - * @brief Swap two rows in mat2s (mat) and store in same matrix. - * - * @param[in] mat mat2s - * @param[in] row1 row 1 array index - * @param[in] row2 row 2 array index - * @return[out] mat constructed mat2s from raw pointers rows swapped - */ -CGLM_INLINE -mat2s -glms_mat2_(swap_row)(mat2s mat, int row1, int row2) { - glm_mat2_swap_row(mat.raw, row1, row2); - return mat; -} - -/*! - * @brief Returns mat2 determinant. - * - * @param[in] m mat2 (src) - * - * @return[out] mat2s raw pointers determinant (float) - */ -CGLM_INLINE -float -glms_mat2_(det)(mat2s m) { - return glm_mat2_det(m.raw); -} - -/*! - * @brief Returns trace of matrix. Which is: - * - * The sum of the elements on the main diagonal from - * upper left corner to the bottom right corner. - * - * @param[in] m mat2 (m) - * - * @return[out] mat2s raw pointers trace (float) - */ -CGLM_INLINE -float -glms_mat2_(trace)(mat2s m) { - return glm_mat2_trace(m.raw); -} - -/*! - * @brief Helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because M * C = ResC (1x2, column vector), - * then if you take the dot_product(R (2x1), ResC (1x2)) = scalar value. - * - * @param[in] r vec2s (2x1, row vector) - * @param[in] m mat2s (2x2, matrix) - * @param[in] c vec2s (1x2, column vector) - * - * @return[out] Scalar value (float, 1x1) - */ -CGLM_INLINE -float -glms_mat2_(rmc)(vec2s r, mat2s m, vec2s c) { - return glm_mat2_rmc(r.raw, m.raw, c.raw); -} - -#endif /* cglms_mat2_h */ diff --git a/external/cglm/struct/mat2x3.h b/external/cglm/struct/mat2x3.h deleted file mode 100644 index 5b061ba..0000000 --- a/external/cglm/struct/mat2x3.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT2X3_ZERO_INIT - GLMS_MAT2X3_ZERO - - Functions: - CGLM_INLINE mat2x3s glms_mat2x3_zero(void); - CGLM_INLINE mat2x3s glms_mat2x3_make(const float * __restrict src); - CGLM_INLINE mat2s glms_mat2x3_mul(mat2x3s m1, mat3x2s m2); - CGLM_INLINE vec3s glms_mat2x3_mulv(mat2x3s m, vec2s v); - CGLM_INLINE mat3x2s glms_mat2x3_transpose(mat2x3s m); - CGLM_INLINE mat2x3s glms_mat2x3_scale(mat2x3s m, float s); - */ - -#ifndef cglms_mat2x3_h -#define cglms_mat2x3_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat2x3.h" - -/* api definition */ -#define glms_mat2x3_(NAME) CGLM_STRUCTAPI(mat2x3, NAME) - -#define GLMS_MAT2X3_ZERO_INIT {GLM_MAT2X3_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT2X3_ZERO ((mat2x3s)GLMS_MAT2X3_ZERO_INIT) - -/*! - * @brief Zero out the mat2x3s (dest). - * - * @return[out] dest constructed mat2x3s from raw pointer - */ -CGLM_INLINE -mat2x3s -glms_mat2x3_(zero)(void) { - mat2x3s dest; - glm_mat2x3_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat2x3s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat2x3s from raw pointer - */ -CGLM_INLINE -mat2x3s -glms_mat2x3_(make)(const float * __restrict src) { - mat2x3s dest; - glm_mat2x3_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x3s (m1) by mat3x2s (m2) and store in mat3s (dest). - * - * @code - * r = glms_mat2x3_mul(mat2x3s, mat3x2s); - * @endcode - * - * @param[in] m1 mat2x3s (left) - * @param[in] m2 mat3x2s (right) - * @return[out] dest constructed mat3s from raw pointers - */ -CGLM_INLINE -mat3s -glms_mat2x3_(mul)(mat2x3s m1, mat3x2s m2) { - mat3s dest; - glm_mat2x3_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x3s (m) by vec2s (v) and store in vec3s (dest). - * - * @param[in] m mat2x3s (left) - * @param[in] v vec2s (right, column vector) - * @return[out] dest constructed vec3s from raw pointers - */ -CGLM_INLINE -vec3s -glms_mat2x3_(mulv)(mat2x3s m, vec2s v) { - vec3s dest; - glm_mat2x3_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat2x3s (m) and store in mat3x2s (dest). - * - * @param[in] m mat2x3s (left) - * @return[out] dest constructed mat3x2s from raw pointers - */ -CGLM_INLINE -mat3x2s -glms_mat2x3_(transpose)(mat2x3s m) { - mat3x2s dest; - glm_mat2x3_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x3s (m) by scalar constant (s). - * - * @param[in, out] m mat2x3 (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat2x3s -glms_mat2x3_(scale)(mat2x3s m, float s) { - glm_mat2x3_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat2x3_h */ diff --git a/external/cglm/struct/mat2x4.h b/external/cglm/struct/mat2x4.h deleted file mode 100644 index 7e3e75a..0000000 --- a/external/cglm/struct/mat2x4.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT2X4_ZERO_INIT - GLMS_MAT2X4_ZERO - - Functions: - CGLM_INLINE mat2x4s glms_mat2x4_zero(void); - CGLM_INLINE mat2x4s glms_mat2x4_make(const float * __restrict src); - CGLM_INLINE mat2s glms_mat2x4_mul(mat2x4s m1, mat4x2s m2); - CGLM_INLINE vec4s glms_mat2x4_mulv(mat2x4s m, vec2s v); - CGLM_INLINE mat4x2s glms_mat2x4_transpose(mat2x4s m); - CGLM_INLINE mat2x4s glms_mat2x4_scale(mat2x4s m, float s); - */ - -#ifndef cglms_mat2x4_h -#define cglms_mat2x4_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat2x4.h" - -/* api definition */ -#define glms_mat2x4_(NAME) CGLM_STRUCTAPI(mat2x4, NAME) - -#define GLMS_MAT2X4_ZERO_INIT {GLM_MAT2X4_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT2X4_ZERO ((mat2x4s)GLMS_MAT2X4_ZERO_INIT) - -/*! - * @brief Zero out the mat2x4s (dest). - * - * @return[out] dest constructed mat2x4s from raw pointer - */ -CGLM_INLINE -mat2x4s -glms_mat2x4_(zero)(void) { - mat2x4s dest; - glm_mat2x4_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat2x4s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat2x4s from raw pointer - */ -CGLM_INLINE -mat2x4s -glms_mat2x4_(make)(const float * __restrict src) { - mat2x4s dest; - glm_mat2x4_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x4s (m1) by mat4x2s (m2) and store in mat4s (dest). - * - * @code - * r = glms_mat2x4_mul(mat2x4s, mat4x2s); - * @endcode - * - * @param[in] m1 mat2x4s (left) - * @param[in] m2 mat4x2s (right) - * @return[out] dest constructed mat4s from raw pointers - */ -CGLM_INLINE -mat4s -glms_mat2x4_(mul)(mat2x4s m1, mat4x2s m2) { - mat4s dest; - glm_mat2x4_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x4s (m) by vec2s (v) and store in vec4s (dest). - * - * @param[in] m mat2x4s (left) - * @param[in] v vec2s (right, column vector) - * @return[out] dest constructed vec4s from raw pointers - */ -CGLM_INLINE -vec4s -glms_mat2x4_(mulv)(mat2x4s m, vec2s v) { - vec4s dest; - glm_mat2x4_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat2x4s (m) and store in mat4x2s (dest). - * - * @param[in] m mat2x4s (left) - * @return[out] dest constructed mat4x2s from raw pointers - */ -CGLM_INLINE -mat4x2s -glms_mat2x4_(transpose)(mat2x4s m) { - mat4x2s dest; - glm_mat2x4_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat2x4s (m) by scalar constant (s). - * - * @param[in, out] m mat2x4s (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat2x4s -glms_mat2x4_(scale)(mat2x4s m, float s) { - glm_mat2x4_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat2x4_h */ diff --git a/external/cglm/struct/mat3.h b/external/cglm/struct/mat3.h deleted file mode 100644 index 2fae073..0000000 --- a/external/cglm/struct/mat3.h +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT3_IDENTITY_INIT - GLMS_MAT3_ZERO_INIT - GLMS_MAT3_IDENTITY - GLMS_MAT3_ZERO - - Functions: - CGLM_INLINE mat3s glms_mat3_copy(mat3s mat); - CGLM_INLINE mat3s glms_mat3_identity(void); - CGLM_INLINE void glms_mat3_identity_array(mat3s * __restrict mat, size_t count); - CGLM_INLINE mat3s glms_mat3_zero(void); - CGLM_INLINE mat3s glms_mat3_mul(mat3s m1, mat3s m2); - CGLM_INLINE ma3s glms_mat3_transpose(mat3s m); - CGLM_INLINE vec3s glms_mat3_mulv(mat3s m, vec3s v); - CGLM_INLINE float glms_mat3_trace(mat3s m); - CGLM_INLINE versor glms_mat3_quat(mat3s m); - CGLM_INLINE mat3s glms_mat3_scale(mat3s m, float s); - CGLM_INLINE float glms_mat3_det(mat3s mat); - CGLM_INLINE mat3s glms_mat3_inv(mat3s mat); - CGLM_INLINE mat3s glms_mat3_swap_col(mat3s mat, int col1, int col2); - CGLM_INLINE mat3s glms_mat3_swap_row(mat3s mat, int row1, int row2); - CGLM_INLINE float glms_mat3_rmc(vec3s r, mat3s m, vec3s c); - CGLM_INLINE mat3s glms_mat3_make(const float * __restrict src); - CGLM_INLINE mat3s glms_mat3_textrans(float sx, float sy, float rot, float tx, float ty); - */ - -#ifndef cglms_mat3s_h -#define cglms_mat3s_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat3.h" -#include "vec3.h" - -/* api definition */ -#define glms_mat3_(NAME) CGLM_STRUCTAPI(mat3, NAME) - -#define GLMS_MAT3_IDENTITY_INIT {GLM_MAT3_IDENTITY_INIT} -#define GLMS_MAT3_ZERO_INIT {GLM_MAT3_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT3_IDENTITY ((mat3s)GLMS_MAT3_IDENTITY_INIT) -#define GLMS_MAT3_ZERO ((mat3s)GLMS_MAT3_ZERO_INIT) - -/*! - * @brief copy all members of [mat] to [dest] - * - * @param[in] mat source - * @returns destination - */ -CGLM_INLINE -mat3s -glms_mat3_(copy)(mat3s mat) { - mat3s r; - glm_mat3_copy(mat.raw, r.raw); - return r; -} - -/*! - * @brief make given matrix identity. It is identical with below, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat3_identity(aStruct->aMatrix); - * - * @code - * glm_mat3_copy(GLM_MAT3_IDENTITY, mat); // C only - * - * // or - * mat3 mat = GLM_MAT3_IDENTITY_INIT; - * @endcode - * - * @returns destination - */ -CGLM_INLINE -mat3s -glms_mat3_(identity)(void) { - mat3s r; - glm_mat3_identity(r.raw); - return r; -} - -/*! - * @brief make given matrix array's each element identity matrix - * - * @param[in, out] mat matrix array (must be aligned (16/32) - * if alignment is not disabled) - * - * @param[in] count count of matrices - */ -CGLM_INLINE -void -glms_mat3_(identity_array)(mat3s * __restrict mat, size_t count) { - CGLM_ALIGN_MAT mat3s t = GLMS_MAT3_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat3_copy(t.raw, mat[i].raw); - } -} - -/*! - * @brief make given matrix zero. - * - * @returns matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(zero)(void) { - mat3s r; - glm_mat3_zero(r.raw); - return r; -} - -/*! - * @brief multiply m1 and m2 to dest - * - * m1, m2 and dest matrices can be same matrix, it is possible to write this: - * - * @code - * mat3 m = GLM_MAT3_IDENTITY_INIT; - * r = glms_mat3_mul(m, m); - * @endcode - * - * @param[in] m1 left matrix - * @param[in] m2 right matrix - * @returns destination matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(mul)(mat3s m1, mat3s m2) { - mat3s r; - glm_mat3_mul(m1.raw, m2.raw, r.raw); - return r; -} - -/*! - * @brief transpose mat3 and store result in same matrix - * - * @param[in, out] m source and dest - */ -CGLM_INLINE -mat3s -glms_mat3_(transpose)(mat3s m) { - glm_mat3_transpose(m.raw); - return m; -} - -/*! - * @brief multiply mat3 with vec3 (column vector) and store in dest vector - * - * @param[in] m mat3 (left) - * @param[in] v vec3 (right, column vector) - * @returns vec3 (result, column vector) - */ -CGLM_INLINE -vec3s -glms_mat3_(mulv)(mat3s m, vec3s v) { - vec3s r; - glm_mat3_mulv(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief trace of matrix - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glms_mat3_(trace)(mat3s m) { - return glm_mat3_trace(m.raw); -} - -/*! - * @brief convert mat3 to quaternion - * - * @param[in] m rotation matrix - * @returns destination quaternion - */ -CGLM_INLINE -versors -glms_mat3_(quat)(mat3s m) { - versors r; - glm_mat3_quat(m.raw, r.raw); - return r; -} - -/*! - * @brief scale (multiply with scalar) matrix - * - * multiply matrix with scalar - * - * @param[in] m matrix - * @param[in] s scalar - * @returns scaled matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(scale)(mat3s m, float s) { - glm_mat3_scale(m.raw, s); - return m; -} - -/*! - * @brief mat3 determinant - * - * @param[in] mat matrix - * - * @return determinant - */ -CGLM_INLINE -float -glms_mat3_(det)(mat3s mat) { - return glm_mat3_det(mat.raw); -} - -/*! - * @brief inverse mat3 and store in dest - * - * @param[in] mat matrix - * @returns inverse matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(inv)(mat3s mat) { - mat3s r; - glm_mat3_inv(mat.raw, r.raw); - return r; -} - -/*! - * @brief swap two matrix columns - * - * @param[in] mat matrix - * @param[in] col1 col1 - * @param[in] col2 col2 - * @returns matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(swap_col)(mat3s mat, int col1, int col2) { - glm_mat3_swap_col(mat.raw, col1, col2); - return mat; -} - -/*! - * @brief swap two matrix rows - * - * @param[in] mat matrix - * @param[in] row1 row1 - * @param[in] row2 row2 - * @returns matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(swap_row)(mat3s mat, int row1, int row2) { - glm_mat3_swap_row(mat.raw, row1, row2); - return mat; -} - -/*! - * @brief helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because R * M = Matrix1x3 (row vector), - * then Matrix1x3 * Vec3 (column vector) = Matrix1x1 (Scalar) - * - * @param[in] r row vector or matrix1x3 - * @param[in] m matrix3x3 - * @param[in] c column vector or matrix3x1 - * - * @return scalar value e.g. Matrix1x1 - */ -CGLM_INLINE -float -glms_mat3_(rmc)(vec3s r, mat3s m, vec3s c) { - return glm_mat3_rmc(r.raw, m.raw, c.raw); -} - -/*! - * @brief Create mat3 matrix from pointer - * - * @param[in] src pointer to an array of floats - * @return constructed matrix from raw pointer - */ -CGLM_INLINE -mat3s -glms_mat3_(make)(const float * __restrict src) { - mat3s r; - glm_mat3_make(src, r.raw); - return r; -} - -/*! - * @brief Create mat3 matrix from texture transform parameters - * - * @param[in] sx scale x - * @param[in] sy scale y - * @param[in] rot rotation in radians CCW/RH - * @param[in] tx translate x - * @param[in] ty translate y - * @return texture transform matrix - */ -CGLM_INLINE -mat3s -glms_mat3_(textrans)(float sx, float sy, float rot, float tx, float ty) { - mat3s r; - glm_mat3_textrans(sx, sy, rot, tx, ty, r.raw); - return r; -} - -#endif /* cglms_mat3s_h */ diff --git a/external/cglm/struct/mat3x2.h b/external/cglm/struct/mat3x2.h deleted file mode 100644 index ab2d388..0000000 --- a/external/cglm/struct/mat3x2.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT3X2_ZERO_INIT - GLMS_MAT3X2_ZERO - - Functions: - CGLM_INLINE mat3x2s glms_mat3x2_zero(void); - CGLM_INLINE mat3x2s glms_mat3x2_make(const float * __restrict src); - CGLM_INLINE mat2s glms_mat3x2_mul(mat3x2s m1, mat2x3s m2); - CGLM_INLINE vec2s glms_mat3x2_mulv(mat3x2s m, vec3s v); - CGLM_INLINE mat2x3s glms_mat3x2_transpose(mat3x2s m); - CGLM_INLINE mat3x2s glms_mat3x2_scale(mat3x2s m, float s); - */ - -#ifndef cglms_mat3x2_h -#define cglms_mat3x2_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat3x2.h" - -/* api definition */ -#define glms_mat3x2_(NAME) CGLM_STRUCTAPI(mat3x2, NAME) - -#define GLMS_MAT3X2_ZERO_INIT {GLM_MAT3X2_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT3X2_ZERO ((mat3x2s)GLMS_MAT3X2_ZERO_INIT) - -/*! - * @brief Zero out the mat3x2s (dest). - * - * @return[out] dest constructed mat3x2s from raw pointer - */ -CGLM_INLINE -mat3x2s -glms_mat3x2_(zero)(void) { - mat3x2s dest; - glm_mat3x2_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat3x2s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat3x2s from raw pointer - */ -CGLM_INLINE -mat3x2s -glms_mat3x2_(make)(const float * __restrict src) { - mat3x2s dest; - glm_mat3x2_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x2s (m1) by mat2x3s (m2) and store in mat2s (dest). - * - * @code - * r = glms_mat3x2_mul(mat3x2s, mat2x3s); - * @endcode - * - * @param[in] m1 mat3x2s (left) - * @param[in] m2 mat2x3s (right) - * @return[out] dest constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat3x2_(mul)(mat3x2s m1, mat2x3s m2) { - mat2s dest; - glm_mat3x2_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x2s (m) by vec3s (v) and store in vec2s (dest). - * - * @param[in] m mat3x2s (left) - * @param[in] v vec3s (right, column vector) - * @return[out] dest constructed vec2s from raw pointers - */ -CGLM_INLINE -vec2s -glms_mat3x2_(mulv)(mat3x2s m, vec3s v) { - vec2s dest; - glm_mat3x2_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat3x2s (m) and store in mat2x3s (dest). - * - * @param[in] m mat3x2s (left) - * @return[out] dest constructed mat2x3s from raw pointers - */ -CGLM_INLINE -mat2x3s -glms_mat3x2_(transpose)(mat3x2s m) { - mat2x3s dest; - glm_mat3x2_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x2s (m) by scalar constant (s). - * - * @param[in, out] m mat3x2s (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat3x2s -glms_mat3x2_(scale)(mat3x2s m, float s) { - glm_mat3x2_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat3x2_h */ diff --git a/external/cglm/struct/mat3x4.h b/external/cglm/struct/mat3x4.h deleted file mode 100644 index 436b36c..0000000 --- a/external/cglm/struct/mat3x4.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT3X4_ZERO_INIT - GLMS_MAT3X4_ZERO - - Functions: - CGLM_INLINE mat3x4s glms_mat3x4_zero(void); - CGLM_INLINE mat3x4s glms_mat3x4_make(const float * __restrict src); - CGLM_INLINE mat4s glms_mat3x4_mul(mat3x4s m1, mat4x3s m2); - CGLM_INLINE vec4s glms_mat3x4_mulv(mat3x4s m, vec3s v); - CGLM_INLINE mat4x3s glms_mat3x4_transpose(mat3x4s m); - CGLM_INLINE mat3x4s glms_mat3x4_scale(mat3x4s m, float s); - */ - -#ifndef cglms_mat3x4_h -#define cglms_mat3x4_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat3x4.h" - -/* api definition */ -#define glms_mat3x4_(NAME) CGLM_STRUCTAPI(mat3x4, NAME) - -#define GLMS_MAT3X4_ZERO_INIT {GLM_MAT3X4_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT3X4_ZERO ((mat3x4s)GLMS_MAT3X4_ZERO_INIT) - -/*! - * @brief Zero out the mat3x4s (dest). - * - * @return[out] dest constructed mat3x4s from raw pointer - */ -CGLM_INLINE -mat3x4s -glms_mat3x4_(zero)(void) { - mat3x4s dest; - glm_mat3x4_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat3x4s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat3x4s from raw pointer - */ -CGLM_INLINE -mat3x4s -glms_mat3x4_(make)(const float * __restrict src) { - mat3x4s dest; - glm_mat3x4_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x4s (m1) by mat4x3s (m2) and store in mat4s (dest). - * - * @code - * r = glms_mat3x4_mul(mat3x4s, mat4x3s); - * @endcode - * - * @param[in] m1 mat3x4s (left) - * @param[in] m2 mat4x3s (right) - * @return[out] dest constructed mat4s from raw pointers - */ -CGLM_INLINE -mat4s -glms_mat3x4_(mul)(mat3x4s m1, mat4x3s m2) { - mat4s dest; - glm_mat3x4_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x4s (m) by vec3s (v) and store in vec4s (dest). - * - * @param[in] m mat3x4s (left) - * @param[in] v vec3s (right, column vector) - * @return[out] dest constructed vec4s from raw pointers - */ -CGLM_INLINE -vec4s -glms_mat3x4_(mulv)(mat3x4s m, vec3s v) { - vec4s dest; - glm_mat3x4_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat3x4s (m) and store in mat4x3s (dest). - * - * @param[in] m mat3x4s (left) - * @return[out] dest constructed mat4x3s from raw pointers - */ -CGLM_INLINE -mat4x3s -glms_mat3x4_(transpose)(mat3x4s m) { - mat4x3s dest; - glm_mat3x4_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat3x4s (m) by scalar constant (s). - * - * @param[in, out] m mat3x4s (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat3x4s -glms_mat3x4_(scale)(mat3x4s m, float s) { - glm_mat3x4_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat3x4_h */ diff --git a/external/cglm/struct/mat4.h b/external/cglm/struct/mat4.h deleted file mode 100644 index 663a5fd..0000000 --- a/external/cglm/struct/mat4.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * Most of functions in this header are optimized manually with SIMD - * if available. You dont need to call/incude SIMD headers manually - */ - -/* - Macros: - GLMS_MAT4_IDENTITY_INIT - GLMS_MAT4_ZERO_INIT - GLMS_MAT4_IDENTITY - GLMS_MAT4_ZERO - - Functions: - CGLM_INLINE mat4s glms_mat4_ucopy(mat4s mat); - CGLM_INLINE mat4s glms_mat4_copy(mat4s mat); - CGLM_INLINE mat4s glms_mat4_identity(void); - CGLM_INLINE void glms_mat4_identity_array(mat4s * __restrict mat, size_t count); - CGLM_INLINE mat4s glms_mat4_zero(void); - CGLM_INLINE mat3s glms_mat4_pick3(mat4s mat); - CGLM_INLINE mat3s glms_mat4_pick3t(mat4s mat); - CGLM_INLINE mat4s glms_mat4_ins3(mat3s mat, mat4s dest); - CGLM_INLINE mat4s glms_mat4_mul(mat4s m1, mat4s m2); - CGLM_INLINE mat4s glms_mat4_mulN(mat4s * __restrict matrices[], uint32_t len); - CGLM_INLINE vec4s glms_mat4_mulv(mat4s m, vec4s v); - CGLM_INLINE float glms_mat4_trace(mat4s m); - CGLM_INLINE float glms_mat4_trace3(mat4s m); - CGLM_INLINE versors glms_mat4_quat(mat4s m); - CGLM_INLINE vec3s glms_mat4_mulv3(mat4s m, vec3s v, float last); - CGLM_INLINE mat4s glms_mat4_transpose(mat4s m); - CGLM_INLINE mat4s glms_mat4_scale_p(mat4s m, float s); - CGLM_INLINE mat4s glms_mat4_scale(mat4s m, float s); - CGLM_INLINE float glms_mat4_det(mat4s mat); - CGLM_INLINE mat4s glms_mat4_inv(mat4s mat); - CGLM_INLINE mat4s glms_mat4_inv_fast(mat4s mat); - CGLM_INLINE mat4s glms_mat4_swap_col(mat4s mat, int col1, int col2); - CGLM_INLINE mat4s glms_mat4_swap_row(mat4s mat, int row1, int row2); - CGLM_INLINE float glms_mat4_rmc(vec4s r, mat4s m, vec4s c); - CGLM_INLINE mat4s glms_mat4_make(const float * __restrict src); - CGLM_INLINE mat4s glms_mat4_textrans(float sx, float sy, float rot, float tx, float ty); - */ - -#ifndef cglms_mat4s_h -#define cglms_mat4s_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat4.h" -#include "vec4.h" -#include "vec3.h" - -/* api definition */ -#define glms_mat4_(NAME) CGLM_STRUCTAPI(mat4, NAME) - -#define GLMS_MAT4_IDENTITY_INIT {GLM_MAT4_IDENTITY_INIT} -#define GLMS_MAT4_ZERO_INIT {GLM_MAT4_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT4_IDENTITY ((mat4s)GLMS_MAT4_IDENTITY_INIT) -#define GLMS_MAT4_ZERO ((mat4s)GLMS_MAT4_ZERO_INIT) - -/*! - * @brief copy all members of [mat] to [dest] - * - * matrix may not be aligned, u stands for unaligned, this may be useful when - * copying a matrix from external source e.g. asset importer... - * - * @param[in] mat source - * @returns destination - */ -CGLM_INLINE -mat4s -glms_mat4_(ucopy)(mat4s mat) { - mat4s r; - glm_mat4_ucopy(mat.raw, r.raw); - return r; -} - -/*! - * @brief copy all members of [mat] to [dest] - * - * @param[in] mat source - * @returns destination - */ -CGLM_INLINE -mat4s -glms_mat4_(copy)(mat4s mat) { - mat4s r; - glm_mat4_copy(mat.raw, r.raw); - return r; -} - -/*! - * @brief make given matrix identity. It is identical with below, - * but it is more easy to do that with this func especially for members - * e.g. glm_mat4_identity(aStruct->aMatrix); - * - * @code - * glm_mat4_copy(GLM_MAT4_IDENTITY, mat); // C only - * - * // or - * mat4 mat = GLM_MAT4_IDENTITY_INIT; - * @endcode - * - * @returns destination - */ -CGLM_INLINE -mat4s -glms_mat4_(identity)(void) { - mat4s r; - glm_mat4_identity(r.raw); - return r; -} - -/*! - * @brief make given matrix array's each element identity matrix - * - * @param[in, out] mat matrix array (must be aligned (16/32) - * if alignment is not disabled) - * - * @param[in] count count of matrices - */ -CGLM_INLINE -void -glms_mat4_(identity_array)(mat4s * __restrict mat, size_t count) { - CGLM_ALIGN_MAT mat4s t = GLMS_MAT4_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_mat4_copy(t.raw, mat[i].raw); - } -} - -/*! - * @brief make given matrix zero. - * - * @returns matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(zero)(void) { - mat4s r; - glm_mat4_zero(r.raw); - return r; -} - -/*! - * @brief copy upper-left of mat4 to mat3 - * - * @param[in] mat source - * @returns destination - */ -CGLM_INLINE -mat3s -glms_mat4_(pick3)(mat4s mat) { - mat3s r; - glm_mat4_pick3(mat.raw, r.raw); - return r; -} - -/*! - * @brief copy upper-left of mat4 to mat3 (transposed) - * - * the postfix t stands for transpose - * - * @param[in] mat source - * @returns destination - */ -CGLM_INLINE -mat3s -glms_mat4_(pick3t)(mat4s mat) { - mat3s r; - glm_mat4_pick3t(mat.raw, r.raw); - return r; -} - -/*! - * @brief copy mat3 to mat4's upper-left - * - * @param[in] mat source - * @param[in] dest destination - * @returns destination - */ -CGLM_INLINE -mat4s -glms_mat4_(ins3)(mat3s mat, mat4s dest) { - glm_mat4_ins3(mat.raw, dest.raw); - return dest; -} - -/*! - * @brief multiply m1 and m2 to dest - * - * m1, m2 and dest matrices can be same matrix, it is possible to write this: - * - * @code - * mat4 m = GLM_MAT4_IDENTITY_INIT; - * r = glms_mat4_mul(m, m); - * @endcode - * - * @param[in] m1 left matrix - * @param[in] m2 right matrix - * @returns destination matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(mul)(mat4s m1, mat4s m2) { - mat4s r; - glm_mat4_mul(m1.raw, m2.raw, r.raw); - return r; -} - -/*! - * @brief mupliply N mat4 matrices and store result in dest - * - * this function lets you multiply multiple (more than two or more...) matrices - *

multiplication will be done in loop, this may reduce instructions - * size but if len is too small then compiler may unroll whole loop, - * usage: - * @code - * mat4 m1, m2, m3, m4, res; - * - * res = glm_mat4_mulN((mat4 *[]){&m1, &m2, &m3, &m4}, 4); - * @endcode - * - * @warning matrices parameter is pointer array not mat4 array! - * - * @param[in] matrices mat4 * array - * @param[in] len matrices count - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(mulN)(mat4s * __restrict matrices[], uint32_t len) { - CGLM_ALIGN_MAT mat4s r = GLMS_MAT4_IDENTITY_INIT; - size_t i; - - for (i = 0; i < len; i++) { - r = glms_mat4_(mul)(r, *matrices[i]); - } - - return r; -} - -/*! - * @brief multiply mat4 with vec4 (column vector) and store in dest vector - * - * @param[in] m mat4 (left) - * @param[in] v vec4 (right, column vector) - * @returns vec4 (result, column vector) - */ -CGLM_INLINE -vec4s -glms_mat4_(mulv)(mat4s m, vec4s v) { - vec4s r; - glm_mat4_mulv(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief trace of matrix - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glms_mat4_(trace)(mat4s m) { - return glm_mat4_trace(m.raw); -} - -/*! - * @brief trace of matrix (rotation part) - * - * sum of the elements on the main diagonal from upper left to the lower right - * - * @param[in] m matrix - */ -CGLM_INLINE -float -glms_mat4_(trace3)(mat4s m) { - return glm_mat4_trace3(m.raw); -} - -/*! - * @brief convert mat4's rotation part to quaternion - * - * @param[in] m affine matrix - * @returns destination quaternion - */ -CGLM_INLINE -versors -glms_mat4_(quat)(mat4s m) { - versors r; - glm_mat4_quat(m.raw, r.raw); - return r; -} - -/*! - * @brief multiply vector with mat4 - * - * @param[in] m mat4(affine transform) - * @param[in] v vec3 - * @param[in] last 4th item to make it vec4 - * @returns result vector (vec3) - */ -CGLM_INLINE -vec3s -glms_mat4_(mulv3)(mat4s m, vec3s v, float last) { - vec3s r; - glm_mat4_mulv3(m.raw, v.raw, last, r.raw); - return r; -} - -/*! - * @brief transpose mat4 and store result in same matrix - * - * @param[in] m source - * @returns result - */ -CGLM_INLINE -mat4s -glms_mat4_(transpose)(mat4s m) { - glm_mat4_transpose(m.raw); - return m; -} - -/*! - * @brief scale (multiply with scalar) matrix without simd optimization - * - * multiply matrix with scalar - * - * @param[in] m matrix - * @param[in] s scalar - * @returns matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(scale_p)(mat4s m, float s) { - glm_mat4_scale_p(m.raw, s); - return m; -} - -/*! - * @brief scale (multiply with scalar) matrix - * - * multiply matrix with scalar - * - * @param[in] m matrix - * @param[in] s scalar - * @returns matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(scale)(mat4s m, float s) { - glm_mat4_scale(m.raw, s); - return m; -} - -/*! - * @brief mat4 determinant - * - * @param[in] mat matrix - * - * @return determinant - */ -CGLM_INLINE -float -glms_mat4_(det)(mat4s mat) { - return glm_mat4_det(mat.raw); -} - -/*! - * @brief inverse mat4 and store in dest - * - * @param[in] mat matrix - * @returns inverse matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(inv)(mat4s mat) { - mat4s r; - glm_mat4_inv(mat.raw, r.raw); - return r; -} - -/*! - * @brief inverse mat4 and store in dest - * - * this func uses reciprocal approximation without extra corrections - * e.g Newton-Raphson. this should work faster than normal, - * to get more precise use glm_mat4_inv version. - * - * NOTE: You will lose precision, glm_mat4_inv is more accurate - * - * @param[in] mat matrix - * @returns inverse matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(inv_fast)(mat4s mat) { - mat4s r; - glm_mat4_inv_fast(mat.raw, r.raw); - return r; -} - -/*! - * @brief swap two matrix columns - * - * @param[in] mat matrix - * @param[in] col1 col1 - * @param[in] col2 col2 - * @returns matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(swap_col)(mat4s mat, int col1, int col2) { - glm_mat4_swap_col(mat.raw, col1, col2); - return mat; -} - -/*! - * @brief swap two matrix rows - * - * @param[in] mat matrix - * @param[in] row1 row1 - * @param[in] row2 row2 - * @returns matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(swap_row)(mat4s mat, int row1, int row2) { - glm_mat4_swap_row(mat.raw, row1, row2); - return mat; -} - -/*! - * @brief helper for R (row vector) * M (matrix) * C (column vector) - * - * rmc stands for Row * Matrix * Column - * - * the result is scalar because R * M = Matrix1x4 (row vector), - * then Matrix1x4 * Vec4 (column vector) = Matrix1x1 (Scalar) - * - * @param[in] r row vector or matrix1x4 - * @param[in] m matrix4x4 - * @param[in] c column vector or matrix4x1 - * - * @return scalar value e.g. B(s) - */ -CGLM_INLINE -float -glms_mat4_(rmc)(vec4s r, mat4s m, vec4s c) { - return glm_mat4_rmc(r.raw, m.raw, c.raw); -} - -/*! - * @brief Create mat4 matrix from pointer - * - * @param[in] src pointer to an array of floats - * @return constructed matrix from raw pointer - */ -CGLM_INLINE -mat4s -glms_mat4_(make)(const float * __restrict src) { - mat4s r; - glm_mat4_make(src, r.raw); - return r; -} - -/*! - * @brief Create mat4 matrix from texture transform parameters - * - * @param[in] sx scale x - * @param[in] sy scale y - * @param[in] rot rotation in radians CCW/RH - * @param[in] tx translate x - * @param[in] ty translate y - * @return texture transform matrix - */ -CGLM_INLINE -mat4s -glms_mat4_(textrans)(float sx, float sy, float rot, float tx, float ty) { - mat4s r; - glm_mat4_textrans(sx, sy, rot, tx, ty, r.raw); - return r; -} - -#endif /* cglms_mat4s_h */ diff --git a/external/cglm/struct/mat4x2.h b/external/cglm/struct/mat4x2.h deleted file mode 100644 index 6c68abe..0000000 --- a/external/cglm/struct/mat4x2.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT4X2_ZERO_INIT - GLMS_MAT4X2_ZERO - - Functions: - CGLM_INLINE mat4x2s glms_mat4x2_zero(void); - CGLM_INLINE mat4x2s glms_mat4x2_make(const float * __restrict src); - CGLM_INLINE mat2s glms_mat4x2_mul(mat4x2s m1, mat2x4s m2); - CGLM_INLINE vec2s glms_mat4x2_mulv(mat4x2s m, vec4s v); - CGLM_INLINE mat2x4s glms_mat4x2_transpose(mat4x2s m); - CGLM_INLINE mat4x2s glms_mat4x2_scale(mat4x2s m, float s); - */ - -#ifndef cglms_mat4x2_h -#define cglms_mat4x2_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat4x2.h" - -/* api definition */ -#define glms_mat4x2_(NAME) CGLM_STRUCTAPI(mat4x2, NAME) - -#define GLMS_MAT4X2_ZERO_INIT {GLM_MAT4X2_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT4X2_ZERO ((mat4x2s)GLMS_MAT4X2_ZERO_INIT) - - -/*! - * @brief Zero out the mat4x2s (dest). - * - * @return[out] dest constructed mat4x2s from raw pointer - */ -CGLM_INLINE -mat4x2s -glms_mat4x2_(zero)(void) { - mat4x2s dest; - glm_mat4x2_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat4x2s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat4x2s from raw pointer - */ -CGLM_INLINE -mat4x2s -glms_mat4x2_(make)(const float * __restrict src) { - mat4x2s dest; - glm_mat4x2_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x2s (m1) by mat2x4s (m2) and store in mat2s (dest). - * - * @code - * r = glms_mat4x2_mul(mat4x2s, mat2x4s); - * @endcode - * - * @param[in] m1 mat4x2s (left) - * @param[in] m2 mat2x4s (right) - * @return[out] dest constructed mat2s from raw pointers - */ -CGLM_INLINE -mat2s -glms_mat4x2_(mul)(mat4x2s m1, mat2x4s m2) { - mat2s dest; - glm_mat4x2_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x2s (m) by vec4s (v) and store in vec2s (dest). - * - * @param[in] m mat4x2s (left) - * @param[in] v vec4s (right, column vector) - * @return[out] dest constructed vec2s from raw pointers - */ -CGLM_INLINE -vec2s -glms_mat4x2_(mulv)(mat4x2s m, vec4s v) { - vec2s dest; - glm_mat4x2_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat4x2s (m) and store in mat2x4s (dest). - * - * @param[in] m mat4x2s (left) - * @return[out] dest constructed mat2x4s from raw pointers - */ -CGLM_INLINE -mat2x4s -glms_mat4x2_(transpose)(mat4x2s m) { - mat2x4s dest; - glm_mat4x2_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x2s (m) by scalar constant (s). - * - * @param[in, out] m mat4x2s (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat4x2s -glms_mat4x2_(scale)(mat4x2s m, float s) { - glm_mat4x2_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat4x2_h */ diff --git a/external/cglm/struct/mat4x3.h b/external/cglm/struct/mat4x3.h deleted file mode 100644 index b398f98..0000000 --- a/external/cglm/struct/mat4x3.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_MAT4X3_ZERO_INIT - GLMS_MAT4X3_ZERO - - Functions: - CGLM_INLINE mat4x3s glms_mat4x3_zero(void); - CGLM_INLINE mat4x3s glms_mat4x3_make(const float * __restrict src); - CGLM_INLINE mat3s glms_mat4x3_mul(mat4x3s m1, mat3x4s m2); - CGLM_INLINE vec3s glms_mat4x3_mulv(mat4x3s m, vec4s v); - CGLM_INLINE mat3x4s glms_mat4x3_transpose(mat4x3s m); - CGLM_INLINE mat4x3s glms_mat4x3_scale(mat4x3s m, float s); - */ - -#ifndef cglms_mat4x3_h -#define cglms_mat4x3_h - -#include "../common.h" -#include "../types-struct.h" -#include "../mat4x3.h" - -/* api definition */ -#define glms_mat4x3_(NAME) CGLM_STRUCTAPI(mat4x3, NAME) - -#define GLMS_MAT4X3_ZERO_INIT {GLM_MAT4X3_ZERO_INIT} - -/* for C only */ -#define GLMS_MAT4X3_ZERO ((mat4x3s)GLMS_MAT4X3_ZERO_INIT) - -/*! - * @brief Zero out the mat4x3s (dest). - * - * @return[out] dest constructed mat4x3s from raw pointer - */ -CGLM_INLINE -mat4x3s -glms_mat4x3_(zero)(void) { - mat4x3s dest; - glm_mat4x3_zero(dest.raw); - return dest; -} - -/*! - * @brief Create mat4x3s (dest) from pointer (src). - * - * @param[in] src pointer to an array of floats - * @return[out] dest constructed mat4x3s from raw pointer - */ -CGLM_INLINE -mat4x3s -glms_mat4x3_(make)(const float * __restrict src) { - mat4x3s dest; - glm_mat4x3_make(src, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x3s (m1) by mat3x4s (m2) and store in mat3s (dest). - * - * @code - * r = glms_mat4x3_mul(mat4x3s, mat3x4s); - * @endcode - * - * @param[in] m1 mat4x3s (left) - * @param[in] m2 mat3x4s (right) - * @return[out] dest constructed mat3s from raw pointers - */ -CGLM_INLINE -mat3s -glms_mat4x3_(mul)(mat4x3s m1, mat3x4s m2) { - mat3s dest; - glm_mat4x3_mul(m1.raw, m2.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x3s (m) by vec4s (v) and store in vec3s (dest). - * - * @param[in] m mat4x3s (left) - * @param[in] v vec4s (right, column vector) - * @return[out] dest constructed vec3s from raw pointers - */ -CGLM_INLINE -vec3s -glms_mat4x3_(mulv)(mat4x3s m, vec4s v) { - vec3s dest; - glm_mat4x3_mulv(m.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief Transpose mat4x3s (m) and store in mat3x4s (dest). - * - * @param[in] m mat4x3s (left) - * @return[out] dest constructed mat3x4s from raw pointers - */ -CGLM_INLINE -mat3x4s -glms_mat4x3_(transpose)(mat4x3s m) { - mat3x4s dest; - glm_mat4x3_transpose(m.raw, dest.raw); - return dest; -} - -/*! - * @brief Multiply mat4x3s (m) by scalar constant (s). - * - * @param[in, out] m mat4x3s (src, dest) - * @param[in] s float (scalar) - */ -CGLM_INLINE -mat4x3s -glms_mat4x3_(scale)(mat4x3s m, float s) { - glm_mat4x3_scale(m.raw, s); - return m; -} - -#endif /* cglms_mat4x3_h */ diff --git a/external/cglm/struct/noise.h b/external/cglm/struct/noise.h deleted file mode 100644 index 3fd7d2e..0000000 --- a/external/cglm/struct/noise.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_noises_h -#define cglms_noises_h - -#include "../common.h" -#include "../types-struct.h" -#include "../noise.h" -#include "vec4.h" - -/* - Functions: - CGLM_INLINE float glms_perlin_vec4(vec4s point); - */ - -/*! - * @brief Classic perlin noise - * - * @param[in] point 4D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glms_perlin_vec4(vec4s point) { - return glm_perlin_vec4(point.raw); -} - -/*! - * @brief Classic perlin noise - * - * @param[in] point 3D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glms_perlin_vec3(vec3s point) { - return glm_perlin_vec3(point.raw); -} - -/*! - * @brief Classic perlin noise - * - * @param[in] point 2D vector - * @returns perlin noise value - */ -CGLM_INLINE -float -glms_perlin_vec2(vec2s point) { - return glm_perlin_vec2(point.raw); -} - -#endif /* cglms_noises_h */ diff --git a/external/cglm/struct/plane.h b/external/cglm/struct/plane.h deleted file mode 100644 index 6a84ac7..0000000 --- a/external/cglm/struct/plane.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_planes_h -#define cglms_planes_h - -#include "../common.h" -#include "../types-struct.h" -#include "../plane.h" -#include "vec4.h" - -/* - Plane equation: Ax + By + Cz + D = 0; - - It stored in vec4 as [A, B, C, D]. (A, B, C) is normal and D is distance -*/ - -/* - Functions: - CGLM_INLINE vec4s glms_plane_normalize(vec4s plane); - */ - -/*! - * @brief normalizes a plane - * - * @param[in] plane plane to normalize - * @returns normalized plane - */ -CGLM_INLINE -vec4s -glms_plane_normalize(vec4s plane) { - glm_plane_normalize(plane.raw); - return plane; -} - -#endif /* cglms_planes_h */ diff --git a/external/cglm/struct/project.h b/external/cglm/struct/project.h deleted file mode 100644 index 8383c77..0000000 --- a/external/cglm/struct/project.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_projects_h -#define cglms_projects_h - -#include "../common.h" -#include "../types-struct.h" -#include "../project.h" -#include "vec3.h" -#include "vec4.h" -#include "mat4.h" - -#ifndef CGLM_CLIPSPACE_INCLUDE_ALL -# if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT -# include "clipspace/project_zo.h" -# elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT -# include "clipspace/project_no.h" -# endif -#else -# include "clipspace/project_zo.h" -# include "clipspace/project_no.h" -#endif - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * if you don't have ( and don't want to have ) an inverse matrix then use - * glm_unproject version. You may use existing inverse of matrix in somewhere - * else, this is why glm_unprojecti exists to save save inversion cost - * - * [1] space: - * 1- if m = invProj: View Space - * 2- if m = invViewProj: World Space - * 3- if m = invMVP: Object Space - * - * You probably want to map the coordinates into object space - * so use invMVP as m - * - * Computing viewProj: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * glm_mat4_inv(viewProj, invMVP); - * - * @param[in] pos point/position in viewport coordinates - * @param[in] invMat matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @returns unprojected coordinates - */ -CGLM_INLINE -vec3s -glms_unprojecti(vec3s pos, mat4s invMat, vec4s vp) { - vec3s r; - glm_unprojecti(pos.raw, invMat.raw, vp.raw, r.raw); - return r; -} - -/*! - * @brief maps the specified viewport coordinates into specified space [1] - * the matrix should contain projection matrix. - * - * this is same as glm_unprojecti except this function get inverse matrix for - * you. - * - * [1] space: - * 1- if m = proj: View Space - * 2- if m = viewProj: World Space - * 3- if m = MVP: Object Space - * - * You probably want to map the coordinates into object space - * so use MVP as m - * - * Computing viewProj and MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * or in struct api: - * MVP = mat4_mul(mat4_mul(proj, view), model) - * - * @param[in] pos point/position in viewport coordinates - * @param[in] m matrix (see brief) - * @param[in] vp viewport as [x, y, width, height] - * @returns unprojected coordinates - */ -CGLM_INLINE -vec3s -glms_unproject(vec3s pos, mat4s m, vec4s vp) { - vec3s r; - glm_unproject(pos.raw, m.raw, vp.raw, r.raw); - return r; -} - -/*! - * @brief map object coordinates to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * or in struct api: - * MVP = mat4_mul(mat4_mul(proj, view), model) - * - * @param[in] pos object coordinates - * @param[in] m MVP matrix - * @param[in] vp viewport as [x, y, width, height] - * @returns projected coordinates - */ -CGLM_INLINE -vec3s -glms_project(vec3s pos, mat4s m, vec4s vp) { - vec3s r; - glm_project(pos.raw, m.raw, vp.raw, r.raw); - return r; -} - -/*! - * @brief map object's z coordinate to window coordinates - * - * Computing MVP: - * glm_mat4_mul(proj, view, viewProj); - * glm_mat4_mul(viewProj, model, MVP); - * - * or in struct api: - * MVP = mat4_mul(mat4_mul(proj, view), model) - * - * @param[in] v object coordinates - * @param[in] m MVP matrix - * - * @returns projected z coordinate - */ -CGLM_INLINE -float -glms_project_z(vec3s v, mat4s m) { -#if CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_ZO_BIT - return glms_project_z_zo(v, m); -#elif CGLM_CONFIG_CLIP_CONTROL & CGLM_CLIP_CONTROL_NO_BIT - return glms_project_z_no(v, m); -#endif -} - -/*! - * @brief define a picking region - * - * @param[in] center center [x, y] of a picking region in window coordinates - * @param[in] size size [width, height] of the picking region in window coordinates - * @param[in] vp viewport as [x, y, width, height] - * @returns projected coordinates - */ -CGLM_INLINE -mat4s -glms_pickmatrix(vec2s center, vec2s size, vec4s vp) { - mat4s res; - glm_pickmatrix(center.raw, size.raw, vp.raw, res.raw); - return res; -} - -#endif /* cglms_projects_h */ diff --git a/external/cglm/struct/quat.h b/external/cglm/struct/quat.h deleted file mode 100644 index d6789e4..0000000 --- a/external/cglm/struct/quat.h +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_QUAT_IDENTITY_INIT - GLMS_QUAT_IDENTITY - - Functions: - CGLM_INLINE versors glms_quat_identity(void) - CGLM_INLINE void glms_quat_identity_array(versor *q, size_t count) - CGLM_INLINE versors glms_quat_init(float x, float y, float z, float w) - CGLM_INLINE versors glms_quatv(float angle, vec3s axis) - CGLM_INLINE versors glms_quat(float angle, float x, float y, float z) - CGLM_INLINE versors glms_quat_from_vecs(vec3s a, vec3s b) - CGLM_INLINE float glms_quat_norm(versors q) - CGLM_INLINE versors glms_quat_normalize(versors q) - CGLM_INLINE float glms_quat_dot(versors p, versors q) - CGLM_INLINE versors glms_quat_conjugate(versors q) - CGLM_INLINE versors glms_quat_inv(versors q) - CGLM_INLINE versors glms_quat_add(versors p, versors q) - CGLM_INLINE versors glms_quat_sub(versors p, versors q) - CGLM_INLINE vec3s glms_quat_imagn(versors q) - CGLM_INLINE float glms_quat_imaglen(versors q) - CGLM_INLINE float glms_quat_angle(versors q) - CGLM_INLINE vec3s glms_quat_axis(versors q) - CGLM_INLINE versors glms_quat_mul(versors p, versors q) - CGLM_INLINE mat4s glms_quat_mat4(versors q) - CGLM_INLINE mat4s glms_quat_mat4t(versors q) - CGLM_INLINE mat3s glms_quat_mat3(versors q) - CGLM_INLINE mat3s glms_quat_mat3t(versors q) - CGLM_INLINE versors glms_quat_lerp(versors from, versors to, float t) - CGLM_INLINE versors glms_quat_lerpc(versors from, versors to, float t) - CGLM_INLINE versors glms_quat_nlerp(versors from, versors to, float t) - CGLM_INLINE versors glms_quat_slerp(versors from, versors to, float t) - CGLM_INLINE versors glms_quat_slerp_longest(versors from, versors to, float t) - CGLM_INLINE mat4s. glms_quat_look(vec3s eye, versors ori) - CGLM_INLINE versors glms_quat_for(vec3s dir, vec3s fwd, vec3s up) - CGLM_INLINE versors glms_quat_forp(vec3s from, vec3s to, vec3s fwd, vec3s up) - CGLM_INLINE vec3s glms_quat_rotatev(versors q, vec3s v) - CGLM_INLINE mat4s glms_quat_rotate(mat4s m, versors q) - CGLM_INLINE mat4s glms_quat_rotate_at(mat4s m, versors q, vec3s pivot) - CGLM_INLINE mat4s glms_quat_rotate_atm(versors q, vec3s pivot) - CGLM_INLINE versors glms_quat_make(float * restrict src) - */ - -#ifndef cglms_quat_h -#define cglms_quat_h - -#include "../common.h" -#include "../types-struct.h" -#include "../plane.h" -#include "../quat.h" - -/* api definition */ -#define glms_quat_(NAME) CGLM_STRUCTAPI(quat, NAME) - -/* - * IMPORTANT: - * ---------------------------------------------------------------------------- - * cglm stores quat as [x, y, z, w] since v0.3.6 - * - * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w] - * with v0.3.6 version. - * ---------------------------------------------------------------------------- - */ - -#define GLMS_QUAT_IDENTITY_INIT {GLM_QUAT_IDENTITY_INIT} -#define GLMS_QUAT_IDENTITY ((versors)GLMS_QUAT_IDENTITY_INIT) - -/*! - * @brief makes given quat to identity - * - * @returns identity quaternion - */ -CGLM_INLINE -versors -glms_quat_(identity)(void) { - versors dest; - glm_quat_identity(dest.raw); - return dest; -} - -/*! - * @brief make given quaternion array's each element identity quaternion - * - * @param[in, out] q quat array (must be aligned (16) - * if alignment is not disabled) - * - * @param[in] count count of quaternions - */ -CGLM_INLINE -void -glms_quat_(identity_array)(versors * __restrict q, size_t count) { - CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT; - size_t i; - - for (i = 0; i < count; i++) { - glm_vec4_copy(v, q[i].raw); - } -} - -/*! - * @brief inits quaternion with raw values - * - * @param[in] x x - * @param[in] y y - * @param[in] z z - * @param[in] w w (real part) - * @returns quaternion - */ -CGLM_INLINE -versors -glms_quat_(init)(float x, float y, float z, float w) { - versors dest; - glm_quat_init(dest.raw, x, y, z, w); - return dest; -} - -/*! - * @brief creates NEW quaternion with axis vector - * - * @param[in] angle angle (radians) - * @param[in] axis axis - * @returns quaternion - */ -CGLM_INLINE -versors -glms_quatv(float angle, vec3s axis) { - versors dest; - glm_quatv(dest.raw, angle, axis.raw); - return dest; -} - -/*! - * @brief creates NEW quaternion with individual axis components - * - * @param[in] angle angle (radians) - * @param[in] x axis.x - * @param[in] y axis.y - * @param[in] z axis.z - * @returns quaternion - */ -CGLM_INLINE -versors -glms_quat(float angle, float x, float y, float z) { - versors dest; - glm_quat(dest.raw, angle, x, y, z); - return dest; -} - -/*! - * @brief compute quaternion rotating vector A to vector B - * - * @param[in] a vec3 (must have unit length) - * @param[in] b vec3 (must have unit length) - * @returns quaternion (of unit length) - */ -CGLM_INLINE -versors -glms_quat_(from_vecs)(vec3s a, vec3s b) { - versors dest; - glm_quat_from_vecs(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief returns norm (magnitude) of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glms_quat_(norm)(versors q) { - return glm_quat_norm(q.raw); -} - -/*! - * @brief normalize quaternion - * - * @param[in] q quaternion - * @returns quaternion - */ -CGLM_INLINE -versors -glms_quat_(normalize)(versors q) { - versors dest; - glm_quat_normalize_to(q.raw, dest.raw); - return dest; -} - -/*! - * @brief dot product of two quaternion - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @returns dot product - */ -CGLM_INLINE -float -glms_quat_(dot)(versors p, versors q) { - return glm_quat_dot(p.raw, q.raw); -} - -/*! - * @brief conjugate of quaternion - * - * @param[in] q quaternion - * @returns conjugate - */ -CGLM_INLINE -versors -glms_quat_(conjugate)(versors q) { - versors dest; - glm_quat_conjugate(q.raw, dest.raw); - return dest; -} - -/*! - * @brief inverse of non-zero quaternion - * - * @param[in] q quaternion - * @returns inverse quaternion - */ -CGLM_INLINE -versors -glms_quat_(inv)(versors q) { - versors dest; - glm_quat_inv(q.raw, dest.raw); - return dest; -} - -/*! - * @brief add (componentwise) two quaternions and store result in dest - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(add)(versors p, versors q) { - versors dest; - glm_quat_add(p.raw, q.raw, dest.raw); - return dest; -} - -/*! - * @brief subtract (componentwise) two quaternions and store result in dest - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(sub)(versors p, versors q) { - versors dest; - glm_quat_sub(p.raw, q.raw, dest.raw); - return dest; -} - -/*! - * @brief returns normalized imaginary part of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -vec3s -glms_quat_(imagn)(versors q) { - vec3s dest; - glm_normalize_to(q.raw, dest.raw); - return dest; -} - -/*! - * @brief returns length of imaginary part of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glms_quat_(imaglen)(versors q) { - return glm_quat_imaglen(q.raw); -} - -/*! - * @brief returns angle of quaternion - * - * @param[in] q quaternion - */ -CGLM_INLINE -float -glms_quat_(angle)(versors q) { - return glm_quat_angle(q.raw); -} - -/*! - * @brief axis of quaternion - * - * @param[in] q quaternion - * @returns axis of quaternion - */ -CGLM_INLINE -vec3s -glms_quat_(axis)(versors q) { - vec3s dest; - glm_quat_axis(q.raw, dest.raw); - return dest; -} - -/*! - * @brief multiplies two quaternion and stores result in dest - * this is also called Hamilton Product - * - * According to WikiPedia: - * The product of two rotation quaternions [clarification needed] will be - * equivalent to the rotation q followed by the rotation p - * - * @param[in] p quaternion 1 - * @param[in] q quaternion 2 - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(mul)(versors p, versors q) { - versors dest; - glm_quat_mul(p.raw, q.raw, dest.raw); - return dest; -} - -/*! - * @brief convert quaternion to mat4 - * - * @param[in] q quaternion - * @returns result matrix - */ -CGLM_INLINE -mat4s -glms_quat_(mat4)(versors q) { - mat4s dest; - glm_quat_mat4(q.raw, dest.raw); - return dest; -} - -/*! - * @brief convert quaternion to mat4 (transposed) - * - * @param[in] q quaternion - * @returns result matrix as transposed - */ -CGLM_INLINE -mat4s -glms_quat_(mat4t)(versors q) { - mat4s dest; - glm_quat_mat4t(q.raw, dest.raw); - return dest; -} - -/*! - * @brief convert quaternion to mat3 - * - * @param[in] q quaternion - * @returns result matrix - */ -CGLM_INLINE -mat3s -glms_quat_(mat3)(versors q) { - mat3s dest; - glm_quat_mat3(q.raw, dest.raw); - return dest; -} - -/*! - * @brief convert quaternion to mat3 (transposed) - * - * @param[in] q quaternion - * @returns result matrix - */ -CGLM_INLINE -mat3s -glms_quat_(mat3t)(versors q) { - mat3s dest; - glm_quat_mat3t(q.raw, dest.raw); - return dest; -} - -/*! - * @brief interpolates between two quaternions - * using linear interpolation (LERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(lerp)(versors from, versors to, float t) { - versors dest; - glm_quat_lerp(from.raw, to.raw, t, dest.raw); - return dest; -} - -/*! - * @brief interpolates between two quaternions - * using linear interpolation (LERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(lerpc)(versors from, versors to, float t) { - versors dest; - glm_quat_lerpc(from.raw, to.raw, t, dest.raw); - return dest; -} - -/*! - * @brief interpolates between two quaternions - * taking the shortest rotation path using - * normalized linear interpolation (NLERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t interpolant (amount) - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(nlerp)(versors from, versors to, float t) { - versors dest; - glm_quat_nlerp(from.raw, to.raw, t, dest.raw); - return dest; -} - -/*! - * @brief interpolates between two quaternions - * using spherical linear interpolation (SLERP) - * - * @param[in] from from - * @param[in] to to - * @param[in] t amount - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(slerp)(versors from, versors to, float t) { - versors dest; - glm_quat_slerp(from.raw, to.raw, t, dest.raw); - return dest; -} - -/*! - * @brief interpolates between two quaternions - * using spherical linear interpolation (SLERP) and always takes the longest path - * - * @param[in] from from - * @param[in] to to - * @param[in] t amount - * @returns result quaternion - */ -CGLM_INLINE -versors -glms_quat_(slerp_longest)(versors from, versors to, float t) { - versors dest; - glm_quat_slerp_longest(from.raw, to.raw, t, dest.raw); - return dest; -} - -/*! - * @brief creates view matrix using quaternion as camera orientation - * - * @param[in] eye eye - * @param[in] ori orientation in world space as quaternion - * @returns view matrix - */ -CGLM_INLINE -mat4s -glms_quat_(look)(vec3s eye, versors ori) { - mat4s dest; - glm_quat_look(eye.raw, ori.raw, dest.raw); - return dest; -} - -/*! - * @brief creates look rotation quaternion - * - * @param[in] dir direction to look - * @param[in] up up vector - * @returns destination quaternion - */ -CGLM_INLINE -versors -glms_quat_(for)(vec3s dir, vec3s up) { - versors dest; - glm_quat_for(dir.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief creates look rotation quaternion using source and - * destination positions p suffix stands for position - * - * @param[in] from source point - * @param[in] to destination point - * @param[in] up up vector - * @returns destination quaternion - */ -CGLM_INLINE -versors -glms_quat_(forp)(vec3s from, vec3s to, vec3s up) { - versors dest; - glm_quat_forp(from.raw, to.raw, up.raw, dest.raw); - return dest; -} - -/*! - * @brief rotate vector using using quaternion - * - * @param[in] q quaternion - * @param[in] v vector to rotate - * @returns rotated vector - */ -CGLM_INLINE -vec3s -glms_quat_(rotatev)(versors q, vec3s v) { - vec3s dest; - glm_quat_rotatev(q.raw, v.raw, dest.raw); - return dest; -} - -/*! - * @brief rotate existing transform matrix using quaternion - * - * @param[in] m existing transform matrix - * @param[in] q quaternion - * @returns rotated matrix/transform - */ -CGLM_INLINE -mat4s -glms_quat_(rotate)(mat4s m, versors q) { - glm_quat_rotate(m.raw, q.raw, m.raw); - return m; -} - -/*! - * @brief rotate existing transform matrix using quaternion at pivot point - * - * @param[in, out] m existing transform matrix - * @param[in] q quaternion - * @returns pivot - */ -CGLM_INLINE -mat4s -glms_quat_(rotate_at)(mat4s m, versors q, vec3s pivot) { - glm_quat_rotate_at(m.raw, q.raw, pivot.raw); - return m; -} - -/*! - * @brief rotate NEW transform matrix using quaternion at pivot point - * - * this creates rotation matrix, it assumes you don't have a matrix - * - * this should work faster than glm_quat_rotate_at because it reduces - * one glm_translate. - * - * @param[in] q quaternion - * @returns pivot - */ -CGLM_INLINE -mat4s -glms_quat_(rotate_atm)(versors q, vec3s pivot) { - mat4s dest; - glm_quat_rotate_atm(dest.raw, q.raw, pivot.raw); - return dest; -} - -/*! - * @brief Create CGLM quaternion from pointer - * - * @param[in] src pointer to an array of floats - * @returns constructed quaternion from raw pointer - */ -CGLM_INLINE -versors -glms_quat_(make)(const float * __restrict src) { - versors dest; - glm_quat_make(src, dest.raw); - return dest; -} - -#endif /* cglms_quat_h */ diff --git a/external/cglm/struct/ray.h b/external/cglm/struct/ray.h deleted file mode 100644 index 10609b9..0000000 --- a/external/cglm/struct/ray.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_ray_h -#define cglms_ray_h - -#include "../common.h" -#include "../types-struct.h" -#include "../ray.h" - -/* api definition */ -#define glms_ray_(NAME) CGLM_STRUCTAPI(ray, NAME) - -/*! - * @brief Möller–Trumbore ray-triangle intersection algorithm - * - * @param[in] origin origin of ray - * @param[in] direction direction of ray - * @param[in] v0 first vertex of triangle - * @param[in] v1 second vertex of triangle - * @param[in] v2 third vertex of triangle - * @param[in, out] d distance to intersection - * @return whether there is intersection - */ -CGLM_INLINE -bool -glms_ray_(triangle)(vec3s origin, - vec3s direction, - vec3s v0, - vec3s v1, - vec3s v2, - float *d) { - return glm_ray_triangle(origin.raw, direction.raw, v0.raw, v1.raw, v2.raw, d); -} - -/*! - * @brief ray sphere intersection - * - * returns false if there is no intersection if true: - * - * - t1 > 0, t2 > 0: ray intersects the sphere at t1 and t2 both ahead of the origin - * - t1 < 0, t2 > 0: ray starts inside the sphere, exits at t2 - * - t1 < 0, t2 < 0: no intersection ahead of the ray ( returns false ) - * - the caller can check if the intersection points (t1 and t2) fall within a - * specific range (for example, tmin < t1, t2 < tmax) to determine if the - * intersections are within a desired segment of the ray - * - * @param[in] origin ray origin - * @param[out] dir normalized ray direction - * @param[in] s sphere [center.x, center.y, center.z, radii] - * @param[in] t1 near point1 (closer to origin) - * @param[in] t2 far point2 (farther from origin) - * - * @returns whether there is intersection - */ -CGLM_INLINE -bool -glms_ray_(sphere)(vec3s origin, - vec3s dir, - vec4s s, - float * __restrict t1, - float * __restrict t2) { - return glm_ray_sphere(origin.raw, dir.raw, s.raw, t1, t2); -} - -/*! - * @brief point using t by 𝐏(𝑡)=𝐀+𝑡𝐛 - * - * @param[in] orig origin of ray - * @param[in] dir direction of ray - * @param[in] t parameter - * @returns point point at t - */ -CGLM_INLINE -vec3s -glms_ray_(at)(vec3s orig, vec3s dir, float t) { - vec3s r; - glm_ray_at(orig.raw, dir.raw, t, r.raw); - return r; -} - -#endif /* cglms_ray_h */ diff --git a/external/cglm/struct/sphere.h b/external/cglm/struct/sphere.h deleted file mode 100644 index 9859c72..0000000 --- a/external/cglm/struct/sphere.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglms_spheres_h -#define cglms_spheres_h - -#include "../common.h" -#include "../types-struct.h" -#include "../sphere.h" -#include "mat4.h" - -/* - Sphere Representation in cglm: [center.x, center.y, center.z, radii] - - You could use this representation or you can convert it to vec4 before call - any function - */ - -/*! - * @brief helper for getting sphere radius - * - * @param[in] s sphere - * - * @return returns radii - */ -CGLM_INLINE -float -glms_sphere_radii(vec4s s) { - return glm_sphere_radii(s.raw); -} - -/*! - * @brief apply transform to sphere, it is just wrapper for glm_mat4_mulv3 - * - * @param[in] s sphere - * @param[in] m transform matrix - * @returns transformed sphere - */ -CGLM_INLINE -vec4s -glms_sphere_transform(vec4s s, mat4s m) { - vec4s r; - glm_sphere_transform(s.raw, m.raw, r.raw); - return r; -} - -/*! - * @brief merges two spheres and creates a new one - * - * two sphere must be in same space, for instance if one in world space then - * the other must be in world space too, not in local space. - * - * @param[in] s1 sphere 1 - * @param[in] s2 sphere 2 - * returns merged/extended sphere - */ -CGLM_INLINE -vec4s -glms_sphere_merge(vec4s s1, vec4s s2) { - vec4s r; - glm_sphere_merge(s1.raw, s2.raw, r.raw); - return r; -} - -/*! - * @brief check if two sphere intersects - * - * @param[in] s1 sphere - * @param[in] s2 other sphere - */ -CGLM_INLINE -bool -glms_sphere_sphere(vec4s s1, vec4s s2) { - return glm_sphere_sphere(s1.raw, s2.raw); -} - -/*! - * @brief check if sphere intersects with point - * - * @param[in] s sphere - * @param[in] point point - */ -CGLM_INLINE -bool -glms_sphere_point(vec4s s, vec3s point) { - return glm_sphere_point(s.raw, point.raw); -} - -#endif /* cglms_spheres_h */ diff --git a/external/cglm/struct/vec2-ext.h b/external/cglm/struct/vec2-ext.h deleted file mode 100644 index 246132f..0000000 --- a/external/cglm/struct/vec2-ext.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * @brief SIMD like functions - */ - -/* - Functions: - CGLM_INLINE vec2s glms_vec2_fill(float val) - CGLM_INLINE bool glms_vec2_eq(vec2s v, float val) - CGLM_INLINE bool glms_vec2_eq_eps(vec2s v, float val) - CGLM_INLINE bool glms_vec2_eq_all(vec2s v) - CGLM_INLINE bool glms_vec2_eqv(vec2s a, vec2s b) - CGLM_INLINE bool glms_vec2_eqv_eps(vec2s a, vec2s b) - CGLM_INLINE float glms_vec2_max(vec2s v) - CGLM_INLINE float glms_vec2_min(vec2s v) - CGLM_INLINE bool glms_vec2_isnan(vec2s v) - CGLM_INLINE bool glms_vec2_isinf(vec2s v) - CGLM_INLINE bool glms_vec2_isvalid(vec2s v) - CGLM_INLINE vec2s glms_vec2_sign(vec2s v) - CGLM_INLINE vec2s glms_vec2_abs(vec2s v) - CGLM_INLINE vec2s glms_vec2_fract(vec2s v) - CGLM_INLINE vec2s glms_vec2_floor(vec2s v) - CGLM_INLINE vec2s glms_vec2_mods(vec2s v, float s) - CGLM_INLINE vec2s glms_vec2_steps(float edge, vec2s v) - CGLM_INLINE vec2s glms_vec2_stepr(vec2s edge, float v) - CGLM_INLINE vec2s glms_vec2_sqrt(vec2s v) - */ - -#ifndef cglms_vec2s_ext_h -#define cglms_vec2s_ext_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec2-ext.h" - -/* api definition */ -#define glms_vec2_(NAME) CGLM_STRUCTAPI(vec2, NAME) - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @returns dest - */ -CGLM_INLINE -vec2s -glms_vec2_(fill)(float val) { - vec2s r; - glm_vec2_fill(r.raw, val); - return r; -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_vec2_(eq)(vec2s v, float val) { - return glm_vec2_eq(v.raw, val); -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_vec2_(eq_eps)(vec2s v, float val) { - return glm_vec2_eq_eps(v.raw, val); -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec2_(eq_all)(vec2s v) { - return glm_vec2_eq_all(v.raw); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_vec2_(eqv)(vec2s a, vec2s b) { - return glm_vec2_eqv(a.raw, b.raw); -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_vec2_(eqv_eps)(vec2s a, vec2s b) { - return glm_vec2_eqv_eps(a.raw, b.raw); -} - -/*! - * @brief max value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glms_vec2_(max)(vec2s v) { - return glm_vec2_max(v.raw); -} - -/*! - * @brief min value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glms_vec2_min(vec2s v) { - return glm_vec2_min(v.raw); -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec2_(isnan)(vec2s v) { - return glm_vec2_isnan(v.raw); -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec2_(isinf)(vec2s v) { - return glm_vec2_isinf(v.raw); -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec2_isvalid(vec2s v) { - return glm_vec2_isvalid(v.raw); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - * @returns sign vector - */ -CGLM_INLINE -vec2s -glms_vec2_(sign)(vec2s v) { - vec2s r; - glm_vec2_sign(v.raw, r.raw); - return r; -} - -/*! - * @brief fractional part of each vector item - * - * @param v vector - * @returns abs vector - */ -CGLM_INLINE -vec2s -glms_vec2_(abs)(vec2s v) { - vec2s r; - glm_vec2_abs(v.raw, r.raw); - return r; -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(fract)(vec2s v) { - vec2s r; - glm_vec2_fract(v.raw, r.raw); - return r; -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(floor)(vec2s v) { - vec2s r; - glm_vec2_floor(v.raw, r.raw); - return r; -} - -/*! - * @brief mod of each vector item by scalar - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(mods)(vec2s v, float s) { - vec2s r; - glm_vec2_mods(v.raw, s, r.raw); - return r; -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(steps)(float edge, vec2s x) { - vec2s r; - glm_vec2_steps(edge, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(stepr)(vec2s edge, float x) { - vec2s r; - glm_vec2_stepr(edge.raw, x, r.raw); - return r; -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(sqrt)(vec2s v) { - vec2s r; - glm_vec2_sqrt(v.raw, r.raw); - return r; -} - -/*! - * @brief treat vectors as complex numbers and multiply them as such. - * - * @param[in] a left number - * @param[in] b right number - * @param[out] dest destination number - */ -CGLM_INLINE -vec2s -glms_vec2_(complex_mul)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_complex_mul(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief treat vectors as complex numbers and divide them as such. - * - * @param[in] a left number (numerator) - * @param[in] b right number (denominator) - * @param[out] dest destination number - */ -CGLM_INLINE -vec2s -glms_vec2_(complex_div)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_complex_div(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief treat the vector as a complex number and conjugate it as such. - * - * @param[in] a the number - * @param[out] dest destination number - */ -CGLM_INLINE -vec2s -glms_vec2_(complex_conjugate)(vec2s a, vec2s dest) { - glm_vec2_complex_conjugate(a.raw, dest.raw); - return dest; -} - -#endif /* cglms_vec2s_ext_h */ diff --git a/external/cglm/struct/vec2.h b/external/cglm/struct/vec2.h deleted file mode 100644 index 40ed659..0000000 --- a/external/cglm/struct/vec2.h +++ /dev/null @@ -1,747 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_VEC2_ONE_INIT - GLMS_VEC2_ZERO_INIT - GLMS_VEC2_ONE - GLMS_VEC2_ZERO - - Functions: - CGLM_INLINE vec2s glms_vec2(vec3s v3) - CGLM_INLINE void glms_vec2_pack(vec2s dst[], vec2 src[], size_t len) - CGLM_INLINE void glms_vec2_unpack(vec2 dst[], vec2s src[], size_t len) - CGLM_INLINE vec2s glms_vec2_zero(void) - CGLM_INLINE vec2s glms_vec2_one(void) - CGLM_INLINE float glms_vec2_dot(vec2s a, vec2s b) - CGLM_INLINE float glms_vec2_cross(vec2s a, vec2s b) - CGLM_INLINE float glms_vec2_norm2(vec2s v) - CGLM_INLINE float glms_vec2_norm(vec2s v) - CGLM_INLINE vec2s glms_vec2_add(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_adds(vec2s a, float s) - CGLM_INLINE vec2s glms_vec2_sub(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_subs(vec2s a, float s) - CGLM_INLINE vec2s glms_vec2_mul(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_scale(vec2s v, float s) - CGLM_INLINE vec2s glms_vec2_scale_as(vec2s v, float s) - CGLM_INLINE vec2s glms_vec2_div(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_divs(vec2s a, float s) - CGLM_INLINE vec2s glms_vec2_addadd(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_subadd(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_muladd(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_muladds(vec2s a, float s, vec2s dest) - CGLM_INLINE vec2s glms_vec2_maxadd(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_minadd(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_subsub(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_addsub(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_mulsub(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_mulsubs(vec2s a, float s, vec2s dest) - CGLM_INLINE vec2s glms_vec2_maxsub(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_minsub(vec2s a, vec2s b, vec2s dest) - CGLM_INLINE vec2s glms_vec2_negate(vec2s v) - CGLM_INLINE vec2s glms_vec2_normalize(vec2s v) - CGLM_INLINE vec2s glms_vec2_rotate(vec2s v, float angle, vec2s axis) - CGLM_INLINE vec2s glms_vec2_center(vec2s a, vec2s b) - CGLM_INLINE float glms_vec2_distance(vec2s a, vec2s b) - CGLM_INLINE float glms_vec2_distance2(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_maxv(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_minv(vec2s a, vec2s b) - CGLM_INLINE vec2s glms_vec2_clamp(vec2s v, float minVal, float maxVal) - CGLM_INLINE vec2s glms_vec2_lerp(vec2s from, vec2s to, float t) - CGLM_INLINE vec2s glms_vec2_step(vec2s edge, vec2s x) - CGLM_INLINE vec2s glms_vec2_make(float * restrict src) - CGLM_INLINE vec2s glms_vec2_reflect(vec2s v, vec2s n) - CGLM_INLINE bool glms_vec2_refract(vec2s v, vec2s n, float eta, vec2s *dest) - */ - -#ifndef cglms_vec2s_h -#define cglms_vec2s_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec2.h" -#include "vec2-ext.h" - -#define GLMS_VEC2_ONE_INIT {GLM_VEC2_ONE_INIT} -#define GLMS_VEC2_ZERO_INIT {GLM_VEC2_ZERO_INIT} - -#define GLMS_VEC2_ONE ((vec2s)GLMS_VEC2_ONE_INIT) -#define GLMS_VEC2_ZERO ((vec2s)GLMS_VEC2_ZERO_INIT) - -/*! - * @brief init vec2 using vec2 - * - * @param[in] v3 vector3 - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2(vec3s v3) { - vec2s r; - glm_vec2(v3.raw, r.raw); - return r; -} - -/*! - * @brief pack an array of vec2 into an array of vec2s - * - * @param[out] dst array of vec2 - * @param[in] src array of vec2s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec2_(pack)(vec2s dst[], vec2 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec2_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of vec2s into an array of vec2 - * - * @param[out] dst array of vec2s - * @param[in] src array of vec2 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec2_(unpack)(vec2 dst[], vec2s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec2_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief make vector zero - * - * @returns zero vector - */ -CGLM_INLINE -vec2s -glms_vec2_(zero)(void) { - vec2s r; - glm_vec2_zero(r.raw); - return r; -} - -/*! - * @brief make vector one - * - * @returns one vector - */ -CGLM_INLINE -vec2s -glms_vec2_(one)(void) { - vec2s r; - glm_vec2_one(r.raw); - return r; -} - -/*! - * @brief vec2 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glms_vec2_(dot)(vec2s a, vec2s b) { - return glm_vec2_dot(a.raw, b.raw); -} - -/*! - * @brief vec2 cross product - * - * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return Z component of cross product - */ -CGLM_INLINE -float -glms_vec2_(cross)(vec2s a, vec2s b) { - return glm_vec2_cross(a.raw, b.raw); -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -float -glms_vec2_(norm2)(vec2s v) { - return glm_vec2_norm2(v.raw); -} - -/*! - * @brief norm (magnitude) of vec2 - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -float -glms_vec2_(norm)(vec2s v) { - return glm_vec2_norm(v.raw); -} - -/*! - * @brief add a vector to b vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(add)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + s) - * - * @param[in] a vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(adds)(vec2s a, float s) { - vec2s r; - glm_vec2_adds(a.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract b vector from a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(sub)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - s) - * - * @param[in] a vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(subs)(vec2s a, float s) { - vec2s r; - glm_vec2_subs(a.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a vector1 - * @param b vector2 - * @returns result = (a[0] * b[0], a[1] * b[1]) - */ -CGLM_INLINE -vec2s -glms_vec2_(mul)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply/scale vec2 vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(scale)(vec2s v, float s) { - vec2s r; - glm_vec2_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief make vec2 vector scale as specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec2s -glms_vec2_(scale_as)(vec2s v, float s) { - vec2s r; - glm_vec2_scale_as(v.raw, s, r.raw); - return r; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]/b[0], a[1]/b[1]) - */ -CGLM_INLINE -vec2s -glms_vec2_(div)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_div(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] a vector - * @param[in] s scalar - * @returns result = (a[0]/s, a[1]/s) - */ -CGLM_INLINE -vec2s -glms_vec2_(divs)(vec2s a, float s) { - vec2s r; - glm_vec2_divs(a.raw, s, r.raw); - return r; -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a + b) - */ -CGLM_INLINE -vec2s -glms_vec2_(addadd)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a + b) - */ -CGLM_INLINE -vec2s -glms_vec2_(subadd)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a * b) - */ -CGLM_INLINE -vec2s -glms_vec2_(muladd)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest += (a * b) - */ -CGLM_INLINE -vec2s -glms_vec2_(muladds)(vec2s a, float s, vec2s dest) { - glm_vec2_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += max(a, b) - */ -CGLM_INLINE -vec2s -glms_vec2_(maxadd)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += min(a, b) - */ -CGLM_INLINE -vec2s -glms_vec2_(minadd)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a - b) - */ -CGLM_INLINE -vec2s -glms_vec2_(subsub)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a + b) - */ -CGLM_INLINE -vec2s -glms_vec2_(addsub)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec2s -glms_vec2_(mulsub)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec2s -glms_vec2_(mulsubs)(vec2s a, float s, vec2s dest) { - glm_vec2_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief sub max of two vectors to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= max(a, b) - */ -CGLM_INLINE -vec2s -glms_vec2_(maxsub)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub min of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= min(a, b) - */ -CGLM_INLINE -vec2s -glms_vec2_(minsub)(vec2s a, vec2s b, vec2s dest) { - glm_vec2_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief negate vector components - * - * @param[in] v vector - * @returns negated vector - */ -CGLM_INLINE -vec2s -glms_vec2_(negate)(vec2s v) { - glm_vec2_negate(v.raw); - return v; -} - -/*! - * @brief normalize vec2 and store result in same vec - * - * @param[in] v vector - * @returns normalized vector - */ -CGLM_INLINE -vec2s -glms_vec2_(normalize)(vec2s v) { - glm_vec2_normalize(v.raw); - return v; -} - -/*! - * @brief rotate vec2 by angle using Rodrigues' rotation formula - * - * @param[in] v vector - * @param[in] angle angle by radians - * @returns rotated vector - */ -CGLM_INLINE -vec2s -glms_vec2_(rotate)(vec2s v, float angle) { - vec2s r; - glm_vec2_rotate(v.raw, angle, r.raw); - return r; -} - -/** - * @brief find center point of two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns center point - */ -CGLM_INLINE -vec2s -glms_vec2_(center)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_center(a.raw, b.raw, r.raw); - return r; -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return distance - */ -CGLM_INLINE -float -glms_vec2_(distance)(vec2s a, vec2s b) { - return glm_vec2_distance(a.raw, b.raw); -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return squared distance (distance * distance) - */ -CGLM_INLINE -float -glms_vec2_(distance2)(vec2s a, vec2s b) { - return glm_vec2_distance2(a.raw, b.raw); -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(maxv)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(minv)(vec2s a, vec2s b) { - vec2s r; - glm_vec2_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -vec2s -glms_vec2_(clamp)(vec2s v, float minVal, float maxVal) { - glm_vec2_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(lerp)(vec2s from, vec2s to, float t) { - vec2s r; - glm_vec2_lerp(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec2s -glms_vec2_(step)(vec2s edge, vec2s x) { - vec2s r; - glm_vec2_step(edge.raw, x.raw, r.raw); - return r; -} - -/*! - * @brief Create two dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @returns constructed 2D vector from raw pointer - */ -CGLM_INLINE -vec2s -glms_vec2_(make)(const float * __restrict src) { - vec2s dest; - glm_vec2_make(src, dest.raw); - return dest; -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] I incident vector - * @param[in] N normalized normal vector - * @returns reflection result - */ -CGLM_INLINE -vec2s -glms_vec2_(reflect)(vec2s v, vec2s n) { - vec2s dest; - glm_vec2_reflect(v.raw, n.raw, dest.raw); - return dest; -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glms_vec2_(refract)(vec2s v, vec2s n, float eta, vec2s * __restrict dest) { - return glm_vec2_refract(v.raw, n.raw, eta, dest->raw); -} - -#endif /* cglms_vec2s_h */ diff --git a/external/cglm/struct/vec3-ext.h b/external/cglm/struct/vec3-ext.h deleted file mode 100644 index 6cd8ca0..0000000 --- a/external/cglm/struct/vec3-ext.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * @brief SIMD like functions - */ - -/* - Functions: - CGLM_INLINE vec3s glms_vec3_broadcast(float val); - CGLM_INLINE vec3s glms_vec3_fill(float val); - CGLM_INLINE bool glms_vec3_eq(vec3s v, float val); - CGLM_INLINE bool glms_vec3_eq_eps(vec3s v, float val); - CGLM_INLINE bool glms_vec3_eq_all(vec3s v); - CGLM_INLINE bool glms_vec3_eqv(vec3s a, vec3s b); - CGLM_INLINE bool glms_vec3_eqv_eps(vec3s a, vec3s b); - CGLM_INLINE float glms_vec3_max(vec3s v); - CGLM_INLINE float glms_vec3_min(vec3s v); - CGLM_INLINE bool glms_vec3_isnan(vec3s v); - CGLM_INLINE bool glms_vec3_isinf(vec3s v); - CGLM_INLINE bool glms_vec3_isvalid(vec3s v); - CGLM_INLINE vec3s glms_vec3_sign(vec3s v); - CGLM_INLINE vec3s glms_vec3_abs(vec3s v); - CGLM_INLINE vec3s glms_vec3_fract(vec3s v); - CGLM_INLINE vec3s glms_vec3_floor(vec3s v); - CGLM_INLINE vec3s glms_vec3_mods(vec3s v, float s); - CGLM_INLINE vec3s glms_vec3_steps(float edge, vec3s v); - CGLM_INLINE vec3s glms_vec3_stepr(vec3s edge, float v); - CGLM_INLINE float glms_vec3_hadd(vec3s v); - CGLM_INLINE vec3s glms_vec3_sqrt(vec3s v); - */ - -#ifndef cglms_vec3s_ext_h -#define cglms_vec3s_ext_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec3-ext.h" - -/* api definition */ -#define glms_vec3_(NAME) CGLM_STRUCTAPI(vec3, NAME) - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @returns dest - */ -CGLM_INLINE -vec3s -glms_vec3_(broadcast)(float val) { - vec3s r; - glm_vec3_broadcast(val, r.raw); - return r; -} - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @returns dest - */ -CGLM_INLINE -vec3s -glms_vec3_(fill)(float val) { - vec3s r; - glm_vec3_fill(r.raw, val); - return r; -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_vec3_(eq)(vec3s v, float val) { - return glm_vec3_eq(v.raw, val); -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glms_vec3_(eq_eps)(vec3s v, float val) { - return glm_vec3_eq_eps(v.raw, val); -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec3_(eq_all)(vec3s v) { - return glm_vec3_eq_all(v.raw); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_vec3_(eqv)(vec3s a, vec3s b) { - return glm_vec3_eqv(a.raw, b.raw); -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glms_vec3_(eqv_eps)(vec3s a, vec3s b) { - return glm_vec3_eqv_eps(a.raw, b.raw); -} - -/*! - * @brief max value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glms_vec3_(max)(vec3s v) { - return glm_vec3_max(v.raw); -} - -/*! - * @brief min value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glms_vec3_(min)(vec3s v) { - return glm_vec3_min(v.raw); -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec3_(isnan)(vec3s v) { - return glm_vec3_isnan(v.raw); -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec3_(isinf)(vec3s v) { - return glm_vec3_isinf(v.raw); -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec3_(isvalid)(vec3s v) { - return glm_vec3_isvalid(v.raw); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - * @returns sign vector - */ -CGLM_INLINE -vec3s -glms_vec3_(sign)(vec3s v) { - vec3s r; - glm_vec3_sign(v.raw, r.raw); - return r; -} - -/*! - * @brief absolute value of each vector item - * - * @param[in] v vector - * @return destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(abs)(vec3s v) { - vec3s r; - glm_vec3_abs(v.raw, r.raw); - return r; -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @return dest destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(fract)(vec3s v) { - vec3s r; - glm_vec3_fract(v.raw, r.raw); - return r; -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @return dest destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(floor)(vec3s v) { - vec3s r; - glm_vec3_floor(v.raw, r.raw); - return r; -} - -/*! - * @brief mod of each vector item by scalar - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(mods)(vec3s v, float s) { - vec3s r; - glm_vec3_mods(v.raw, s, r.raw); - return r; -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(steps)(float edge, vec3s x) { - vec3s r; - glm_vec3_steps(edge, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(stepr)(vec3s edge, float x) { - vec3s r; - glm_vec3_stepr(edge.raw, x, r.raw); - return r; -} - -/*! - * @brief vector reduction by summation - * @warning could overflow - * - * @param[in] v vector - * @return sum of all vector's elements - */ -CGLM_INLINE -float -glms_vec3_(hadd)(vec3s v) { - return glm_vec3_hadd(v.raw); -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(sqrt)(vec3s v) { - vec3s r; - glm_vec3_sqrt(v.raw, r.raw); - return r; -} - -#endif /* cglms_vec3s_ext_h */ diff --git a/external/cglm/struct/vec3.h b/external/cglm/struct/vec3.h deleted file mode 100644 index a1d901e..0000000 --- a/external/cglm/struct/vec3.h +++ /dev/null @@ -1,1132 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_VEC3_ONE_INIT - GLMS_VEC3_ZERO_INIT - GLMS_VEC3_ONE - GLMS_VEC3_ZERO - GLMS_YUP - GLMS_ZUP - GLMS_XUP - - Functions: - CGLM_INLINE vec3s glms_vec3(vec4s v4); - CGLM_INLINE void glms_vec3_pack(vec3s dst[], vec3 src[], size_t len); - CGLM_INLINE void glms_vec3_unpack(vec3 dst[], vec3s src[], size_t len); - CGLM_INLINE vec3s glms_vec3_zero(void); - CGLM_INLINE vec3s glms_vec3_one(void); - CGLM_INLINE float glms_vec3_dot(vec3s a, vec3s b); - CGLM_INLINE float glms_vec3_norm2(vec3s v); - CGLM_INLINE float glms_vec3_norm(vec3s v); - CGLM_INLINE float glms_vec3_norm_one(vec3s v); - CGLM_INLINE float glms_vec3_norm_inf(vec3s v); - CGLM_INLINE vec3s glms_vec3_add(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_adds(vec3s a, float s); - CGLM_INLINE vec3s glms_vec3_sub(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_subs(vec3s a, float s); - CGLM_INLINE vec3s glms_vec3_mul(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_scale(vec3s v, float s); - CGLM_INLINE vec3s glms_vec3_scale_as(vec3s v, float s); - CGLM_INLINE vec3s glms_vec3_div(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_divs(vec3s a, float s); - CGLM_INLINE vec3s glms_vec3_addadd(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_subadd(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_muladd(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_muladds(vec3s a, float s, vec3s dest); - CGLM_INLINE vec3s glms_vec3_maxadd(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_minadd(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_subsub(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_addsub(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_mulsub(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_mulsubs(vec3s a, float s, vec3s dest); - CGLM_INLINE vec3s glms_vec3_maxsub(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_minsub(vec3s a, vec3s b, vec3s dest); - CGLM_INLINE vec3s glms_vec3_flipsign(vec3s v); - CGLM_INLINE vec3s glms_vec3_negate(vec3s v); - CGLM_INLINE vec3s glms_vec3_normalize(vec3s v); - CGLM_INLINE vec3s glms_vec3_cross(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_crossn(vec3s a, vec3s b); - CGLM_INLINE float glms_vec3_angle(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_rotate(vec3s v, float angle, vec3s axis); - CGLM_INLINE vec3s glms_vec3_rotate_m4(mat4s m, vec3s v); - CGLM_INLINE vec3s glms_vec3_rotate_m3(mat3s m, vec3s v); - CGLM_INLINE vec3s glms_vec3_proj(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_center(vec3s a, vec3s b); - CGLM_INLINE float glms_vec3_distance(vec3s a, vec3s b); - CGLM_INLINE float glms_vec3_distance2(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_maxv(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_minv(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_vec3_ortho(vec3s v); - CGLM_INLINE vec3s glms_vec3_clamp(vec3s v, float minVal, float maxVal); - CGLM_INLINE vec3s glms_vec3_lerp(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_lerpc(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_mix(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_mixc(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_step(vec3s edge, vec3s x); - CGLM_INLINE vec3s glms_vec3_smoothstep_uni(float edge0, float edge1, vec3s x); - CGLM_INLINE vec3s glms_vec3_smoothstep(vec3s edge0, vec3s edge1, vec3s x); - CGLM_INLINE vec3s glms_vec3_smoothinterp(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_smoothinterpc(vec3s from, vec3s to, float t); - CGLM_INLINE vec3s glms_vec3_swizzle(vec3s v, int mask); - CGLM_INLINE vec3s glms_vec3_make(float * restrict src); - CGLM_INLINE vec3s glms_vec3_faceforward(vec3s n, vec3s v, vec3s nref); - CGLM_INLINE vec3s glms_vec3_reflect(vec3s v, vec3s n); - CGLM_INLINE bool glms_vec3_refract(vec3s v, vec3s n, float eta, vec3s *dest) - - Convenient: - CGLM_INLINE vec3s glms_cross(vec3s a, vec3s b); - CGLM_INLINE float glms_dot(vec3s a, vec3s b); - CGLM_INLINE vec3s glms_normalize(vec3s v); - - Deprecated: - glms_vec3_step_uni --> use glms_vec3_steps - */ - -#ifndef cglms_vec3s_h -#define cglms_vec3s_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec3.h" -#include "vec3-ext.h" - -/* DEPRECATED! */ -#define glms_vec3_step_uni(edge, x) glms_vec3_steps(edge, x) - -#define GLMS_VEC3_ONE_INIT {GLM_VEC3_ONE_INIT} -#define GLMS_VEC3_ZERO_INIT {GLM_VEC3_ZERO_INIT} - -#define GLMS_VEC3_ONE ((vec3s)GLMS_VEC3_ONE_INIT) -#define GLMS_VEC3_ZERO ((vec3s)GLMS_VEC3_ZERO_INIT) - -#define GLMS_YUP ((vec3s){{0.0f, 1.0f, 0.0f}}) -#define GLMS_ZUP ((vec3s){{0.0f, 0.0f, 1.0f}}) -#define GLMS_XUP ((vec3s){{1.0f, 0.0f, 0.0f}}) - -/*! - * @brief init vec3 using vec4 - * - * @param[in] v4 vector4 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3(vec4s v4) { - vec3s r; - glm_vec3(v4.raw, r.raw); - return r; -} - -/*! - * @brief pack an array of vec3 into an array of vec3s - * - * @param[out] dst array of vec3 - * @param[in] src array of vec3s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec3_(pack)(vec3s dst[], vec3 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec3_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of vec3s into an array of vec3 - * - * @param[out] dst array of vec3s - * @param[in] src array of vec3 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec3_(unpack)(vec3 dst[], vec3s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec3_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief make vector zero - * - * @returns zero vector - */ -CGLM_INLINE -vec3s -glms_vec3_(zero)(void) { - vec3s r; - glm_vec3_zero(r.raw); - return r; -} - -/*! - * @brief make vector one - * - * @returns one vector - */ -CGLM_INLINE -vec3s -glms_vec3_(one)(void) { - vec3s r; - glm_vec3_one(r.raw); - return r; -} - -/*! - * @brief vec3 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glms_vec3_(dot)(vec3s a, vec3s b) { - return glm_vec3_dot(a.raw, b.raw); -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -float -glms_vec3_(norm2)(vec3s v) { - return glm_vec3_norm2(v.raw); -} - -/*! - * @brief norm (magnitude) of vec3 - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -float -glms_vec3_(norm)(vec3s v) { - return glm_vec3_norm(v.raw); -} - -/*! - * @brief L1 norm of vec3 - * Also known as Manhattan Distance or Taxicab norm. - * L1 Norm is the sum of the magnitudes of the vectors in a space. - * It is calculated as the sum of the absolute values of the vector components. - * In this norm, all the components of the vector are weighted equally. - * - * This computes: - * R = |v[0]| + |v[1]| + |v[2]| - * - * @param[in] v vector - * - * @return L1 norm - */ -CGLM_INLINE -float -glms_vec3_(norm_one)(vec3s v) { - return glm_vec3_norm_one(v.raw); -} - -/*! - * @brief Infinity norm of vec3 - * Also known as Maximum norm. - * Infinity Norm is the largest magnitude among each element of a vector. - * It is calculated as the maximum of the absolute values of the vector components. - * - * This computes: - * inf norm = max(|v[0]|, |v[1]|, |v[2]|) - * - * @param[in] v vector - * - * @return Infinity norm - */ -CGLM_INLINE -float -glms_vec3_(norm_inf)(vec3s v) { - return glm_vec3_norm_inf(v.raw); -} - -/*! - * @brief add a vector to b vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(add)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + s) - * - * @param[in] a vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(adds)(vec3s a, float s) { - vec3s r; - glm_vec3_adds(a.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract b vector from a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(sub)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - s) - * - * @param[in] a vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(subs)(vec3s a, float s) { - vec3s r; - glm_vec3_subs(a.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a vector1 - * @param b vector2 - * @returns v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) - */ -CGLM_INLINE -vec3s -glms_vec3_(mul)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply/scale vec3 vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(scale)(vec3s v, float s) { - vec3s r; - glm_vec3_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief make vec3 vector scale as specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec3s -glms_vec3_(scale_as)(vec3s v, float s) { - vec3s r; - glm_vec3_scale_as(v.raw, s, r.raw); - return r; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) - */ -CGLM_INLINE -vec3s -glms_vec3_(div)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_div(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] a vector - * @param[in] s scalar - * @returns result = (a[0]/s, a[1]/s, a[2]/s) - */ -CGLM_INLINE -vec3s -glms_vec3_(divs)(vec3s a, float s) { - vec3s r; - glm_vec3_divs(a.raw, s, r.raw); - return r; -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a + b) - */ -CGLM_INLINE -vec3s -glms_vec3_(addadd)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a + b) - */ -CGLM_INLINE -vec3s -glms_vec3_(subadd)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a * b) - */ -CGLM_INLINE -vec3s -glms_vec3_(muladd)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest += (a * b) - */ -CGLM_INLINE -vec3s -glms_vec3_(muladds)(vec3s a, float s, vec3s dest) { - glm_vec3_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += max(a, b) - */ -CGLM_INLINE -vec3s -glms_vec3_(maxadd)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += min(a, b) - */ -CGLM_INLINE -vec3s -glms_vec3_(minadd)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a - b) - */ -CGLM_INLINE -vec3s -glms_vec3_(subsub)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a + b) - */ -CGLM_INLINE -vec3s -glms_vec3_(addsub)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec3s -glms_vec3_(mulsub)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec3s -glms_vec3_(mulsubs)(vec3s a, float s, vec3s dest) { - glm_vec3_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief sub max of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= max(a, b) - */ -CGLM_INLINE -vec3s -glms_vec3_(maxsub)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub min of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= min(a, b) - */ -CGLM_INLINE -vec3s -glms_vec3_(minsub)(vec3s a, vec3s b, vec3s dest) { - glm_vec3_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief negate vector components and store result in dest - * - * @param[in] v vector - * @returns result vector - */ -CGLM_INLINE -vec3s -glms_vec3_(flipsign)(vec3s v) { - glm_vec3_flipsign(v.raw); - return v; -} - -/*! - * @brief negate vector components - * - * @param[in] v vector - * @returns negated vector - */ -CGLM_INLINE -vec3s -glms_vec3_(negate)(vec3s v) { - glm_vec3_negate(v.raw); - return v; -} - -/*! - * @brief normalize vec3 and store result in same vec - * - * @param[in] v vector - * @returns normalized vector - */ -CGLM_INLINE -vec3s -glms_vec3_(normalize)(vec3s v) { - glm_vec3_normalize(v.raw); - return v; -} - -/*! - * @brief cross product of two vector (RH) - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(cross)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_cross(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief cross product of two vector (RH) and normalize the result - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(crossn)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_crossn(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief angle between two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return angle as radians - */ -CGLM_INLINE -float -glms_vec3_(angle)(vec3s a, vec3s b) { - return glm_vec3_angle(a.raw, b.raw); -} - -/*! - * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula - * - * @param[in] v vector - * @param[in] axis axis vector (must be unit vector) - * @param[in] angle angle by radians - * @returns rotated vector - */ -CGLM_INLINE -vec3s -glms_vec3_(rotate)(vec3s v, float angle, vec3s axis) { - glm_vec3_rotate(v.raw, angle, axis.raw); - return v; -} - -/*! - * @brief apply rotation matrix to vector - * - * matrix format should be (no perspective): - * a b c x - * e f g y - * i j k z - * 0 0 0 w - * - * @param[in] m affine matrix or rot matrix - * @param[in] v vector - * @returns rotated vector - */ -CGLM_INLINE -vec3s -glms_vec3_(rotate_m4)(mat4s m, vec3s v) { - vec3s r; - glm_vec3_rotate_m4(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief apply rotation matrix to vector - * - * @param[in] m affine matrix or rot matrix - * @param[in] v vector - * @returns rotated vector - */ -CGLM_INLINE -vec3s -glms_vec3_(rotate_m3)(mat3s m, vec3s v) { - vec3s r; - glm_vec3_rotate_m3(m.raw, v.raw, r.raw); - return r; -} - -/*! - * @brief project a vector onto b vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns projected vector - */ -CGLM_INLINE -vec3s -glms_vec3_(proj)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_proj(a.raw, b.raw, r.raw); - return r; -} - -/** - * @brief find center point of two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns center point - */ -CGLM_INLINE -vec3s -glms_vec3_(center)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_center(a.raw, b.raw, r.raw); - return r; -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return distance - */ -CGLM_INLINE -float -glms_vec3_(distance)(vec3s a, vec3s b) { - return glm_vec3_distance(a.raw, b.raw); -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return squared distance (distance * distance) - */ -CGLM_INLINE -float -glms_vec3_(distance2)(vec3s a, vec3s b) { - return glm_vec3_distance2(a.raw, b.raw); -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(maxv)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(minv)(vec3s a, vec3s b) { - vec3s r; - glm_vec3_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief possible orthogonal/perpendicular vector - * - * @param[in] v vector - * @returns orthogonal/perpendicular vector - */ -CGLM_INLINE -vec3s -glms_vec3_(ortho)(vec3s v) { - vec3s r; - glm_vec3_ortho(v.raw, r.raw); - return r; -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -vec3s -glms_vec3_(clamp)(vec3s v, float minVal, float maxVal) { - glm_vec3_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(lerp)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_lerp(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(lerpc)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_lerpc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(mix)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_mix(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(mixc)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_mixc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @returns 0.0 if x < edge, else 1.0 - */ -CGLM_INLINE -vec3s -glms_vec3_(step)(vec3s edge, vec3s x) { - vec3s r; - glm_vec3_step(edge.raw, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold function with a smooth transition (unidimensional) - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(smoothstep_uni)(float edge0, float edge1, vec3s x) { - vec3s r; - glm_vec3_smoothstep_uni(edge0, edge1, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold function with a smooth transition - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(smoothstep)(vec3s edge0, vec3s edge1, vec3s x) { - vec3s r; - glm_vec3_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); - return r; -} - -/*! - * @brief smooth Hermite interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(smoothinterp)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_smoothinterp(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief smooth Hermite interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_vec3_(smoothinterpc)(vec3s from, vec3s to, float t) { - vec3s r; - glm_vec3_smoothinterpc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief vec3 cross product - * - * this is just convenient wrapper - * - * @param[in] a source 1 - * @param[in] b source 2 - * @returns destination - */ -CGLM_INLINE -vec3s -glms_cross(vec3s a, vec3s b) { - vec3s r; - glm_cross(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief vec3 dot product - * - * this is just convenient wrapper - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return dot product - */ -CGLM_INLINE -float -glms_dot(vec3s a, vec3s b) { - return glm_dot(a.raw, b.raw); -} - -/*! - * @brief normalize vec3 and store result in same vec - * - * this is just convenient wrapper - * - * @param[in] v vector - * @returns normalized vector - */ -CGLM_INLINE -vec3s -glms_normalize(vec3s v) { - glm_normalize(v.raw); - return v; -} - -/*! - * @brief swizzle vector components - * - * you can use existing masks e.g. GLM_XXX, GLM_ZYX - * - * @param[in] v source - * @param[in] mask mask - * @returns swizzled vector - */ -CGLM_INLINE -vec3s -glms_vec3_(swizzle)(vec3s v, int mask) { - vec3s dest; - glm_vec3_swizzle(v.raw, mask, dest.raw); - return dest; -} - -/*! - * @brief Create three dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @returns constructed 3D vector from raw pointer - */ -CGLM_INLINE -vec3s -glms_vec3_(make)(const float * __restrict src) { - vec3s dest; - glm_vec3_make(src, dest.raw); - return dest; -} - -/*! - * @brief a vector pointing in the same direction as another - * - * orients a vector to point away from a surface as defined by its normal - * - * @param[in] n vector to orient. - * @param[in] v incident vector - * @param[in] nref reference vector - * @returns oriented vector, pointing away from the surface. - */ -CGLM_INLINE -vec3s -glms_vec3_(faceforward)(vec3s n, vec3s v, vec3s nref) { - vec3s dest; - glm_vec3_faceforward(n.raw, v.raw, nref.raw, dest.raw); - return dest; -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] I incident vector - * @param[in] N normalized normal vector - * @returns reflection result - */ -CGLM_INLINE -vec3s -glms_vec3_(reflect)(vec3s v, vec3s n) { - vec3s dest; - glm_vec3_reflect(v.raw, n.raw, dest.raw); - return dest; -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glms_vec3_(refract)(vec3s v, vec3s n, float eta, vec3s * __restrict dest) { - return glm_vec3_refract(v.raw, n.raw, eta, dest->raw); -} - -#endif /* cglms_vec3s_h */ diff --git a/external/cglm/struct/vec4-ext.h b/external/cglm/struct/vec4-ext.h deleted file mode 100644 index f57348e..0000000 --- a/external/cglm/struct/vec4-ext.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * @brief SIMD like functions - */ - -/* - Functions: - CGLM_INLINE vec4s glms_vec4_broadcast(float val); - CGLM_INLINE vec4s glms_vec4_fill(float val); - CGLM_INLINE bool glms_vec4_eq(vec4s v, float val); - CGLM_INLINE bool glms_vec4_eq_eps(vec4s v, float val); - CGLM_INLINE bool glms_vec4_eq_all(vec4s v); - CGLM_INLINE bool glms_vec4_eqv(vec4s a, vec4s b); - CGLM_INLINE bool glms_vec4_eqv_eps(vec4s a, vec4s b); - CGLM_INLINE float glms_vec4_max(vec4s v); - CGLM_INLINE float glms_vec4_min(vec4s v); - CGLM_INLINE bool glms_vec4_isnan(vec4s v); - CGLM_INLINE bool glms_vec4_isinf(vec4s v); - CGLM_INLINE bool glms_vec4_isvalid(vec4s v); - CGLM_INLINE vec4s glms_vec4_sign(vec4s v); - CGLM_INLINE vec4s glms_vec4_abs(vec4s v); - CGLM_INLINE vec4s glms_vec4_fract(vec4s v); - CGLM_INLINE float glms_vec4_floor(vec4s v); - CGLM_INLINE float glms_vec4_mods(vec4s v, float s); - CGLM_INLINE float glms_vec4_steps(float edge, vec4s v); - CGLM_INLINE void glms_vec4_stepr(vec4s edge, float v); - CGLM_INLINE float glms_vec4_hadd(vec4s v); - CGLM_INLINE vec4s glms_vec4_sqrt(vec4s v); - */ - -#ifndef cglms_vec4s_ext_h -#define cglms_vec4s_ext_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec4-ext.h" - -/* api definition */ -#define glms_vec4_(NAME) CGLM_STRUCTAPI(vec4, NAME) - -/*! - * @brief fill a vector with specified value - * - * @param val value - * @returns dest - */ -CGLM_INLINE -vec4s -glms_vec4_(broadcast)(float val) { - vec4s r; - glm_vec4_broadcast(val, r.raw); - return r; -} - -/*! - * @brief fill a vector with specified value - * - * @param val value - * @returns dest - */ -CGLM_INLINE -vec4s -glms_vec4_(fill)(float val) { - vec4s r; - glm_vec4_fill(r.raw, val); - return r; -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param v vector - * @param val value - */ -CGLM_INLINE -bool -glms_vec4_(eq)(vec4s v, float val) { - return glm_vec4_eq(v.raw, val); -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param v vector - * @param val value - */ -CGLM_INLINE -bool -glms_vec4_(eq_eps)(vec4s v, float val) { - return glm_vec4_eq_eps(v.raw, val); -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param v vector - */ -CGLM_INLINE -bool -glms_vec4_(eq_all)(vec4s v) { - return glm_vec4_eq_all(v.raw); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param a vector - * @param b vector - */ -CGLM_INLINE -bool -glms_vec4_(eqv)(vec4s a, vec4s b) { - return glm_vec4_eqv(a.raw, b.raw); -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param a vector - * @param b vector - */ -CGLM_INLINE -bool -glms_vec4_(eqv_eps)(vec4s a, vec4s b) { - return glm_vec4_eqv_eps(a.raw, b.raw); -} - -/*! - * @brief max value of vector - * - * @param v vector - */ -CGLM_INLINE -float -glms_vec4_(max)(vec4s v) { - return glm_vec4_max(v.raw); -} - -/*! - * @brief min value of vector - * - * @param v vector - */ -CGLM_INLINE -float -glms_vec4_(min)(vec4s v) { - return glm_vec4_min(v.raw); -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec4_(isnan)(vec4s v) { - return glm_vec4_isnan(v.raw); -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec4_(isinf)(vec4s v) { - return glm_vec4_isinf(v.raw); -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glms_vec4_(isvalid)(vec4s v) { - return glm_vec4_isvalid(v.raw); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - * @returns sign vector - */ -CGLM_INLINE -vec4s -glms_vec4_(sign)(vec4s v) { - vec4s r; - glm_vec4_sign(v.raw, r.raw); - return r; -} - -/*! - * @brief absolute value of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(abs)(vec4s v) { - vec4s r; - glm_vec4_abs(v.raw, r.raw); - return r; -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @returns dest destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(fract)(vec4s v) { - vec4s r; - glm_vec4_fract(v.raw, r.raw); - return r; -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @returns dest destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(floor)(vec4s v) { - vec4s r; - glm_vec4_floor(v.raw, r.raw); - return r; -} - -/*! - * @brief mod of each vector item by scalar - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(mods)(vec4s v, float s) { - vec4s r; - glm_vec4_mods(v.raw, s, r.raw); - return r; -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(steps)(float edge, vec4s x) { - vec4s r; - glm_vec4_steps(edge, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(stepr)(vec4s edge, float x) { - vec4s r; - glm_vec4_stepr(edge.raw, x, r.raw); - return r; -} - -/*! - * @brief vector reduction by summation - * @warning could overflow - * - * @param[in] v vector - * @return sum of all vector's elements - */ -CGLM_INLINE -float -glms_vec4_(hadd)(vec4s v) { - return glm_vec4_hadd(v.raw); -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(sqrt)(vec4s v) { - vec4s r; - glm_vec4_sqrt(v.raw, r.raw); - return r; -} - -#endif /* cglms_vec4s_ext_h */ diff --git a/external/cglm/struct/vec4.h b/external/cglm/struct/vec4.h deleted file mode 100644 index a64c1a3..0000000 --- a/external/cglm/struct/vec4.h +++ /dev/null @@ -1,961 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLMS_VEC4_ONE_INIT - GLMS_VEC4_BLACK_INIT - GLMS_VEC4_ZERO_INIT - GLMS_VEC4_ONE - GLMS_VEC4_BLACK - GLMS_VEC4_ZERO - - Functions: - CGLM_INLINE vec4s glms_vec4(vec3s v3, float last); - CGLM_INLINE vec3s glms_vec4_copy3(vec4s v); - CGLM_INLINE vec4s glms_vec4_copy(vec4s v); - CGLM_INLINE vec4s glms_vec4_ucopy(vec4s v); - CGLM_INLINE void glms_vec4_pack(vec4s dst[], vec4 src[], size_t len); - CGLM_INLINE void glms_vec4_unpack(vec4 dst[], vec4s src[], size_t len); - CGLM_INLINE float glms_vec4_dot(vec4s a, vec4s b); - CGLM_INLINE float glms_vec4_norm2(vec4s v); - CGLM_INLINE float glms_vec4_norm(vec4s v); - CGLM_INLINE float glms_vec4_norm_one(vec4s v); - CGLM_INLINE float glms_vec4_norm_inf(vec4s v); - CGLM_INLINE vec4s glms_vec4_add(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_adds(vec4s v, float s); - CGLM_INLINE vec4s glms_vec4_sub(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_subs(vec4s v, float s); - CGLM_INLINE vec4s glms_vec4_mul(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_scale(vec4s v, float s); - CGLM_INLINE vec4s glms_vec4_scale_as(vec4s v, float s); - CGLM_INLINE vec4s glms_vec4_div(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_divs(vec4s v, float s); - CGLM_INLINE vec4s glms_vec4_addadd(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_subadd(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_muladd(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_muladds(vec4s a, float s, vec4s dest); - CGLM_INLINE vec4s glms_vec4_maxadd(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_minadd(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_subsub(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_addsub(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_mulsub(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_mulsubs(vec4s a, float s, vec4s dest); - CGLM_INLINE vec4s glms_vec4_maxsub(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_minsub(vec4s a, vec4s b, vec4s dest); - CGLM_INLINE vec4s glms_vec4_negate(vec4s v); - CGLM_INLINE vec4s glms_vec4_normalize(vec4s v); - CGLM_INLINE float glms_vec4_distance(vec4s a, vec4s b); - CGLM_INLINE float glms_vec4_distance2(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_maxv(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_minv(vec4s a, vec4s b); - CGLM_INLINE vec4s glms_vec4_clamp(vec4s v, float minVal, float maxVal); - CGLM_INLINE vec4s glms_vec4_lerp(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_lerpc(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_mix(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_mixc(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_step(vec4s edge, vec4s x); - CGLM_INLINE vec4s glms_vec4_smoothstep_uni(float edge0, float edge1, vec4s x); - CGLM_INLINE vec4s glms_vec4_smoothstep(vec4s edge0, vec4s edge1, vec4s x); - CGLM_INLINE vec4s glms_vec4_smoothinterp(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_smoothinterpc(vec4s from, vec4s to, float t); - CGLM_INLINE vec4s glms_vec4_cubic(float s); - CGLM_INLINE vec4s glms_vec4_swizzle(vec4s v, int mask); - CGLM_INLINE vec4s glms_vec4_make(float * restrict src); - CGLM_INLINE vec4s glms_vec4_reflect(vec4s v, vec4s n); - CGLM_INLINE bool glms_vec4_refract(vec4s v, vec4s n, float eta, vec4s *dest) - - Deprecated: - glms_vec4_step_uni --> use glms_vec4_steps - */ - -#ifndef cglms_vec4s_h -#define cglms_vec4s_h - -#include "../common.h" -#include "../types-struct.h" -#include "../util.h" -#include "../vec4.h" -#include "vec4-ext.h" - -/* DEPRECATED! */ -#define glms_vec4_step_uni(edge, x) glms_vec4_steps(edge, x) - -#define GLMS_VEC4_ONE_INIT {GLM_VEC4_ONE_INIT} -#define GLMS_VEC4_BLACK_INIT {GLM_VEC4_BLACK_INIT} -#define GLMS_VEC4_ZERO_INIT {GLM_VEC4_ZERO_INIT} - -#define GLMS_VEC4_ONE ((vec4s)GLM_VEC4_ONE_INIT) -#define GLMS_VEC4_BLACK ((vec4s)GLM_VEC4_BLACK_INIT) -#define GLMS_VEC4_ZERO ((vec4s)GLM_VEC4_ZERO_INIT) - -/*! - * @brief init vec4 using vec3 - * - * @param[in] v3 vector3 - * @param[in] last last item - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4(vec3s v3, float last) { - vec4s r; - glm_vec4(v3.raw, last, r.raw); - return r; -} - -/*! - * @brief copy first 3 members of [a] to [dest] - * - * @param[in] v source - * @returns vec3 - */ -CGLM_INLINE -vec3s -glms_vec4_(copy3)(vec4s v) { - vec3s r; - glm_vec4_copy3(v.raw, r.raw); - return r; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] v source - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(copy)(vec4s v) { - vec4s r; - glm_vec4_copy(v.raw, r.raw); - return r; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * alignment is not required - * - * @param[in] v source - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(ucopy)(vec4s v) { - vec4s r; - glm_vec4_ucopy(v.raw, r.raw); - return r; -} - -/*! - * @brief pack an array of vec4 into an array of vec4s - * - * @param[out] dst array of vec4 - * @param[in] src array of vec4s - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec4_(pack)(vec4s dst[], vec4 src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec4_copy(src[i], dst[i].raw); - } -} - -/*! - * @brief unpack an array of vec4s into an array of vec4 - * - * @param[out] dst array of vec4s - * @param[in] src array of vec4 - * @param[in] len number of elements - */ -CGLM_INLINE -void -glms_vec4_(unpack)(vec4 dst[], vec4s src[], size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - glm_vec4_copy(src[i].raw, dst[i]); - } -} - -/*! - * @brief make vector zero - * - * @returns zero vector - */ -CGLM_INLINE -vec4s -glms_vec4_(zero)(void) { - vec4s r; - glm_vec4_zero(r.raw); - return r; -} - -/*! - * @brief make vector one - * - * @returns one vector - */ -CGLM_INLINE -vec4s -glms_vec4_(one)(void) { - vec4s r; - glm_vec4_one(r.raw); - return r; -} - -/*! - * @brief vec4 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glms_vec4_(dot)(vec4s a, vec4s b) { - return glm_vec4_dot(a.raw, b.raw); -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vec4 - * - * @return norm * norm - */ -CGLM_INLINE -float -glms_vec4_(norm2)(vec4s v) { - return glm_vec4_norm2(v.raw); -} - -/*! - * @brief norm (magnitude) of vec4 - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -float -glms_vec4_(norm)(vec4s v) { - return glm_vec4_norm(v.raw); -} - -/*! - * @brief L1 norm of vec4 - * Also known as Manhattan Distance or Taxicab norm. - * L1 Norm is the sum of the magnitudes of the vectors in a space. - * It is calculated as the sum of the absolute values of the vector components. - * In this norm, all the components of the vector are weighted equally. - * - * This computes: - * R = |v[0]| + |v[1]| + |v[2]| + |v[3]| - * - * @param[in] v vector - * - * @return L1 norm - */ -CGLM_INLINE -float -glms_vec4_(norm_one)(vec4s v) { - return glm_vec4_norm_one(v.raw); -} - -/*! - * @brief Infinity norm of vec4 - * Also known as Maximum norm. - * Infinity Norm is the largest magnitude among each element of a vector. - * It is calculated as the maximum of the absolute values of the vector components. - * - * This computes: - * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) - * - * @param[in] v vector - * - * @return Infinity norm - */ -CGLM_INLINE -float -glms_vec4_(norm_inf)(vec4s v) { - return glm_vec4_norm_inf(v.raw); -} - -/*! - * @brief add b vector to a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(add)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_add(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + vec(s)) - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(adds)(vec4s v, float s) { - vec4s r; - glm_vec4_adds(v.raw, s, r.raw); - return r; -} - -/*! - * @brief subtract b vector from a vector store result in dest (d = a - b) - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(sub)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_sub(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(subs)(vec4s v, float s) { - vec4s r; - glm_vec4_subs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a vector1 - * @param b vector2 - * @returns dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) - */ -CGLM_INLINE -vec4s -glms_vec4_(mul)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_mul(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief multiply/scale vec4 vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(scale)(vec4s v, float s) { - vec4s r; - glm_vec4_scale(v.raw, s, r.raw); - return r; -} - -/*! - * @brief make vec4 vector scale as specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(scale_as)(vec4s v, float s) { - vec4s r; - glm_vec4_scale_as(v.raw, s, r.raw); - return r; -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) - */ -CGLM_INLINE -vec4s -glms_vec4_(div)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_div(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief div vec4 vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @returns destination vector - */ -CGLM_INLINE -vec4s -glms_vec4_(divs)(vec4s v, float s) { - vec4s r; - glm_vec4_divs(v.raw, s, r.raw); - return r; -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a + b) - */ -CGLM_INLINE -vec4s -glms_vec4_(addadd)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_addadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a - b) - */ -CGLM_INLINE -vec4s -glms_vec4_(subadd)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_subadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += (a * b) - */ -CGLM_INLINE -vec4s -glms_vec4_(muladd)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_muladd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest += (a * b) - */ -CGLM_INLINE -vec4s -glms_vec4_(muladds)(vec4s a, float s, vec4s dest) { - glm_vec4_muladds(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += max(a, b) - */ -CGLM_INLINE -vec4s -glms_vec4_(maxadd)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_maxadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest += min(a, b) - */ -CGLM_INLINE -vec4s -glms_vec4_(minadd)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_minadd(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a + b) - */ -CGLM_INLINE -vec4s -glms_vec4_(subsub)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_subsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a + b) - */ -CGLM_INLINE -vec4s -glms_vec4_(addsub)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_addsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec4s -glms_vec4_(mulsub)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_mulsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief mul vector with scalar and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @returns dest -= (a * b) - */ -CGLM_INLINE -vec4s -glms_vec4_(mulsubs)(vec4s a, float s, vec4s dest) { - glm_vec4_mulsubs(a.raw, s, dest.raw); - return dest; -} - -/*! - * @brief sub max of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= max(a, b) - */ -CGLM_INLINE -vec4s -glms_vec4_(maxsub)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_maxsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief sub min of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @returns dest -= min(a, b) - */ -CGLM_INLINE -vec4s -glms_vec4_(minsub)(vec4s a, vec4s b, vec4s dest) { - glm_vec4_minsub(a.raw, b.raw, dest.raw); - return dest; -} - -/*! - * @brief negate vector components and store result in dest - * - * @param[in] v vector - * @returns result vector - */ -CGLM_INLINE -vec4s -glms_vec4_(negate)(vec4s v) { - glm_vec4_negate(v.raw); - return v; -} - -/*! - * @brief normalize vec4 and store result in same vec - * - * @param[in] v vector - * @returns normalized vector - */ -CGLM_INLINE -vec4s -glms_vec4_(normalize)(vec4s v) { - glm_vec4_normalize(v.raw); - return v; -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns distance - */ -CGLM_INLINE -float -glms_vec4_(distance)(vec4s a, vec4s b) { - return glm_vec4_distance(a.raw, b.raw); -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns squared distance - */ -CGLM_INLINE -float -glms_vec4_(distance2)(vec4s a, vec4s b) { - return glm_vec4_distance2(a.raw, b.raw); -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(maxv)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_maxv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(minv)(vec4s a, vec4s b) { - vec4s r; - glm_vec4_minv(a.raw, b.raw, r.raw); - return r; -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - * @returns clamped vector - */ -CGLM_INLINE -vec4s -glms_vec4_(clamp)(vec4s v, float minVal, float maxVal) { - glm_vec4_clamp(v.raw, minVal, maxVal); - return v; -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(lerp)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_lerp(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(lerpc)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_lerpc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(mix)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_mix(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(mixc)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_mixc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @returns 0.0 if x < edge, else 1.0 - */ -CGLM_INLINE -vec4s -glms_vec4_(step)(vec4s edge, vec4s x) { - vec4s r; - glm_vec4_step(edge.raw, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold function with a smooth transition (unidimensional) - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(smoothstep_uni)(float edge0, float edge1, vec4s x) { - vec4s r; - glm_vec4_smoothstep_uni(edge0, edge1, x.raw, r.raw); - return r; -} - -/*! - * @brief threshold function with a smooth transition - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(smoothstep)(vec4s edge0, vec4s edge1, vec4s x) { - vec4s r; - glm_vec4_smoothstep(edge0.raw, edge1.raw, x.raw, r.raw); - return r; -} - -/*! - * @brief smooth Hermite interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(smoothinterp)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_smoothinterp(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief smooth Hermite interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(smoothinterpc)(vec4s from, vec4s to, float t) { - vec4s r; - glm_vec4_smoothinterpc(from.raw, to.raw, t, r.raw); - return r; -} - -/*! - * @brief helper to fill vec4 as [S^3, S^2, S, 1] - * - * @param[in] s parameter - * @returns destination - */ -CGLM_INLINE -vec4s -glms_vec4_(cubic)(float s) { - vec4s r; - glm_vec4_cubic(s, r.raw); - return r; -} - -/*! - * @brief swizzle vector components - * - * you can use existing masks e.g. GLM_XXXX, GLM_WZYX - * - * @param[in] v source - * @param[in] mask mask - * @returns swizzled vector - */ -CGLM_INLINE -vec4s -glms_vec4_(swizzle)(vec4s v, int mask) { - vec4s dest; - glm_vec4_swizzle(v.raw, mask, dest.raw); - return dest; -} - -/*! - * @brief Create four dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @returns constructed 4D vector from raw pointer - */ -CGLM_INLINE -vec4s -glms_vec4_(make)(const float * __restrict src) { - vec4s dest; - glm_vec4_make(src, dest.raw); - return dest; -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] v incident vector - * @param[in] n normalized normal vector - * @returns reflection result - */ -CGLM_INLINE -vec4s -glms_vec4_(reflect)(vec4s v, vec4s n) { - vec4s dest; - glm_vec4_reflect(v.raw, n.raw, dest.raw); - return dest; -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * this implementation does not explicitly preserve the 'w' component of the - * incident vector 'I' in the output 'dest', users requiring the preservation of - * the 'w' component should manually adjust 'dest' after calling this function. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glms_vec4_(refract)(vec4s v, vec4s n, float eta, vec4s * __restrict dest) { - return glm_vec4_refract(v.raw, n.raw, eta, dest->raw); -} - -#endif /* cglms_vec4s_h */ diff --git a/external/cglm/types-struct.h b/external/cglm/types-struct.h deleted file mode 100644 index d93152e..0000000 --- a/external/cglm/types-struct.h +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_types_struct_h -#define cglm_types_struct_h - -#include "types.h" - -/* - * Anonymous structs are available since C11, but we'd like to be compatible - * with C99 and C89 too. So let's figure out if we should be using them or not. - * It's simply a convenience feature, you can e.g. build the library with - * anonymous structs and your application without them and they'll still be - * compatible, cglm doesn't use the anonymous structs internally. - */ -#ifndef CGLM_USE_ANONYMOUS_STRUCT - /* If the user doesn't explicitly specify if they want anonymous structs or - * not, then we'll try to intuit an appropriate choice. */ -# if defined(CGLM_NO_ANONYMOUS_STRUCT) - /* The user has defined CGLM_NO_ANONYMOUS_STRUCT. This used to be the - * only #define governing the use of anonymous structs, so for backward - * compatibility, we still honor that choice and disable them. */ -# define CGLM_USE_ANONYMOUS_STRUCT 0 - /* Disable anonymous structs if strict ANSI mode is enabled for C89 or C99 */ -# elif defined(__STRICT_ANSI__) && \ - (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 201112L)) - /* __STRICT_ANSI__ is defined and we're in C89 - * or C99 mode (C11 or later not detected) */ -# define CGLM_USE_ANONYMOUS_STRUCT 0 -# elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) - /* We're compiling for C11 or this is the MSVC compiler. In either - * case, anonymous structs are available, so use them. */ -# define CGLM_USE_ANONYMOUS_STRUCT 1 -# elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) - /* GCC 4.6 and onwards support anonymous structs as an extension */ -# define CGLM_USE_ANONYMOUS_STRUCT 1 -# elif defined(__clang__) && __clang_major__ >= 3 - /* Clang 3.0 and onwards support anonymous structs as an extension */ -# define CGLM_USE_ANONYMOUS_STRUCT 1 -# elif defined(_MSC_VER) && (_MSC_VER >= 1900) /* Visual Studio 2015 */ - /* We can support anonymous structs - * since Visual Studio 2015 or 2017 (1910) maybe? */ -# define CGLM_USE_ANONYMOUS_STRUCT 1 -# else - /* Otherwise, we're presumably building for C99 or C89 and can't rely - * on anonymous structs being available. Turn them off. */ -# define CGLM_USE_ANONYMOUS_STRUCT 0 -# endif -#endif - -typedef union vec2s { - vec2 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float x; - float y; - }; - - struct { - float r; - float i; - }; - - struct { - float u; - float v; - }; - - struct { - float s; - float t; - }; -#endif -} vec2s; - -typedef union vec3s { - vec3 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float x; - float y; - float z; - }; - - struct { - float r; - float g; - float b; - }; -#endif -} vec3s; - -typedef union ivec2s { - ivec2 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - int x; - int y; - }; - - struct { - int r; - int i; - }; - - struct { - int u; - int v; - }; - - struct { - int s; - int t; - }; -#endif -} ivec2s; - -typedef union ivec3s { - ivec3 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - int x; - int y; - int z; - }; - - struct { - int r; - int g; - int b; - }; -#endif -} ivec3s; - -typedef union ivec4s { - ivec4 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - int x; - int y; - int z; - int w; - }; - - struct { - int r; - int g; - int b; - int a; - }; -#endif -} ivec4s; - -typedef union CGLM_ALIGN_IF(16) vec4s { - vec4 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float x; - float y; - float z; - float w; - }; - - struct { - float r; - float g; - float b; - float a; - }; -#endif -} vec4s; - -typedef union CGLM_ALIGN_IF(16) versors { - vec4 raw; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float x; - float y; - float z; - float w; - }; - - struct { - vec3s imag; - float real; - }; -#endif -} versors; - -typedef union mat2s { - mat2 raw; - vec2s col[2]; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01; - float m10, m11; - }; -#endif -} mat2s; - -typedef union mat2x3s { - mat2x3 raw; - vec3s col[2]; /* [col (2), row (3)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02; - float m10, m11, m12; - }; -#endif -} mat2x3s; - -typedef union mat2x4s { - mat2x4 raw; - vec4s col[2]; /* [col (2), row (4)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02, m03; - float m10, m11, m12, m13; - }; -#endif -} mat2x4s; - -typedef union mat3s { - mat3 raw; - vec3s col[3]; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02; - float m10, m11, m12; - float m20, m21, m22; - }; -#endif -} mat3s; - -typedef union mat3x2s { - mat3x2 raw; - vec2s col[3]; /* [col (3), row (2)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01; - float m10, m11; - float m20, m21; - }; -#endif -} mat3x2s; - -typedef union mat3x4s { - mat3x4 raw; - vec4s col[3]; /* [col (3), row (4)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02, m03; - float m10, m11, m12, m13; - float m20, m21, m22, m23; - }; -#endif -} mat3x4s; - -typedef union CGLM_ALIGN_MAT mat4s { - mat4 raw; - vec4s col[4]; -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02, m03; - float m10, m11, m12, m13; - float m20, m21, m22, m23; - float m30, m31, m32, m33; - }; -#endif -} mat4s; - -typedef union mat4x2s { - mat4x2 raw; - vec2s col[4]; /* [col (4), row (2)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01; - float m10, m11; - float m20, m21; - float m30, m31; - }; -#endif -} mat4x2s; - -typedef union mat4x3s { - mat4x3 raw; - vec3s col[4]; /* [col (4), row (3)] */ -#if CGLM_USE_ANONYMOUS_STRUCT - struct { - float m00, m01, m02; - float m10, m11, m12; - float m20, m21, m22; - float m30, m31, m32; - }; -#endif -} mat4x3s; - -#endif /* cglm_types_struct_h */ diff --git a/external/cglm/types.h b/external/cglm/types.h deleted file mode 100644 index 7a482c0..0000000 --- a/external/cglm/types.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_types_h -#define cglm_types_h - -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) -# include -#endif - -#if defined(_MSC_VER) -/* do not use alignment for older visual studio versions */ -/* also ARM32 also causes similar error, disable it for now on ARM32 too */ -# if _MSC_VER < 1913 || _M_ARM /* Visual Studio 2017 version 15.6 */ -# define CGLM_ALL_UNALIGNED -# define CGLM_ALIGN(X) /* no alignment */ -# else -# define CGLM_ALIGN(X) __declspec(align(X)) -# endif -#else -# define CGLM_ALIGN(X) __attribute((aligned(X))) -#endif - -#ifndef CGLM_ALL_UNALIGNED -# define CGLM_ALIGN_IF(X) CGLM_ALIGN(X) -#else -# define CGLM_ALIGN_IF(X) /* no alignment */ -#endif - -#ifdef __AVX__ -# define CGLM_ALIGN_MAT CGLM_ALIGN(32) -#else -# define CGLM_ALIGN_MAT CGLM_ALIGN(16) -#endif - -#ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED - -# if defined(__has_builtin) -# if __has_builtin(__builtin_assume_aligned) -# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1 -# endif -# elif defined(__GNUC__) && defined(__GNUC_MINOR__) -# if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7 -# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 1 -# endif -# endif - -# ifndef CGLM_HAVE_BUILTIN_ASSUME_ALIGNED -# define CGLM_HAVE_BUILTIN_ASSUME_ALIGNED 0 -# endif - -#endif - -#if CGLM_HAVE_BUILTIN_ASSUME_ALIGNED -# define CGLM_ASSUME_ALIGNED(expr, alignment) \ - __builtin_assume_aligned((expr), (alignment)) -#else -# define CGLM_ASSUME_ALIGNED(expr, alignment) (expr) -#endif - -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) -# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ - ((type*)CGLM_ASSUME_ALIGNED((expr), alignof(type))) -#elif defined(_MSC_VER) -# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ - ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof(type))) -#else -# define CGLM_CASTPTR_ASSUME_ALIGNED(expr, type) \ - ((type*)CGLM_ASSUME_ALIGNED((expr), __alignof__(type))) -#endif - -typedef int ivec2[2]; -typedef int ivec3[3]; -typedef int ivec4[4]; - -typedef float vec2[2]; -typedef float vec3[3]; -typedef CGLM_ALIGN_IF(16) float vec4[4]; -typedef vec4 versor; /* |x, y, z, w| -> w is the last */ -typedef vec3 mat3[3]; -typedef vec2 mat3x2[3]; /* [col (3), row (2)] */ -typedef vec4 mat3x4[3]; /* [col (3), row (4)] */ -typedef CGLM_ALIGN_IF(16) vec2 mat2[2]; -typedef vec3 mat2x3[2]; /* [col (2), row (3)] */ -typedef vec4 mat2x4[2]; /* [col (2), row (4)] */ -typedef CGLM_ALIGN_MAT vec4 mat4[4]; -typedef vec2 mat4x2[4]; /* [col (4), row (2)] */ -typedef vec3 mat4x3[4]; /* [col (4), row (3)] */ - -/* - Important: cglm stores quaternion as [x, y, z, w] in memory since v0.4.0 - it was [w, x, y, z] before v0.4.0 ( v0.3.5 and earlier ). w is real part. -*/ - -#define GLM_E 2.71828182845904523536028747135266250 /* e */ -#define GLM_LOG2E 1.44269504088896340735992468100189214 /* log2(e) */ -#define GLM_LOG10E 0.434294481903251827651128918916605082 /* log10(e) */ -#define GLM_LN2 0.693147180559945309417232121458176568 /* loge(2) */ -#define GLM_LN10 2.30258509299404568401799145468436421 /* loge(10) */ -#define GLM_PI 3.14159265358979323846264338327950288 /* pi */ -#define GLM_PI_2 1.57079632679489661923132169163975144 /* pi/2 */ -#define GLM_PI_4 0.785398163397448309615660845819875721 /* pi/4 */ -#define GLM_1_PI 0.318309886183790671537767526745028724 /* 1/pi */ -#define GLM_2_PI 0.636619772367581343075535053490057448 /* 2/pi */ -#define GLM_TAU 6.283185307179586476925286766559005768 /* tau */ -#define GLM_TAU_2 GLM_PI /* tau/2 */ -#define GLM_TAU_4 GLM_PI_2 /* tau/4 */ -#define GLM_1_TAU 0.159154943091895335768883763372514362 /* 1/tau */ -#define GLM_2_TAU 0.318309886183790671537767526745028724 /* 2/tau */ -#define GLM_2_SQRTPI 1.12837916709551257389615890312154517 /* 2/sqrt(pi) */ -#define GLM_SQRTTAU 2.506628274631000502415765284811045253 /* sqrt(tau) */ -#define GLM_SQRT2 1.41421356237309504880168872420969808 /* sqrt(2) */ -#define GLM_SQRT1_2 0.707106781186547524400844362104849039 /* 1/sqrt(2) */ - -#define GLM_Ef ((float)GLM_E) -#define GLM_LOG2Ef ((float)GLM_LOG2E) -#define GLM_LOG10Ef ((float)GLM_LOG10E) -#define GLM_LN2f ((float)GLM_LN2) -#define GLM_LN10f ((float)GLM_LN10) -#define GLM_PIf ((float)GLM_PI) -#define GLM_PI_2f ((float)GLM_PI_2) -#define GLM_PI_4f ((float)GLM_PI_4) -#define GLM_1_PIf ((float)GLM_1_PI) -#define GLM_2_PIf ((float)GLM_2_PI) -#define GLM_TAUf ((float)GLM_TAU) -#define GLM_TAU_2f ((float)GLM_TAU_2) -#define GLM_TAU_4f ((float)GLM_TAU_4) -#define GLM_1_TAUf ((float)GLM_1_TAU) -#define GLM_2_TAUf ((float)GLM_2_TAU) -#define GLM_2_SQRTPIf ((float)GLM_2_SQRTPI) -#define GLM_2_SQRTTAUf ((float)GLM_SQRTTAU) -#define GLM_SQRT2f ((float)GLM_SQRT2) -#define GLM_SQRT1_2f ((float)GLM_SQRT1_2) - -/* DEPRECATED! use GLM_PI and friends */ -#define CGLM_PI GLM_PIf -#define CGLM_PI_2 GLM_PI_2f -#define CGLM_PI_4 GLM_PI_4f - -#endif /* cglm_types_h */ diff --git a/external/cglm/util.h b/external/cglm/util.h deleted file mode 100644 index 8c5f2cb..0000000 --- a/external/cglm/util.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE int glm_sign(int val); - CGLM_INLINE float glm_signf(float val); - CGLM_INLINE float glm_rad(float deg); - CGLM_INLINE float glm_deg(float rad); - CGLM_INLINE void glm_make_rad(float *deg); - CGLM_INLINE void glm_make_deg(float *rad); - CGLM_INLINE float glm_pow2(float x); - CGLM_INLINE float glm_min(float a, float b); - CGLM_INLINE float glm_max(float a, float b); - CGLM_INLINE float glm_clamp(float val, float minVal, float maxVal); - CGLM_INLINE float glm_clamp_zo(float val, float minVal, float maxVal); - CGLM_INLINE float glm_lerp(float from, float to, float t); - CGLM_INLINE float glm_lerpc(float from, float to, float t); - CGLM_INLINE float glm_step(float edge, float x); - CGLM_INLINE float glm_smooth(float t); - CGLM_INLINE float glm_smoothstep(float edge0, float edge1, float x); - CGLM_INLINE float glm_smoothinterp(float from, float to, float t); - CGLM_INLINE float glm_smoothinterpc(float from, float to, float t); - CGLM_INLINE bool glm_eq(float a, float b); - CGLM_INLINE float glm_percent(float from, float to, float current); - CGLM_INLINE float glm_percentc(float from, float to, float current); - */ - -#ifndef cglm_util_h -#define cglm_util_h - -#include "common.h" - -#define GLM_MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) -#define GLM_MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) - -/*! - * @brief get sign of 32 bit integer as +1, -1, 0 - * - * Important: It returns 0 for zero input - * - * @param val integer value - */ -CGLM_INLINE -int -glm_sign(int val) { - return ((val >> 31) - (-val >> 31)); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param val float value - */ -CGLM_INLINE -float -glm_signf(float val) { - return (float)((val > 0.0f) - (val < 0.0f)); -} - -/*! - * @brief convert degree to radians - * - * @param[in] deg angle in degrees - */ -CGLM_INLINE -float -glm_rad(float deg) { - return deg * GLM_PIf / 180.0f; -} - -/*! - * @brief convert radians to degree - * - * @param[in] rad angle in radians - */ -CGLM_INLINE -float -glm_deg(float rad) { - return rad * 180.0f / GLM_PIf; -} - -/*! - * @brief convert existing degree to radians. this will override degrees value - * - * @param[in, out] deg pointer to angle in degrees - */ -CGLM_INLINE -void -glm_make_rad(float *deg) { - *deg = *deg * GLM_PIf / 180.0f; -} - -/*! - * @brief convert existing radians to degree. this will override radians value - * - * @param[in, out] rad pointer to angle in radians - */ -CGLM_INLINE -void -glm_make_deg(float *rad) { - *rad = *rad * 180.0f / GLM_PIf; -} - -/*! - * @brief multiplies given parameter with itself = x * x or powf(x, 2) - * - * @param[in] x x - */ -CGLM_INLINE -float -glm_pow2(float x) { - return x * x; -} - -/*! - * @brief find minimum of given two values - * - * @param[in] a number 1 - * @param[in] b number 2 - */ -CGLM_INLINE -float -glm_min(float a, float b) { - if (a < b) - return a; - return b; -} - -/*! - * @brief find maximum of given two values - * - * @param[in] a number 1 - * @param[in] b number 2 - */ -CGLM_INLINE -float -glm_max(float a, float b) { - if (a > b) - return a; - return b; -} - -/*! - * @brief find minimum of given two values - * - * @param[in] a number 1 - * @param[in] b number 2 - * - * @return smallest of the two values - */ -CGLM_INLINE -int -glm_imin(int a, int b) { - if (a < b) - return a; - return b; -} - -/*! - * @brief find maximum of given two values - * - * @param[in] a number 1 - * @param[in] b number 2 - * - * @return largest of the two values - */ -CGLM_INLINE -int -glm_imax(int a, int b) { - if (a > b) - return a; - return b; -} - -/*! - * @brief clamp a number between min and max - * - * @param[in] val value to clamp - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -float -glm_clamp(float val, float minVal, float maxVal) { - return glm_min(glm_max(val, minVal), maxVal); -} - -/*! - * @brief clamp a number to zero and one - * - * @param[in] val value to clamp - */ -CGLM_INLINE -float -glm_clamp_zo(float val) { - return glm_clamp(val, 0.0f, 1.0f); -} - -/*! - * @brief linear interpolation between two numbers - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - */ -CGLM_INLINE -float -glm_lerp(float from, float to, float t) { - return from + t * (to - from); -} - -/*! - * @brief clamped linear interpolation between two numbers - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - */ -CGLM_INLINE -float -glm_lerpc(float from, float to, float t) { - return glm_lerp(from, to, glm_clamp_zo(t)); -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @return returns 0.0 if x < edge, else 1.0 - */ -CGLM_INLINE -float -glm_step(float edge, float x) { - /* branching - no type conversion */ - return (x < edge) ? 0.0f : 1.0f; - /* - * An alternative implementation without branching - * but with type conversion could be: - * return !(x < edge); - */ -} - -/*! - * @brief smooth Hermite interpolation - * - * formula: t^2 * (3-2t) - * - * @param[in] t interpolant (amount) - */ -CGLM_INLINE -float -glm_smooth(float t) { - return t * t * (3.0f - 2.0f * t); -} - -/*! - * @brief threshold function with a smooth transition (according to OpenCL specs) - * - * formula: t^2 * (3-2t) - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x interpolant (amount) - */ -CGLM_INLINE -float -glm_smoothstep(float edge0, float edge1, float x) { - float t; - t = glm_clamp_zo((x - edge0) / (edge1 - edge0)); - return glm_smooth(t); -} - -/*! - * @brief smoothstep interpolation between two numbers - * - * formula: from + smoothstep(t) * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - */ -CGLM_INLINE -float -glm_smoothinterp(float from, float to, float t) { - return from + glm_smooth(t) * (to - from); -} - -/*! - * @brief clamped smoothstep interpolation between two numbers - * - * formula: from + smoothstep(t) * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - */ -CGLM_INLINE -float -glm_smoothinterpc(float from, float to, float t) { - return glm_smoothinterp(from, to, glm_clamp_zo(t)); -} - -/*! - * @brief check if two float equal with using EPSILON - * - * @param[in] a a - * @param[in] b b - */ -CGLM_INLINE -bool -glm_eq(float a, float b) { - return fabsf(a - b) <= GLM_FLT_EPSILON; -} - -/*! - * @brief percentage of current value between start and end value - * - * maybe fraction could be alternative name. - * - * @param[in] from from value - * @param[in] to to value - * @param[in] current current value - */ -CGLM_INLINE -float -glm_percent(float from, float to, float current) { - float t; - - if ((t = to - from) == 0.0f) - return 1.0f; - - return (current - from) / t; -} - -/*! - * @brief clamped percentage of current value between start and end value - * - * @param[in] from from value - * @param[in] to to value - * @param[in] current current value - */ -CGLM_INLINE -float -glm_percentc(float from, float to, float current) { - return glm_clamp_zo(glm_percent(from, to, current)); -} - -/*! -* @brief swap two float values -* -* @param[in] a float value 1 (pointer) -* @param[in] b float value 2 (pointer) -*/ -CGLM_INLINE -void -glm_swapf(float * __restrict a, float * __restrict b) { - float t; - t = *a; - *a = *b; - *b = t; -} - -#endif /* cglm_util_h */ diff --git a/external/cglm/vec2-ext.h b/external/cglm/vec2-ext.h deleted file mode 100644 index 6186f07..0000000 --- a/external/cglm/vec2-ext.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Functions: - CGLM_INLINE void glm_vec2_fill(vec2 v, float val) - CGLM_INLINE bool glm_vec2_eq(vec2 v, float val); - CGLM_INLINE bool glm_vec2_eq_eps(vec2 v, float val); - CGLM_INLINE bool glm_vec2_eq_all(vec2 v); - CGLM_INLINE bool glm_vec2_eqv(vec2 a, vec2 b); - CGLM_INLINE bool glm_vec2_eqv_eps(vec2 a, vec2 b); - CGLM_INLINE float glm_vec2_max(vec2 v); - CGLM_INLINE float glm_vec2_min(vec2 v); - CGLM_INLINE bool glm_vec2_isnan(vec2 v); - CGLM_INLINE bool glm_vec2_isinf(vec2 v); - CGLM_INLINE bool glm_vec2_isvalid(vec2 v); - CGLM_INLINE void glm_vec2_sign(vec2 v, vec2 dest); - CGLM_INLINE void glm_vec2_abs(vec2 v, vec2 dest); - CGLM_INLINE void glm_vec2_fract(vec2 v, vec2 dest); - CGLM_INLINE void glm_vec2_floor(vec2 v, vec2 dest); - CGLM_INLINE float glm_vec2_mods(vec2 v, float s, vec2 dest); - CGLM_INLINE float glm_vec2_steps(float edge, vec2 v, vec2 dest); - CGLM_INLINE void glm_vec2_stepr(vec2 edge, float v, vec2 dest); - CGLM_INLINE void glm_vec2_sqrt(vec2 v, vec2 dest); - CGLM_INLINE void glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_complex_conjugate(vec2 a, vec2 dest) - */ - -#ifndef cglm_vec2_ext_h -#define cglm_vec2_ext_h - -#include "common.h" -#include "util.h" - -/*! - * @brief fill a vector with specified value - * - * @param[out] v dest - * @param[in] val value - */ -CGLM_INLINE -void -glm_vec2_fill(vec2 v, float val) { - v[0] = v[1] = val; -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_vec2_eq(vec2 v, float val) { - return v[0] == val && v[0] == v[1]; -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_vec2_eq_eps(vec2 v, float val) { - return fabsf(v[0] - val) <= GLM_FLT_EPSILON - && fabsf(v[1] - val) <= GLM_FLT_EPSILON; -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec2_eq_all(vec2 v) { - return glm_vec2_eq_eps(v, v[0]); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_vec2_eqv(vec2 a, vec2 b) { - return a[0] == b[0] && a[1] == b[1]; -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_vec2_eqv_eps(vec2 a, vec2 b) { - return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON - && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON; -} - -/*! - * @brief max value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glm_vec2_max(vec2 v) { - return glm_max(v[0], v[1]); -} - -/*! - * @brief min value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glm_vec2_min(vec2 v) { - return glm_min(v[0], v[1]); -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec2_isnan(vec2 v) { -#ifndef CGLM_FAST_MATH - return isnan(v[0]) || isnan(v[1]); -#else - return false; -#endif -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec2_isinf(vec2 v) { -#ifndef CGLM_FAST_MATH - return isinf(v[0]) || isinf(v[1]); -#else - return false; -#endif -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec2_isvalid(vec2 v) { - return !glm_vec2_isnan(v) && !glm_vec2_isinf(v); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - */ -CGLM_INLINE -void -glm_vec2_sign(vec2 v, vec2 dest) { - dest[0] = glm_signf(v[0]); - dest[1] = glm_signf(v[1]); -} - -/*! - * @brief absolute value of v - * - * @param[in] v vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_abs(vec2 v, vec2 dest) { - dest[0] = fabsf(v[0]); - dest[1] = fabsf(v[1]); -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_fract(vec2 v, vec2 dest) { - dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); - dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_floor(vec2 v, vec2 dest) { - dest[0] = floorf(v[0]); - dest[1] = floorf(v[1]); -} - -/*! - * @brief mod of each vector item, result is written to dest (dest = v % s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_mods(vec2 v, float s, vec2 dest) { - dest[0] = fmodf(v[0], s); - dest[1] = fmodf(v[1], s); -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_sqrt(vec2 v, vec2 dest) { - dest[0] = sqrtf(v[0]); - dest[1] = sqrtf(v[1]); -} - -/*! - * @brief treat vectors as complex numbers and multiply them as such. - * - * @param[in] a left number - * @param[in] b right number - * @param[out] dest destination number - */ -CGLM_INLINE -void -glm_vec2_complex_mul(vec2 a, vec2 b, vec2 dest) { - float tr, ti; - tr = a[0] * b[0] - a[1] * b[1]; - ti = a[0] * b[1] + a[1] * b[0]; - dest[0] = tr; - dest[1] = ti; -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_steps(float edge, vec2 x, vec2 dest) { - dest[0] = glm_step(edge, x[0]); - dest[1] = glm_step(edge, x[1]); -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_stepr(vec2 edge, float x, vec2 dest) { - dest[0] = glm_step(edge[0], x); - dest[1] = glm_step(edge[1], x); -} - -/*! - * @brief treat vectors as complex numbers and divide them as such. - * - * @param[in] a left number (numerator) - * @param[in] b right number (denominator) - * @param[out] dest destination number - */ -CGLM_INLINE -void -glm_vec2_complex_div(vec2 a, vec2 b, vec2 dest) { - float tr, ti; - float const ibnorm2 = 1.0f / (b[0] * b[0] + b[1] * b[1]); - tr = ibnorm2 * (a[0] * b[0] + a[1] * b[1]); - ti = ibnorm2 * (a[1] * b[0] - a[0] * b[1]); - dest[0] = tr; - dest[1] = ti; -} - -/*! - * @brief treat the vector as a complex number and conjugate it as such. - * - * @param[in] a the number - * @param[out] dest destination number - */ -CGLM_INLINE -void -glm_vec2_complex_conjugate(vec2 a, vec2 dest) { - dest[0] = a[0]; - dest[1] = -a[1]; -} - -#endif /* cglm_vec2_ext_h */ diff --git a/external/cglm/vec2.h b/external/cglm/vec2.h deleted file mode 100644 index 655fb4b..0000000 --- a/external/cglm/vec2.h +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_VEC2_ONE_INIT - GLM_VEC2_ZERO_INIT - GLM_VEC2_ONE - GLM_VEC2_ZERO - - Functions: - CGLM_INLINE void glm_vec2(float * __restrict v, vec2 dest) - CGLM_INLINE void glm_vec2_copy(vec2 a, vec2 dest) - CGLM_INLINE void glm_vec2_zero(vec2 v) - CGLM_INLINE void glm_vec2_one(vec2 v) - CGLM_INLINE float glm_vec2_dot(vec2 a, vec2 b) - CGLM_INLINE float glm_vec2_cross(vec2 a, vec2 b) - CGLM_INLINE float glm_vec2_norm2(vec2 v) - CGLM_INLINE float glm_vec2_norm(vec2 vec) - CGLM_INLINE void glm_vec2_add(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_adds(vec2 v, float s, vec2 dest) - CGLM_INLINE void glm_vec2_sub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_subs(vec2 v, float s, vec2 dest) - CGLM_INLINE void glm_vec2_mul(vec2 a, vec2 b, vec2 d) - CGLM_INLINE void glm_vec2_scale(vec2 v, float s, vec2 dest) - CGLM_INLINE void glm_vec2_scale_as(vec2 v, float s, vec2 dest) - CGLM_INLINE void glm_vec2_div(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_divs(vec2 v, float s, vec2 dest) - CGLM_INLINE void glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_muladds(vec2 a, float s, vec2 dest) - CGLM_INLINE void glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_subsub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_addsub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_mulsubs(vec2 a, float s, vec2 dest) - CGLM_INLINE void glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_minsub(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE void glm_vec2_negate_to(vec2 v, vec2 dest) - CGLM_INLINE void glm_vec2_negate(vec2 v) - CGLM_INLINE void glm_vec2_normalize(vec2 v) - CGLM_INLINE void glm_vec2_normalize_to(vec2 vec, vec2 dest) - CGLM_INLINE void glm_vec2_rotate(vec2 v, float angle, vec2 dest) - CGLM_INLINE void glm_vec2_center(vec2 a, vec2 b, vec2 dest) - CGLM_INLINE float glm_vec2_distance2(vec2 a, vec2 b) - CGLM_INLINE float glm_vec2_distance(vec2 a, vec2 b) - CGLM_INLINE void glm_vec2_maxv(vec2 v1, vec2 v2, vec2 dest) - CGLM_INLINE void glm_vec2_minv(vec2 v1, vec2 v2, vec2 dest) - CGLM_INLINE void glm_vec2_clamp(vec2 v, float minVal, float maxVal) - CGLM_INLINE void glm_vec2_swizzle(vec2 v, int mask, vec2 dest) - CGLM_INLINE void glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) - CGLM_INLINE void glm_vec2_step(vec2 edge, vec2 x, vec2 dest) - CGLM_INLINE void glm_vec2_make(float * restrict src, vec2 dest) - CGLM_INLINE void glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) - CGLM_INLINE void glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) - */ - -#ifndef cglm_vec2_h -#define cglm_vec2_h - -#include "common.h" -#include "util.h" -#include "vec2-ext.h" - -#define GLM_VEC2_ONE_INIT {1.0f, 1.0f} -#define GLM_VEC2_ZERO_INIT {0.0f, 0.0f} - -#define GLM_VEC2_ONE ((vec2)GLM_VEC2_ONE_INIT) -#define GLM_VEC2_ZERO ((vec2)GLM_VEC2_ZERO_INIT) - -/*! - * @brief init vec2 using another vector - * - * @param[in] v a vector - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2(float * __restrict v, vec2 dest) { - dest[0] = v[0]; - dest[1] = v[1]; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] a source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_copy(vec2 a, vec2 dest) { - dest[0] = a[0]; - dest[1] = a[1]; -} - -/*! - * @brief make vector zero - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec2_zero(vec2 v) { - v[0] = v[1] = 0.0f; -} - -/*! - * @brief make vector one - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec2_one(vec2 v) { - v[0] = v[1] = 1.0f; -} - -/*! - * @brief vec2 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glm_vec2_dot(vec2 a, vec2 b) { - return a[0] * b[0] + a[1] * b[1]; -} - -/*! - * @brief vec2 cross product - * - * REF: http://allenchou.net/2013/07/cross-product-of-2d-vectors/ - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return Z component of cross product - */ -CGLM_INLINE -float -glm_vec2_cross(vec2 a, vec2 b) { - /* just calculate the z-component */ - return a[0] * b[1] - a[1] * b[0]; -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -float -glm_vec2_norm2(vec2 v) { - return glm_vec2_dot(v, v); -} - -/*! - * @brief norm (magnitude) of vec2 - * - * @param[in] vec vector - * - * @return norm - */ -CGLM_INLINE -float -glm_vec2_norm(vec2 vec) { - return sqrtf(glm_vec2_norm2(vec)); -} - -/*! - * @brief add a vector to b vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_add(vec2 a, vec2 b, vec2 dest) { - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_adds(vec2 v, float s, vec2 dest) { - dest[0] = v[0] + s; - dest[1] = v[1] + s; -} - -/*! - * @brief subtract b vector from a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_sub(vec2 a, vec2 b, vec2 dest) { - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_subs(vec2 v, float s, vec2 dest) { - dest[0] = v[0] - s; - dest[1] = v[1] - s; -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a v1 - * @param b v2 - * @param dest v3 = (a[0] * b[0], a[1] * b[1]) - */ -CGLM_INLINE -void -glm_vec2_mul(vec2 a, vec2 b, vec2 dest) { - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; -} - -/*! - * @brief multiply/scale vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_scale(vec2 v, float s, vec2 dest) { - dest[0] = v[0] * s; - dest[1] = v[1] * s; -} - -/*! - * @brief scale as vector specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_scale_as(vec2 v, float s, vec2 dest) { - float norm; - norm = glm_vec2_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec2_zero(dest); - return; - } - - glm_vec2_scale(v, s / norm, dest); -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]/b[0], a[1]/b[1]) - */ -CGLM_INLINE -void -glm_vec2_div(vec2 a, vec2 b, vec2 dest) { - dest[0] = a[0] / b[0]; - dest[1] = a[1] / b[1]; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest result = (a[0]/s, a[1]/s) - */ -CGLM_INLINE -void -glm_vec2_divs(vec2 v, float s, vec2 dest) { - dest[0] = v[0] / s; - dest[1] = v[1] / s; -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_vec2_addadd(vec2 a, vec2 b, vec2 dest) { - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_vec2_subadd(vec2 a, vec2 b, vec2 dest) { - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec2_muladd(vec2 a, vec2 b, vec2 dest) { - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec2_muladds(vec2 a, float s, vec2 dest) { - dest[0] += a[0] * s; - dest[1] += a[1] * s; -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_vec2_maxadd(vec2 a, vec2 b, vec2 dest) { - dest[0] += glm_max(a[0], b[0]); - dest[1] += glm_max(a[1], b[1]); -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_vec2_minadd(vec2 a, vec2 b, vec2 dest) { - dest[0] += glm_min(a[0], b[0]); - dest[1] += glm_min(a[1], b[1]); -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_vec2_subsub(vec2 a, vec2 b, vec2 dest) { - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_vec2_addsub(vec2 a, vec2 b, vec2 dest) { - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec2_mulsub(vec2 a, vec2 b, vec2 dest) { - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; -} - -/*! - * @brief mul vector with scalar and sub result to sum - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec2_mulsubs(vec2 a, float s, vec2 dest) { - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; -} - -/*! - * @brief sub max of two vectors to result/dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_vec2_maxsub(vec2 a, vec2 b, vec2 dest) { - dest[0] -= glm_max(a[0], b[0]); - dest[1] -= glm_max(a[1], b[1]); -} - -/*! - * @brief sub min of two vectors to result/dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_vec2_minsub(vec2 a, vec2 b, vec2 dest) { - dest[0] -= glm_min(a[0], b[0]); - dest[1] -= glm_min(a[1], b[1]); -} - -/*! - * @brief negate vector components and store result in dest - * - * @param[in] v vector - * @param[out] dest result vector - */ -CGLM_INLINE -void -glm_vec2_negate_to(vec2 v, vec2 dest) { - dest[0] = -v[0]; - dest[1] = -v[1]; -} - -/*! - * @brief negate vector components - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec2_negate(vec2 v) { - glm_vec2_negate_to(v, v); -} - -/*! - * @brief normalize vector and store result in same vec - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec2_normalize(vec2 v) { - float norm; - - norm = glm_vec2_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - v[0] = v[1] = 0.0f; - return; - } - - glm_vec2_scale(v, 1.0f / norm, v); -} - -/*! - * @brief normalize vector to dest - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_normalize_to(vec2 v, vec2 dest) { - float norm; - - norm = glm_vec2_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec2_zero(dest); - return; - } - - glm_vec2_scale(v, 1.0f / norm, dest); -} - -/*! - * @brief rotate vec2 around origin by angle (CCW: counterclockwise) - * - * Formula: - * 𝑥2 = cos(a)𝑥1 − sin(a)𝑦1 - * 𝑦2 = sin(a)𝑥1 + cos(a)𝑦1 - * - * @param[in] v vector to rotate - * @param[in] angle angle by radians - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_rotate(vec2 v, float angle, vec2 dest) { - float c, s, x1, y1; - - c = cosf(angle); - s = sinf(angle); - - x1 = v[0]; - y1 = v[1]; - - dest[0] = c * x1 - s * y1; - dest[1] = s * x1 + c * y1; -} - -/** - * @brief find center point of two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest center point - */ -CGLM_INLINE -void -glm_vec2_center(vec2 a, vec2 b, vec2 dest) { - glm_vec2_add(a, b, dest); - glm_vec2_scale(dest, 0.5f, dest); -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -float -glm_vec2_distance2(vec2 a, vec2 b) { - return glm_pow2(b[0] - a[0]) + glm_pow2(b[1] - a[1]); -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns distance - */ -CGLM_INLINE -float -glm_vec2_distance(vec2 a, vec2 b) { - return sqrtf(glm_vec2_distance2(a, b)); -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_maxv(vec2 a, vec2 b, vec2 dest) { - dest[0] = glm_max(a[0], b[0]); - dest[1] = glm_max(a[1], b[1]); -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_minv(vec2 a, vec2 b, vec2 dest) { - dest[0] = glm_min(a[0], b[0]); - dest[1] = glm_min(a[1], b[1]); -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in, out] v vector - * @param[in] minval minimum value - * @param[in] maxval maximum value - */ -CGLM_INLINE -void -glm_vec2_clamp(vec2 v, float minval, float maxval) { - v[0] = glm_clamp(v[0], minval, maxval); - v[1] = glm_clamp(v[1], minval, maxval); -} - -/*! - * @brief swizzle vector components - * - * @param[in] v source - * @param[in] mask mask - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_swizzle(vec2 v, int mask, vec2 dest) { - vec2 t; - - t[0] = v[(mask & (3 << 0))]; - t[1] = v[(mask & (3 << 2)) >> 2]; - - glm_vec2_copy(t, dest); -} - -/*! - * @brief linear interpolation between two vector - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_lerp(vec2 from, vec2 to, float t, vec2 dest) { - vec2 s, v; - - /* from + s * (to - from) */ - glm_vec2_fill(s, glm_clamp_zo(t)); - glm_vec2_sub(to, from, v); - glm_vec2_mul(s, v, v); - glm_vec2_add(from, v, dest); -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec2_step(vec2 edge, vec2 x, vec2 dest) { - dest[0] = glm_step(edge[0], x[0]); - dest[1] = glm_step(edge[1], x[1]); -} - -/*! - * @brief Create two dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec2_make(const float * __restrict src, vec2 dest) { - dest[0] = src[0]; dest[1] = src[1]; -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] v incident vector - * @param[in] n normalized normal vector - * @param[out] dest destination vector for the reflection result - */ -CGLM_INLINE -void -glm_vec2_reflect(vec2 v, vec2 n, vec2 dest) { - vec2 temp; - glm_vec2_scale(n, 2.0f * glm_vec2_dot(v, n), temp); - glm_vec2_sub(v, temp, dest); -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glm_vec2_refract(vec2 v, vec2 n, float eta, vec2 dest) { - float ndi, eni, k; - - ndi = glm_vec2_dot(n, v); - eni = eta * ndi; - k = 1.0f - eta * eta + eni * eni; - - if (k < 0.0f) { - glm_vec2_zero(dest); - return false; - } - - glm_vec2_scale(v, eta, dest); - glm_vec2_mulsubs(n, eni + sqrtf(k), dest); - return true; -} - -#endif /* cglm_vec2_h */ diff --git a/external/cglm/vec3-ext.h b/external/cglm/vec3-ext.h deleted file mode 100644 index 4413cc2..0000000 --- a/external/cglm/vec3-ext.h +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * @brief SIMD like functions - */ - -/* - Functions: - CGLM_INLINE void glm_vec3_broadcast(float val, vec3 d); - CGLM_INLINE void glm_vec3_fill(vec3 v, float val); - CGLM_INLINE bool glm_vec3_eq(vec3 v, float val); - CGLM_INLINE bool glm_vec3_eq_eps(vec3 v, float val); - CGLM_INLINE bool glm_vec3_eq_all(vec3 v); - CGLM_INLINE bool glm_vec3_eqv(vec3 a, vec3 b); - CGLM_INLINE bool glm_vec3_eqv_eps(vec3 a, vec3 b); - CGLM_INLINE float glm_vec3_max(vec3 v); - CGLM_INLINE float glm_vec3_min(vec3 v); - CGLM_INLINE bool glm_vec3_isnan(vec3 v); - CGLM_INLINE bool glm_vec3_isinf(vec3 v); - CGLM_INLINE bool glm_vec3_isvalid(vec3 v); - CGLM_INLINE void glm_vec3_sign(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_abs(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_fract(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_floor(vec3 v, vec3 dest); - CGLM_INLINE float glm_vec3_mods(vec3 v, float s, vec3 dest); - CGLM_INLINE float glm_vec3_steps(float edge, vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_stepr(vec3 edge, float v, vec3 dest); - CGLM_INLINE float glm_vec3_hadd(vec3 v); - CGLM_INLINE void glm_vec3_sqrt(vec3 v, vec3 dest); - */ - -#ifndef cglm_vec3_ext_h -#define cglm_vec3_ext_h - -#include "common.h" -#include "util.h" - -/*! - * @brief fill a vector with specified value - * - * @param[in] val value - * @param[out] d dest - */ -CGLM_INLINE -void -glm_vec3_broadcast(float val, vec3 d) { - d[0] = d[1] = d[2] = val; -} - -/*! - * @brief fill a vector with specified value - * - * @param[out] v dest - * @param[in] val value - */ -CGLM_INLINE -void -glm_vec3_fill(vec3 v, float val) { - v[0] = v[1] = v[2] = val; -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_vec3_eq(vec3 v, float val) { - return v[0] == val && v[0] == v[1] && v[0] == v[2]; -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param[in] v vector - * @param[in] val value - */ -CGLM_INLINE -bool -glm_vec3_eq_eps(vec3 v, float val) { - return fabsf(v[0] - val) <= GLM_FLT_EPSILON - && fabsf(v[1] - val) <= GLM_FLT_EPSILON - && fabsf(v[2] - val) <= GLM_FLT_EPSILON; -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec3_eq_all(vec3 v) { - return glm_vec3_eq_eps(v, v[0]); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_vec3_eqv(vec3 a, vec3 b) { - return a[0] == b[0] - && a[1] == b[1] - && a[2] == b[2]; -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param[in] a vector - * @param[in] b vector - */ -CGLM_INLINE -bool -glm_vec3_eqv_eps(vec3 a, vec3 b) { - return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON - && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON - && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON; -} - -/*! - * @brief max value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glm_vec3_max(vec3 v) { - float max; - - max = v[0]; - if (v[1] > max) - max = v[1]; - if (v[2] > max) - max = v[2]; - - return max; -} - -/*! - * @brief min value of vector - * - * @param[in] v vector - */ -CGLM_INLINE -float -glm_vec3_min(vec3 v) { - float min; - - min = v[0]; - if (v[1] < min) - min = v[1]; - if (v[2] < min) - min = v[2]; - - return min; -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec3_isnan(vec3 v) { -#ifndef CGLM_FAST_MATH - return isnan(v[0]) || isnan(v[1]) || isnan(v[2]); -#else - return false; -#endif -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec3_isinf(vec3 v) { -#ifndef CGLM_FAST_MATH - return isinf(v[0]) || isinf(v[1]) || isinf(v[2]); -#else - return false; -#endif -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec3_isvalid(vec3 v) { - return !glm_vec3_isnan(v) && !glm_vec3_isinf(v); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - */ -CGLM_INLINE -void -glm_vec3_sign(vec3 v, vec3 dest) { - dest[0] = glm_signf(v[0]); - dest[1] = glm_signf(v[1]); - dest[2] = glm_signf(v[2]); -} - -/*! - * @brief absolute value of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_abs(vec3 v, vec3 dest) { - dest[0] = fabsf(v[0]); - dest[1] = fabsf(v[1]); - dest[2] = fabsf(v[2]); -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_fract(vec3 v, vec3 dest) { - dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); - dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); - dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_floor(vec3 v, vec3 dest) { - dest[0] = floorf(v[0]); - dest[1] = floorf(v[1]); - dest[2] = floorf(v[2]); -} - -/*! - * @brief mod of each vector item, result is written to dest (dest = v % s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_mods(vec3 v, float s, vec3 dest) { - dest[0] = fmodf(v[0], s); - dest[1] = fmodf(v[1], s); - dest[2] = fmodf(v[2], s); -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_steps(float edge, vec3 x, vec3 dest) { - dest[0] = glm_step(edge, x[0]); - dest[1] = glm_step(edge, x[1]); - dest[2] = glm_step(edge, x[2]); -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_stepr(vec3 edge, float x, vec3 dest) { - dest[0] = glm_step(edge[0], x); - dest[1] = glm_step(edge[1], x); - dest[2] = glm_step(edge[2], x); -} - -/*! - * @brief vector reduction by summation - * @warning could overflow - * - * @param[in] v vector - * @return sum of all vector's elements - */ -CGLM_INLINE -float -glm_vec3_hadd(vec3 v) { - return v[0] + v[1] + v[2]; -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_sqrt(vec3 v, vec3 dest) { - dest[0] = sqrtf(v[0]); - dest[1] = sqrtf(v[1]); - dest[2] = sqrtf(v[2]); -} - -#endif /* cglm_vec3_ext_h */ diff --git a/external/cglm/vec3.h b/external/cglm/vec3.h deleted file mode 100644 index 1350818..0000000 --- a/external/cglm/vec3.h +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_VEC3_ONE_INIT - GLM_VEC3_ZERO_INIT - GLM_VEC3_ONE - GLM_VEC3_ZERO - GLM_YUP - GLM_ZUP - GLM_XUP - - Functions: - CGLM_INLINE void glm_vec3(vec4 v4, vec3 dest); - CGLM_INLINE void glm_vec3_copy(vec3 a, vec3 dest); - CGLM_INLINE void glm_vec3_zero(vec3 v); - CGLM_INLINE void glm_vec3_one(vec3 v); - CGLM_INLINE float glm_vec3_dot(vec3 a, vec3 b); - CGLM_INLINE float glm_vec3_norm2(vec3 v); - CGLM_INLINE float glm_vec3_norm(vec3 v); - CGLM_INLINE float glm_vec3_norm_one(vec3 v); - CGLM_INLINE float glm_vec3_norm_inf(vec3 v); - CGLM_INLINE void glm_vec3_add(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_adds(vec3 a, float s, vec3 dest); - CGLM_INLINE void glm_vec3_sub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_subs(vec3 a, float s, vec3 dest); - CGLM_INLINE void glm_vec3_mul(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_scale(vec3 v, float s, vec3 dest); - CGLM_INLINE void glm_vec3_scale_as(vec3 v, float s, vec3 dest); - CGLM_INLINE void glm_vec3_div(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_divs(vec3 a, float s, vec3 dest); - CGLM_INLINE void glm_vec3_addadd(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_subadd(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_muladd(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_muladds(vec3 a, float s, vec3 dest); - CGLM_INLINE void glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_minadd(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_subsub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_addsub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_mulsubs(vec3 a, float s, vec3 dest); - CGLM_INLINE void glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_minsub(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_flipsign(vec3 v); - CGLM_INLINE void glm_vec3_flipsign_to(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_negate_to(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_negate(vec3 v); - CGLM_INLINE void glm_vec3_inv(vec3 v); - CGLM_INLINE void glm_vec3_inv_to(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_normalize(vec3 v); - CGLM_INLINE void glm_vec3_normalize_to(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_cross(vec3 a, vec3 b, vec3 d); - CGLM_INLINE void glm_vec3_crossn(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE float glm_vec3_angle(vec3 a, vec3 b); - CGLM_INLINE void glm_vec3_rotate(vec3 v, float angle, vec3 axis); - CGLM_INLINE void glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_proj(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_center(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE float glm_vec3_distance(vec3 a, vec3 b); - CGLM_INLINE float glm_vec3_distance2(vec3 a, vec3 b); - CGLM_INLINE void glm_vec3_maxv(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_minv(vec3 a, vec3 b, vec3 dest); - CGLM_INLINE void glm_vec3_ortho(vec3 v, vec3 dest); - CGLM_INLINE void glm_vec3_clamp(vec3 v, float minVal, float maxVal); - CGLM_INLINE void glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_step(vec3 edge, vec3 x, vec3 dest); - CGLM_INLINE void glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest); - CGLM_INLINE void glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest); - CGLM_INLINE void glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest); - CGLM_INLINE void glm_vec3_swizzle(vec3 v, int mask, vec3 dest); - CGLM_INLINE void glm_vec3_make(float * restrict src, vec3 dest); - CGLM_INLINE void glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest); - CGLM_INLINE void glm_vec3_reflect(vec3 v, vec3 n, vec3 dest); - CGLM_INLINE void glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest); - - Convenient: - CGLM_INLINE void glm_cross(vec3 a, vec3 b, vec3 d); - CGLM_INLINE float glm_dot(vec3 a, vec3 b); - CGLM_INLINE void glm_normalize(vec3 v); - CGLM_INLINE void glm_normalize_to(vec3 v, vec3 dest); - - DEPRECATED: - glm_vec3_dup - glm_vec3_flipsign - glm_vec3_flipsign_to - glm_vec3_inv - glm_vec3_inv_to - glm_vec3_mulv - glm_vec3_step_uni --> use glm_vec3_steps - */ - -#ifndef cglm_vec3_h -#define cglm_vec3_h - -#include "common.h" -#include "vec4.h" -#include "vec3-ext.h" -#include "util.h" - -/* DEPRECATED! use _copy, _ucopy versions */ -#define glm_vec3_dup(v, dest) glm_vec3_copy(v, dest) -#define glm_vec3_flipsign(v) glm_vec3_negate(v) -#define glm_vec3_flipsign_to(v, dest) glm_vec3_negate_to(v, dest) -#define glm_vec3_inv(v) glm_vec3_negate(v) -#define glm_vec3_inv_to(v, dest) glm_vec3_negate_to(v, dest) -#define glm_vec3_mulv(a, b, d) glm_vec3_mul(a, b, d) -#define glm_vec3_step_uni(edge, x, dest) glm_vec3_steps(edge, x, dest) - -#define GLM_VEC3_ONE_INIT {1.0f, 1.0f, 1.0f} -#define GLM_VEC3_ZERO_INIT {0.0f, 0.0f, 0.0f} - -#define GLM_VEC3_ONE ((vec3)GLM_VEC3_ONE_INIT) -#define GLM_VEC3_ZERO ((vec3)GLM_VEC3_ZERO_INIT) - -#define GLM_YUP ((vec3){0.0f, 1.0f, 0.0f}) -#define GLM_ZUP ((vec3){0.0f, 0.0f, 1.0f}) -#define GLM_XUP ((vec3){1.0f, 0.0f, 0.0f}) -#define GLM_FORWARD ((vec3){0.0f, 0.0f, -1.0f}) - -#define GLM_XXX GLM_SHUFFLE3(0, 0, 0) -#define GLM_YYY GLM_SHUFFLE3(1, 1, 1) -#define GLM_ZZZ GLM_SHUFFLE3(2, 2, 2) -#define GLM_ZYX GLM_SHUFFLE3(0, 1, 2) - -/*! - * @brief init vec3 using vec4 - * - * @param[in] v4 vector4 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3(vec4 v4, vec3 dest) { - dest[0] = v4[0]; - dest[1] = v4[1]; - dest[2] = v4[2]; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] a source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_copy(vec3 a, vec3 dest) { - dest[0] = a[0]; - dest[1] = a[1]; - dest[2] = a[2]; -} - -/*! - * @brief make vector zero - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec3_zero(vec3 v) { - v[0] = v[1] = v[2] = 0.0f; -} - -/*! - * @brief make vector one - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec3_one(vec3 v) { - v[0] = v[1] = v[2] = 1.0f; -} - -/*! - * @brief vec3 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glm_vec3_dot(vec3 a, vec3 b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vector - * - * @return norm * norm - */ -CGLM_INLINE -float -glm_vec3_norm2(vec3 v) { - return glm_vec3_dot(v, v); -} - -/*! - * @brief euclidean norm (magnitude), also called L2 norm - * this will give magnitude of vector in euclidean space - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -float -glm_vec3_norm(vec3 v) { - return sqrtf(glm_vec3_norm2(v)); -} - -/*! - * @brief L1 norm of vec3 - * Also known as Manhattan Distance or Taxicab norm. - * L1 Norm is the sum of the magnitudes of the vectors in a space. - * It is calculated as the sum of the absolute values of the vector components. - * In this norm, all the components of the vector are weighted equally. - * - * This computes: - * R = |v[0]| + |v[1]| + |v[2]| - * - * @param[in] v vector - * - * @return L1 norm - */ -CGLM_INLINE -float -glm_vec3_norm_one(vec3 v) { - vec3 t; - glm_vec3_abs(v, t); - return glm_vec3_hadd(t); -} - -/*! - * @brief infinity norm of vec3 - * Also known as Maximum norm. - * Infinity Norm is the largest magnitude among each element of a vector. - * It is calculated as the maximum of the absolute values of the vector components. - * - * This computes: - * inf norm = max(|v[0]|, |v[1]|, |v[2]|) - * - * @param[in] v vector - * - * @return infinity norm - */ -CGLM_INLINE -float -glm_vec3_norm_inf(vec3 v) { - vec3 t; - glm_vec3_abs(v, t); - return glm_vec3_max(t); -} - -/*! - * @brief add a vector to b vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_add(vec3 a, vec3 b, vec3 dest) { - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; - dest[2] = a[2] + b[2]; -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_adds(vec3 v, float s, vec3 dest) { - dest[0] = v[0] + s; - dest[1] = v[1] + s; - dest[2] = v[2] + s; -} - -/*! - * @brief subtract b vector from a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_sub(vec3 a, vec3 b, vec3 dest) { - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; - dest[2] = a[2] - b[2]; -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_subs(vec3 v, float s, vec3 dest) { - dest[0] = v[0] - s; - dest[1] = v[1] - s; - dest[2] = v[2] - s; -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a vector1 - * @param b vector2 - * @param dest v3 = (a[0] * b[0], a[1] * b[1], a[2] * b[2]) - */ -CGLM_INLINE -void -glm_vec3_mul(vec3 a, vec3 b, vec3 dest) { - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; - dest[2] = a[2] * b[2]; -} - -/*! - * @brief multiply/scale vec3 vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_scale(vec3 v, float s, vec3 dest) { - dest[0] = v[0] * s; - dest[1] = v[1] * s; - dest[2] = v[2] * s; -} - -/*! - * @brief make vec3 vector scale as specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_scale_as(vec3 v, float s, vec3 dest) { - float norm; - norm = glm_vec3_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec3_zero(dest); - return; - } - - glm_vec3_scale(v, s / norm, dest); -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2]) - */ -CGLM_INLINE -void -glm_vec3_div(vec3 a, vec3 b, vec3 dest) { - dest[0] = a[0] / b[0]; - dest[1] = a[1] / b[1]; - dest[2] = a[2] / b[2]; -} - -/*! - * @brief div vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest result = (a[0]/s, a[1]/s, a[2]/s) - */ -CGLM_INLINE -void -glm_vec3_divs(vec3 v, float s, vec3 dest) { - dest[0] = v[0] / s; - dest[1] = v[1] / s; - dest[2] = v[2] / s; -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_vec3_addadd(vec3 a, vec3 b, vec3 dest) { - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; - dest[2] += a[2] + b[2]; -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_vec3_subadd(vec3 a, vec3 b, vec3 dest) { - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; - dest[2] += a[2] - b[2]; -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec3_muladd(vec3 a, vec3 b, vec3 dest) { - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; - dest[2] += a[2] * b[2]; -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec3_muladds(vec3 a, float s, vec3 dest) { - dest[0] += a[0] * s; - dest[1] += a[1] * s; - dest[2] += a[2] * s; -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_vec3_maxadd(vec3 a, vec3 b, vec3 dest) { - dest[0] += glm_max(a[0], b[0]); - dest[1] += glm_max(a[1], b[1]); - dest[2] += glm_max(a[2], b[2]); -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_vec3_minadd(vec3 a, vec3 b, vec3 dest) { - dest[0] += glm_min(a[0], b[0]); - dest[1] += glm_min(a[1], b[1]); - dest[2] += glm_min(a[2], b[2]); -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_vec3_subsub(vec3 a, vec3 b, vec3 dest) { - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; - dest[2] -= a[2] - b[2]; -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_vec3_addsub(vec3 a, vec3 b, vec3 dest) { - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; - dest[2] -= a[2] + b[2]; -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec3_mulsub(vec3 a, vec3 b, vec3 dest) { - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; - dest[2] -= a[2] * b[2]; -} - -/*! - * @brief mul vector with scalar and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec3_mulsubs(vec3 a, float s, vec3 dest) { - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; - dest[2] -= a[2] * s; -} - -/*! - * @brief sub max of two vectors to result/dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_vec3_maxsub(vec3 a, vec3 b, vec3 dest) { - dest[0] -= glm_max(a[0], b[0]); - dest[1] -= glm_max(a[1], b[1]); - dest[2] -= glm_max(a[2], b[2]); -} - -/*! - * @brief sub min of two vectors to result/dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_vec3_minsub(vec3 a, vec3 b, vec3 dest) { - dest[0] -= glm_min(a[0], b[0]); - dest[1] -= glm_min(a[1], b[1]); - dest[2] -= glm_min(a[2], b[2]); -} - -/*! - * @brief negate vector components and store result in dest - * - * @param[in] v vector - * @param[out] dest result vector - */ -CGLM_INLINE -void -glm_vec3_negate_to(vec3 v, vec3 dest) { - dest[0] = -v[0]; - dest[1] = -v[1]; - dest[2] = -v[2]; -} - -/*! - * @brief negate vector components - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec3_negate(vec3 v) { - glm_vec3_negate_to(v, v); -} - -/*! - * @brief normalize vec3 and store result in same vec - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec3_normalize(vec3 v) { - float norm; - - norm = glm_vec3_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - v[0] = v[1] = v[2] = 0.0f; - return; - } - - glm_vec3_scale(v, 1.0f / norm, v); -} - -/*! - * @brief normalize vec3 to dest - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_normalize_to(vec3 v, vec3 dest) { - float norm; - - norm = glm_vec3_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec3_zero(dest); - return; - } - - glm_vec3_scale(v, 1.0f / norm, dest); -} - -/*! - * @brief cross product of two vector (RH) - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_cross(vec3 a, vec3 b, vec3 dest) { - vec3 c; - /* (u2.v3 - u3.v2, u3.v1 - u1.v3, u1.v2 - u2.v1) */ - c[0] = a[1] * b[2] - a[2] * b[1]; - c[1] = a[2] * b[0] - a[0] * b[2]; - c[2] = a[0] * b[1] - a[1] * b[0]; - glm_vec3_copy(c, dest); -} - -/*! - * @brief cross product of two vector (RH) and normalize the result - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_crossn(vec3 a, vec3 b, vec3 dest) { - glm_vec3_cross(a, b, dest); - glm_vec3_normalize(dest); -} - -/*! - * @brief angle between two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return angle as radians - */ -CGLM_INLINE -float -glm_vec3_angle(vec3 a, vec3 b) { - float norm, dot; - - /* maybe compiler generate approximation instruction (rcp) */ - norm = 1.0f / (glm_vec3_norm(a) * glm_vec3_norm(b)); - dot = glm_vec3_dot(a, b) * norm; - - if (dot > 1.0f) - return 0.0f; - else if (dot < -1.0f) - return CGLM_PI; - - return acosf(dot); -} - -/*! - * @brief rotate vec3 around axis by angle using Rodrigues' rotation formula - * - * @param[in, out] v vector - * @param[in] axis axis vector (must be unit vector) - * @param[in] angle angle by radians - */ -CGLM_INLINE -void -glm_vec3_rotate(vec3 v, float angle, vec3 axis) { - vec3 v1, v2, k; - float c, s; - - c = cosf(angle); - s = sinf(angle); - - glm_vec3_normalize_to(axis, k); - - /* Right Hand, Rodrigues' rotation formula: - v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) - */ - glm_vec3_scale(v, c, v1); - - glm_vec3_cross(k, v, v2); - glm_vec3_scale(v2, s, v2); - - glm_vec3_add(v1, v2, v1); - - glm_vec3_scale(k, glm_vec3_dot(k, v) * (1.0f - c), v2); - glm_vec3_add(v1, v2, v); -} - -/*! - * @brief apply rotation matrix to vector - * - * matrix format should be (no perspective): - * a b c x - * e f g y - * i j k z - * 0 0 0 w - * - * @param[in] m affine matrix or rot matrix - * @param[in] v vector - * @param[out] dest rotated vector - */ -CGLM_INLINE -void -glm_vec3_rotate_m4(mat4 m, vec3 v, vec3 dest) { - vec4 x, y, z, res; - - glm_vec4_normalize_to(m[0], x); - glm_vec4_normalize_to(m[1], y); - glm_vec4_normalize_to(m[2], z); - - glm_vec4_scale(x, v[0], res); - glm_vec4_muladds(y, v[1], res); - glm_vec4_muladds(z, v[2], res); - - glm_vec3(res, dest); -} - -/*! - * @brief apply rotation matrix to vector - * - * @param[in] m affine matrix or rot matrix - * @param[in] v vector - * @param[out] dest rotated vector - */ -CGLM_INLINE -void -glm_vec3_rotate_m3(mat3 m, vec3 v, vec3 dest) { - vec4 res, x, y, z; - - glm_vec4(m[0], 0.0f, x); - glm_vec4(m[1], 0.0f, y); - glm_vec4(m[2], 0.0f, z); - - glm_vec4_normalize(x); - glm_vec4_normalize(y); - glm_vec4_normalize(z); - - glm_vec4_scale(x, v[0], res); - glm_vec4_muladds(y, v[1], res); - glm_vec4_muladds(z, v[2], res); - - glm_vec3(res, dest); -} - -/*! - * @brief project a vector onto b vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest projected vector - */ -CGLM_INLINE -void -glm_vec3_proj(vec3 a, vec3 b, vec3 dest) { - glm_vec3_scale(b, - glm_vec3_dot(a, b) / glm_vec3_norm2(b), - dest); -} - -/** - * @brief find center point of two vector - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest center point - */ -CGLM_INLINE -void -glm_vec3_center(vec3 a, vec3 b, vec3 dest) { - glm_vec3_add(a, b, dest); - glm_vec3_scale(dest, 0.5f, dest); -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns squared distance (distance * distance) - */ -CGLM_INLINE -float -glm_vec3_distance2(vec3 a, vec3 b) { - return glm_pow2(a[0] - b[0]) - + glm_pow2(a[1] - b[1]) - + glm_pow2(a[2] - b[2]); -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns distance - */ -CGLM_INLINE -float -glm_vec3_distance(vec3 a, vec3 b) { - return sqrtf(glm_vec3_distance2(a, b)); -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_maxv(vec3 a, vec3 b, vec3 dest) { - dest[0] = glm_max(a[0], b[0]); - dest[1] = glm_max(a[1], b[1]); - dest[2] = glm_max(a[2], b[2]); -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_minv(vec3 a, vec3 b, vec3 dest) { - dest[0] = glm_min(a[0], b[0]); - dest[1] = glm_min(a[1], b[1]); - dest[2] = glm_min(a[2], b[2]); -} - -/*! - * @brief possible orthogonal/perpendicular vector - * - * @param[in] v vector - * @param[out] dest orthogonal/perpendicular vector - */ -CGLM_INLINE -void -glm_vec3_ortho(vec3 v, vec3 dest) { - float ignore; - float f = modff(fabsf(v[0]) + 0.5f, &ignore); - vec3 result = {-v[1], v[0] - f * v[2], f * v[1]}; - glm_vec3_copy(result, dest); -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in, out] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -void -glm_vec3_clamp(vec3 v, float minVal, float maxVal) { - v[0] = glm_clamp(v[0], minVal, maxVal); - v[1] = glm_clamp(v[1], minVal, maxVal); - v[2] = glm_clamp(v[2], minVal, maxVal); -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_lerp(vec3 from, vec3 to, float t, vec3 dest) { - vec3 s, v; - - /* from + s * (to - from) */ - glm_vec3_broadcast(t, s); - glm_vec3_sub(to, from, v); - glm_vec3_mul(s, v, v); - glm_vec3_add(from, v, dest); -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_lerpc(vec3 from, vec3 to, float t, vec3 dest) { - glm_vec3_lerp(from, to, glm_clamp_zo(t), dest); -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_mix(vec3 from, vec3 to, float t, vec3 dest) { - glm_vec3_lerp(from, to, t, dest); -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_mixc(vec3 from, vec3 to, float t, vec3 dest) { - glm_vec3_lerpc(from, to, t, dest); -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_step(vec3 edge, vec3 x, vec3 dest) { - dest[0] = glm_step(edge[0], x[0]); - dest[1] = glm_step(edge[1], x[1]); - dest[2] = glm_step(edge[2], x[2]); -} - -/*! - * @brief threshold function with a smooth transition (unidimensional) - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_smoothstep_uni(float edge0, float edge1, vec3 x, vec3 dest) { - dest[0] = glm_smoothstep(edge0, edge1, x[0]); - dest[1] = glm_smoothstep(edge0, edge1, x[1]); - dest[2] = glm_smoothstep(edge0, edge1, x[2]); -} - -/*! - * @brief threshold function with a smooth transition - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_smoothstep(vec3 edge0, vec3 edge1, vec3 x, vec3 dest) { - dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); - dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); - dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); -} - -/*! - * @brief smooth Hermite interpolation between two vectors - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_smoothinterp(vec3 from, vec3 to, float t, vec3 dest) { - vec3 s, v; - - /* from + s * (to - from) */ - glm_vec3_broadcast(glm_smooth(t), s); - glm_vec3_sub(to, from, v); - glm_vec3_mul(s, v, v); - glm_vec3_add(from, v, dest); -} - -/*! - * @brief smooth Hermite interpolation between two vectors (clamped) - * - * formula: from + s * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_smoothinterpc(vec3 from, vec3 to, float t, vec3 dest) { - glm_vec3_smoothinterp(from, to, glm_clamp_zo(t), dest); -} - -/*! - * @brief swizzle vector components - * - * you can use existing masks e.g. GLM_XXX, GLM_ZYX - * - * @param[in] v source - * @param[in] mask mask - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec3_swizzle(vec3 v, int mask, vec3 dest) { - vec3 t; - - t[0] = v[(mask & (3 << 0))]; - t[1] = v[(mask & (3 << 2)) >> 2]; - t[2] = v[(mask & (3 << 4)) >> 4]; - - glm_vec3_copy(t, dest); -} - -/*! - * @brief vec3 cross product - * - * this is just convenient wrapper - * - * @param[in] a source 1 - * @param[in] b source 2 - * @param[out] d destination - */ -CGLM_INLINE -void -glm_cross(vec3 a, vec3 b, vec3 d) { - glm_vec3_cross(a, b, d); -} - -/*! - * @brief vec3 dot product - * - * this is just convenient wrapper - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glm_dot(vec3 a, vec3 b) { - return glm_vec3_dot(a, b); -} - -/*! - * @brief normalize vec3 and store result in same vec - * - * this is just convenient wrapper - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_normalize(vec3 v) { - glm_vec3_normalize(v); -} - -/*! - * @brief normalize vec3 to dest - * - * this is just convenient wrapper - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_normalize_to(vec3 v, vec3 dest) { - glm_vec3_normalize_to(v, dest); -} - -/*! - * @brief Create three dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec3_make(const float * __restrict src, vec3 dest) { - dest[0] = src[0]; - dest[1] = src[1]; - dest[2] = src[2]; -} - -/*! - * @brief a vector pointing in the same direction as another - * - * orients a vector to point away from a surface as defined by its normal - * - * @param[in] n vector to orient - * @param[in] v incident vector - * @param[in] nref reference vector - * @param[out] dest oriented vector, pointing away from the surface - */ -CGLM_INLINE -void -glm_vec3_faceforward(vec3 n, vec3 v, vec3 nref, vec3 dest) { - if (glm_vec3_dot(v, nref) < 0.0f) { - /* N is facing away from I */ - glm_vec3_copy(n, dest); - } else { - /* N is facing towards I, negate it */ - glm_vec3_negate_to(n, dest); - } -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] v incident vector - * @param[in] n normalized normal vector - * @param[out] dest reflection result - */ -CGLM_INLINE -void -glm_vec3_reflect(vec3 v, vec3 n, vec3 dest) { - vec3 temp; - glm_vec3_scale(n, 2.0f * glm_vec3_dot(v, n), temp); - glm_vec3_sub(v, temp, dest); -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glm_vec3_refract(vec3 v, vec3 n, float eta, vec3 dest) { - float ndi, eni, k; - - ndi = glm_vec3_dot(n, v); - eni = eta * ndi; - k = 1.0f - eta * eta + eni * eni; - - if (k < 0.0f) { - glm_vec3_zero(dest); - return false; - } - - glm_vec3_scale(v, eta, dest); - glm_vec3_mulsubs(n, eni + sqrtf(k), dest); - return true; -} - -#endif /* cglm_vec3_h */ diff --git a/external/cglm/vec4-ext.h b/external/cglm/vec4-ext.h deleted file mode 100644 index 193a5e9..0000000 --- a/external/cglm/vec4-ext.h +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/*! - * @brief SIMD like functions - */ - -/* - Functions: - CGLM_INLINE void glm_vec4_broadcast(float val, vec4 d); - CGLM_INLINE void glm_vec4_fill(vec4 v, float val); - CGLM_INLINE bool glm_vec4_eq(vec4 v, float val); - CGLM_INLINE bool glm_vec4_eq_eps(vec4 v, float val); - CGLM_INLINE bool glm_vec4_eq_all(vec4 v); - CGLM_INLINE bool glm_vec4_eqv(vec4 a, vec4 b); - CGLM_INLINE bool glm_vec4_eqv_eps(vec4 a, vec4 b); - CGLM_INLINE float glm_vec4_max(vec4 v); - CGLM_INLINE float glm_vec4_min(vec4 v); - CGLM_INLINE bool glm_vec4_isnan(vec4 v); - CGLM_INLINE bool glm_vec4_isinf(vec4 v); - CGLM_INLINE bool glm_vec4_isvalid(vec4 v); - CGLM_INLINE void glm_vec4_sign(vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_abs(vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_fract(vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_floor(vec4 v, vec4 dest); - CGLM_INLINE float glm_vec4_mods(vec4 v, float s, vec4 dest); - CGLM_INLINE float glm_vec4_steps(float edge, vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_stepr(vec4 edge, float v, vec4 dest); - CGLM_INLINE float glm_vec4_hadd(vec4 v); - CGLM_INLINE void glm_vec4_sqrt(vec4 v, vec4 dest); - */ - -#ifndef cglm_vec4_ext_h -#define cglm_vec4_ext_h - -#include "common.h" -#include "vec3-ext.h" - -/*! - * @brief fill a vector with specified value - * - * @param val value - * @param d dest - */ -CGLM_INLINE -void -glm_vec4_broadcast(float val, vec4 d) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(d, wasm_f32x4_splat(val)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(d, glmm_set1(val)); -#else - d[0] = d[1] = d[2] = d[3] = val; -#endif -} - -/*! - * @brief fill a vector with specified value - * - * @param v dest - * @param val value - */ -CGLM_INLINE -void -glm_vec4_fill(vec4 v, float val) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(v, wasm_f32x4_splat(val)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(v, glmm_set1(val)); -#else - v[0] = v[1] = v[2] = v[3] = val; -#endif -} - -/*! - * @brief check if vector is equal to value (without epsilon) - * - * @param v vector - * @param val value - */ -CGLM_INLINE -bool -glm_vec4_eq(vec4 v, float val) { - return v[0] == val - && v[0] == v[1] - && v[0] == v[2] - && v[0] == v[3]; -} - -/*! - * @brief check if vector is equal to value (with epsilon) - * - * @param v vector - * @param val value - */ -CGLM_INLINE -bool -glm_vec4_eq_eps(vec4 v, float val) { - return fabsf(v[0] - val) <= GLM_FLT_EPSILON - && fabsf(v[1] - val) <= GLM_FLT_EPSILON - && fabsf(v[2] - val) <= GLM_FLT_EPSILON - && fabsf(v[3] - val) <= GLM_FLT_EPSILON; -} - -/*! - * @brief check if vector members are equal (without epsilon) - * - * @param v vector - */ -CGLM_INLINE -bool -glm_vec4_eq_all(vec4 v) { - return glm_vec4_eq_eps(v, v[0]); -} - -/*! - * @brief check if vector is equal to another (without epsilon) - * - * @param a vector - * @param b vector - */ -CGLM_INLINE -bool -glm_vec4_eqv(vec4 a, vec4 b) { - return a[0] == b[0] - && a[1] == b[1] - && a[2] == b[2] - && a[3] == b[3]; -} - -/*! - * @brief check if vector is equal to another (with epsilon) - * - * @param a vector - * @param b vector - */ -CGLM_INLINE -bool -glm_vec4_eqv_eps(vec4 a, vec4 b) { - return fabsf(a[0] - b[0]) <= GLM_FLT_EPSILON - && fabsf(a[1] - b[1]) <= GLM_FLT_EPSILON - && fabsf(a[2] - b[2]) <= GLM_FLT_EPSILON - && fabsf(a[3] - b[3]) <= GLM_FLT_EPSILON; -} - -/*! - * @brief max value of vector - * - * @param v vector - */ -CGLM_INLINE -float -glm_vec4_max(vec4 v) { - float max; - - max = glm_vec3_max(v); - if (v[3] > max) - max = v[3]; - - return max; -} - -/*! - * @brief min value of vector - * - * @param v vector - */ -CGLM_INLINE -float -glm_vec4_min(vec4 v) { - float min; - - min = glm_vec3_min(v); - if (v[3] < min) - min = v[3]; - - return min; -} - -/*! - * @brief check if one of items is NaN (not a number) - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec4_isnan(vec4 v) { -#ifndef CGLM_FAST_MATH - return isnan(v[0]) || isnan(v[1]) || isnan(v[2]) || isnan(v[3]); -#else - return false; -#endif -} - -/*! - * @brief check if one of items is INFINITY - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec4_isinf(vec4 v) { -#ifndef CGLM_FAST_MATH - return isinf(v[0]) || isinf(v[1]) || isinf(v[2]) || isinf(v[3]); -#else - return false; -#endif -} - -/*! - * @brief check if all items are valid number - * you should only use this in DEBUG mode or very critical asserts - * - * @param[in] v vector - */ -CGLM_INLINE -bool -glm_vec4_isvalid(vec4 v) { - return !glm_vec4_isnan(v) && !glm_vec4_isinf(v); -} - -/*! - * @brief get sign of 32 bit float as +1, -1, 0 - * - * Important: It returns 0 for zero/NaN input - * - * @param v vector - */ -CGLM_INLINE -void -glm_vec4_sign(vec4 v, vec4 dest) { -#if defined( __SSE__ ) || defined( __SSE2__ ) - __m128 x0, x1, x2, x3, x4; - - x0 = glmm_load(v); - x1 = _mm_set_ps(0.0f, 0.0f, 1.0f, -1.0f); - x2 = glmm_splat(x1, 2); - - x3 = _mm_and_ps(_mm_cmpgt_ps(x0, x2), glmm_splat(x1, 1)); - x4 = _mm_and_ps(_mm_cmplt_ps(x0, x2), glmm_splat(x1, 0)); - - glmm_store(dest, _mm_or_ps(x3, x4)); -#else - dest[0] = glm_signf(v[0]); - dest[1] = glm_signf(v[1]); - dest[2] = glm_signf(v[2]); - dest[3] = glm_signf(v[3]); -#endif -} - -/*! - * @brief absolute value of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_abs(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, glmm_abs(glmm_load(v))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, glmm_abs(glmm_load(v))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vabsq_f32(vld1q_f32(v))); -#else - dest[0] = fabsf(v[0]); - dest[1] = fabsf(v[1]); - dest[2] = fabsf(v[2]); - dest[3] = fabsf(v[3]); -#endif -} - -/*! - * @brief fractional part of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_fract(vec4 v, vec4 dest) { - dest[0] = fminf(v[0] - floorf(v[0]), 0.999999940395355224609375f); - dest[1] = fminf(v[1] - floorf(v[1]), 0.999999940395355224609375f); - dest[2] = fminf(v[2] - floorf(v[2]), 0.999999940395355224609375f); - dest[3] = fminf(v[3] - floorf(v[3]), 0.999999940395355224609375f); -} - -/*! - * @brief floor of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_floor(vec4 v, vec4 dest) { - dest[0] = floorf(v[0]); - dest[1] = floorf(v[1]); - dest[2] = floorf(v[2]); - dest[3] = floorf(v[3]); -} - -/*! - * @brief mod of each vector item, result is written to dest (dest = v % s) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_mods(vec4 v, float s, vec4 dest) { - dest[0] = fmodf(v[0], s); - dest[1] = fmodf(v[1], s); - dest[2] = fmodf(v[2], s); - dest[3] = fmodf(v[3], s); -} - -/*! - * @brief threshold each vector item with scalar - * condition is: (x[i] < edge) ? 0.0 : 1.0 - * - * @param[in] edge threshold - * @param[in] x vector to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_steps(float edge, vec4 x, vec4 dest) { - dest[0] = glm_step(edge, x[0]); - dest[1] = glm_step(edge, x[1]); - dest[2] = glm_step(edge, x[2]); - dest[3] = glm_step(edge, x[3]); -} - -/*! - * @brief threshold a value with *vector* as the threshold - * condition is: (x < edge[i]) ? 0.0 : 1.0 - * - * @param[in] edge threshold vector - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_stepr(vec4 edge, float x, vec4 dest) { - dest[0] = glm_step(edge[0], x); - dest[1] = glm_step(edge[1], x); - dest[2] = glm_step(edge[2], x); - dest[3] = glm_step(edge[3], x); -} - -/*! - * @brief vector reduction by summation - * @warning could overflow - * - * @param[in] v vector - * @return sum of all vector's elements - */ -CGLM_INLINE -float -glm_vec4_hadd(vec4 v) { -#if defined(__wasm__) && defined(__wasm_simd128__) - return glmm_hadd(glmm_load(v)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - return glmm_hadd(glmm_load(v)); -#else - return v[0] + v[1] + v[2] + v[3]; -#endif -} - -/*! - * @brief square root of each vector item - * - * @param[in] v vector - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_sqrt(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sqrt(glmm_load(v))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sqrt_ps(glmm_load(v))); -#else - dest[0] = sqrtf(v[0]); - dest[1] = sqrtf(v[1]); - dest[2] = sqrtf(v[2]); - dest[3] = sqrtf(v[3]); -#endif -} - -#endif /* cglm_vec4_ext_h */ diff --git a/external/cglm/vec4.h b/external/cglm/vec4.h deleted file mode 100644 index ded09c9..0000000 --- a/external/cglm/vec4.h +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -/* - Macros: - GLM_VEC4_ONE_INIT - GLM_VEC4_BLACK_INIT - GLM_VEC4_ZERO_INIT - GLM_VEC4_ONE - GLM_VEC4_BLACK - GLM_VEC4_ZERO - - Functions: - CGLM_INLINE void glm_vec4(vec3 v3, float last, vec4 dest); - CGLM_INLINE void glm_vec4_copy3(vec4 a, vec3 dest); - CGLM_INLINE void glm_vec4_copy(vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_ucopy(vec4 v, vec4 dest); - CGLM_INLINE float glm_vec4_dot(vec4 a, vec4 b); - CGLM_INLINE float glm_vec4_norm2(vec4 v); - CGLM_INLINE float glm_vec4_norm(vec4 v); - CGLM_INLINE float glm_vec4_norm_one(vec4 v); - CGLM_INLINE float glm_vec4_norm_inf(vec4 v); - CGLM_INLINE void glm_vec4_add(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_adds(vec4 v, float s, vec4 dest); - CGLM_INLINE void glm_vec4_sub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_subs(vec4 v, float s, vec4 dest); - CGLM_INLINE void glm_vec4_mul(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_scale(vec4 v, float s, vec4 dest); - CGLM_INLINE void glm_vec4_scale_as(vec4 v, float s, vec4 dest); - CGLM_INLINE void glm_vec4_div(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_divs(vec4 v, float s, vec4 dest); - CGLM_INLINE void glm_vec4_addadd(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_subadd(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_muladd(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_muladds(vec4 a, float s, vec4 dest); - CGLM_INLINE void glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_minadd(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_subsub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_addsub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_mulsubs(vec4 a, float s, vec4 dest); - CGLM_INLINE void glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_minsub(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_negate(vec4 v); - CGLM_INLINE void glm_vec4_inv(vec4 v); - CGLM_INLINE void glm_vec4_inv_to(vec4 v, vec4 dest); - CGLM_INLINE void glm_vec4_normalize(vec4 v); - CGLM_INLINE void glm_vec4_normalize_to(vec4 vec, vec4 dest); - CGLM_INLINE float glm_vec4_distance(vec4 a, vec4 b); - CGLM_INLINE float glm_vec4_distance2(vec4 a, vec4 b); - CGLM_INLINE void glm_vec4_maxv(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_minv(vec4 a, vec4 b, vec4 dest); - CGLM_INLINE void glm_vec4_clamp(vec4 v, float minVal, float maxVal); - CGLM_INLINE void glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest); - CGLM_INLINE void glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest); - CGLM_INLINE void glm_vec4_step(vec4 edge, vec4 x, vec4 dest); - CGLM_INLINE void glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest); - CGLM_INLINE void glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest); - CGLM_INLINE void glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest); - CGLM_INLINE void glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest); - CGLM_INLINE void glm_vec4_swizzle(vec4 v, int mask, vec4 dest); - CGLM_INLINE void glm_vec4_make(float * restrict src, vec4 dest); - CGLM_INLINE void glm_vec4_reflect(vec4 v, vec4 n, vec4 dest); - CGLM_INLINE void glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest); - - DEPRECATED: - glm_vec4_dup - glm_vec4_flipsign - glm_vec4_flipsign_to - glm_vec4_inv - glm_vec4_inv_to - glm_vec4_mulv - glm_vec4_step_uni --> use glm_vec4_steps - */ - -#ifndef cglm_vec4_h -#define cglm_vec4_h - -#include "common.h" -#include "vec4-ext.h" -#include "util.h" - -/* DEPRECATED! functions */ -#define glm_vec4_dup3(v, dest) glm_vec4_copy3(v, dest) -#define glm_vec4_dup(v, dest) glm_vec4_copy(v, dest) -#define glm_vec4_flipsign(v) glm_vec4_negate(v) -#define glm_vec4_flipsign_to(v, dest) glm_vec4_negate_to(v, dest) -#define glm_vec4_inv(v) glm_vec4_negate(v) -#define glm_vec4_inv_to(v, dest) glm_vec4_negate_to(v, dest) -#define glm_vec4_mulv(a, b, d) glm_vec4_mul(a, b, d) -#define glm_vec4_step_uni(edge, x, dest) glm_vec4_steps(edge, x, dest) - -#define GLM_VEC4_ONE_INIT {1.0f, 1.0f, 1.0f, 1.0f} -#define GLM_VEC4_BLACK_INIT {0.0f, 0.0f, 0.0f, 1.0f} -#define GLM_VEC4_ZERO_INIT {0.0f, 0.0f, 0.0f, 0.0f} - -#define GLM_VEC4_ONE ((vec4)GLM_VEC4_ONE_INIT) -#define GLM_VEC4_BLACK ((vec4)GLM_VEC4_BLACK_INIT) -#define GLM_VEC4_ZERO ((vec4)GLM_VEC4_ZERO_INIT) - -#define GLM_XXXX GLM_SHUFFLE4(0, 0, 0, 0) -#define GLM_YYYY GLM_SHUFFLE4(1, 1, 1, 1) -#define GLM_ZZZZ GLM_SHUFFLE4(2, 2, 2, 2) -#define GLM_WWWW GLM_SHUFFLE4(3, 3, 3, 3) -#define GLM_WZYX GLM_SHUFFLE4(0, 1, 2, 3) - -/*! - * @brief init vec4 using vec3 - * - * @param[in] v3 vector3 - * @param[in] last last item - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4(vec3 v3, float last, vec4 dest) { - dest[0] = v3[0]; - dest[1] = v3[1]; - dest[2] = v3[2]; - dest[3] = last; -} - -/*! - * @brief copy first 3 members of [a] to [dest] - * - * @param[in] a source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_copy3(vec4 a, vec3 dest) { - dest[0] = a[0]; - dest[1] = a[1]; - dest[2] = a[2]; -} - -/*! - * @brief copy all members of [a] to [dest] - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_copy(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, glmm_load(v)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, glmm_load(v)); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vld1q_f32(v)); -#else - dest[0] = v[0]; - dest[1] = v[1]; - dest[2] = v[2]; - dest[3] = v[3]; -#endif -} - -/*! - * @brief copy all members of [a] to [dest] - * - * alignment is not required - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_ucopy(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - /* note here wasm v128.load/v128.store support unaligned loads and stores */ - wasm_v128_store(dest, wasm_v128_load(v)); -#else - dest[0] = v[0]; - dest[1] = v[1]; - dest[2] = v[2]; - dest[3] = v[3]; -#endif -} - -/*! - * @brief make vector zero - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec4_zero(vec4 v) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(v, wasm_f32x4_const_splat(0.f)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(v, _mm_setzero_ps()); -#elif defined(CGLM_NEON_FP) - vst1q_f32(v, vdupq_n_f32(0.0f)); -#else - v[0] = 0.0f; - v[1] = 0.0f; - v[2] = 0.0f; - v[3] = 0.0f; -#endif -} - -/*! - * @brief make vector one - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec4_one(vec4 v) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(v, wasm_f32x4_const_splat(1.0f)); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(v, glmm_set1_rval(1.0f)); -#elif defined(CGLM_NEON_FP) - vst1q_f32(v, vdupq_n_f32(1.0f)); -#else - v[0] = 1.0f; - v[1] = 1.0f; - v[2] = 1.0f; - v[3] = 1.0f; -#endif -} - -/*! - * @brief vec4 dot product - * - * @param[in] a vector1 - * @param[in] b vector2 - * - * @return dot product - */ -CGLM_INLINE -float -glm_vec4_dot(vec4 a, vec4 b) { -#if defined(CGLM_SIMD) - return glmm_dot(glmm_load(a), glmm_load(b)); -#else - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; -#endif -} - -/*! - * @brief norm * norm (magnitude) of vec - * - * we can use this func instead of calling norm * norm, because it would call - * sqrtf function twice but with this func we can avoid func call, maybe this is - * not good name for this func - * - * @param[in] v vec4 - * - * @return norm * norm - */ -CGLM_INLINE -float -glm_vec4_norm2(vec4 v) { - return glm_vec4_dot(v, v); -} - -/*! - * @brief euclidean norm (magnitude), also called L2 norm - * this will give magnitude of vector in euclidean space - * - * @param[in] v vector - * - * @return norm - */ -CGLM_INLINE -float -glm_vec4_norm(vec4 v) { -#if defined(CGLM_SIMD) - return glmm_norm(glmm_load(v)); -#else - return sqrtf(glm_vec4_dot(v, v)); -#endif -} - -/*! - * @brief L1 norm of vec4 - * Also known as Manhattan Distance or Taxicab norm. - * L1 Norm is the sum of the magnitudes of the vectors in a space. - * It is calculated as the sum of the absolute values of the vector components. - * In this norm, all the components of the vector are weighted equally. - * - * This computes: - * L1 norm = |v[0]| + |v[1]| + |v[2]| + |v[3]| - * - * @param[in] v vector - * - * @return L1 norm - */ -CGLM_INLINE -float -glm_vec4_norm_one(vec4 v) { -#if defined(CGLM_SIMD) - return glmm_norm_one(glmm_load(v)); -#else - vec4 t; - glm_vec4_abs(v, t); - return glm_vec4_hadd(t); -#endif -} - -/*! - * @brief infinity norm of vec4 - * Also known as Maximum norm. - * Infinity Norm is the largest magnitude among each element of a vector. - * It is calculated as the maximum of the absolute values of the vector components. - * - * This computes: - * inf norm = max(|v[0]|, |v[1]|, |v[2]|, |v[3]|) - * - * @param[in] v vector - * - * @return infinity norm - */ -CGLM_INLINE -float -glm_vec4_norm_inf(vec4 v) { -#if defined(CGLM_SIMD) - return glmm_norm_inf(glmm_load(v)); -#else - vec4 t; - glm_vec4_abs(v, t); - return glm_vec4_max(t); -#endif -} - -/*! - * @brief add b vector to a vector store result in dest - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_add(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add(glmm_load(a), glmm_load(b))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(a), glmm_load(b))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vaddq_f32(vld1q_f32(a), vld1q_f32(b))); -#else - dest[0] = a[0] + b[0]; - dest[1] = a[1] + b[1]; - dest[2] = a[2] + b[2]; - dest[3] = a[3] + b[3]; -#endif -} - -/*! - * @brief add scalar to v vector store result in dest (d = v + vec(s)) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_adds(vec4 v, float s, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add(glmm_load(v), wasm_f32x4_splat(s))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(v), glmm_set1(s))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vaddq_f32(vld1q_f32(v), vdupq_n_f32(s))); -#else - dest[0] = v[0] + s; - dest[1] = v[1] + s; - dest[2] = v[2] + s; - dest[3] = v[3] + s; -#endif -} - -/*! - * @brief subtract b vector from a vector store result in dest (d = a - b) - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_sub(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub(glmm_load(a), glmm_load(b))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(a), glmm_load(b))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vsubq_f32(vld1q_f32(a), vld1q_f32(b))); -#else - dest[0] = a[0] - b[0]; - dest[1] = a[1] - b[1]; - dest[2] = a[2] - b[2]; - dest[3] = a[3] - b[3]; -#endif -} - -/*! - * @brief subtract scalar from v vector store result in dest (d = v - vec(s)) - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_subs(vec4 v, float s, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub(glmm_load(v), wasm_f32x4_splat(s))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(v), glmm_set1(s))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vsubq_f32(vld1q_f32(v), vdupq_n_f32(s))); -#else - dest[0] = v[0] - s; - dest[1] = v[1] - s; - dest[2] = v[2] - s; - dest[3] = v[3] - s; -#endif -} - -/*! - * @brief multiply two vectors (component-wise multiplication) - * - * @param a vector1 - * @param b vector2 - * @param dest dest = (a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]) - */ -CGLM_INLINE -void -glm_vec4_mul(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_mul(glmm_load(a), glmm_load(b))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_mul_ps(glmm_load(a), glmm_load(b))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vmulq_f32(vld1q_f32(a), vld1q_f32(b))); -#else - dest[0] = a[0] * b[0]; - dest[1] = a[1] * b[1]; - dest[2] = a[2] * b[2]; - dest[3] = a[3] * b[3]; -#endif -} - -/*! - * @brief multiply/scale vec4 vector with scalar: result = v * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_scale(vec4 v, float s, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_mul(glmm_load(v), wasm_f32x4_splat(s))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_mul_ps(glmm_load(v), glmm_set1(s))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vmulq_f32(vld1q_f32(v), vdupq_n_f32(s))); -#else - dest[0] = v[0] * s; - dest[1] = v[1] * s; - dest[2] = v[2] * s; - dest[3] = v[3] * s; -#endif -} - -/*! - * @brief make vec4 vector scale as specified: result = unit(v) * s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_scale_as(vec4 v, float s, vec4 dest) { - float norm; - norm = glm_vec4_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec4_zero(dest); - return; - } - - glm_vec4_scale(v, s / norm, dest); -} - -/*! - * @brief div vector with another component-wise division: d = a / b - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest result = (a[0]/b[0], a[1]/b[1], a[2]/b[2], a[3]/b[3]) - */ -CGLM_INLINE -void -glm_vec4_div(vec4 a, vec4 b, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_div(glmm_load(a), glmm_load(b))); -#else - dest[0] = a[0] / b[0]; - dest[1] = a[1] / b[1]; - dest[2] = a[2] / b[2]; - dest[3] = a[3] / b[3]; -#endif -} - -/*! - * @brief div vec4 vector with scalar: d = v / s - * - * @param[in] v vector - * @param[in] s scalar - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_divs(vec4 v, float s, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_div(glmm_load(v), glmm_set1(s))); -#else - glm_vec4_scale(v, 1.0f / s, dest); -#endif -} - -/*! - * @brief add two vectors and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a + b) - */ -CGLM_INLINE -void -glm_vec4_addadd(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add( - glmm_load(dest), - wasm_f32x4_add(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(dest), - _mm_add_ps(glmm_load(a), - glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), - vaddq_f32(vld1q_f32(a), - vld1q_f32(b)))); -#else - dest[0] += a[0] + b[0]; - dest[1] += a[1] + b[1]; - dest[2] += a[2] + b[2]; - dest[3] += a[3] + b[3]; -#endif -} - -/*! - * @brief sub two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a - b) - */ -CGLM_INLINE -void -glm_vec4_subadd(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add( - glmm_load(dest), - wasm_f32x4_sub(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(dest), - _mm_sub_ps(glmm_load(a), - glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vaddq_f32(vld1q_f32(dest), - vsubq_f32(vld1q_f32(a), - vld1q_f32(b)))); -#else - dest[0] += a[0] - b[0]; - dest[1] += a[1] - b[1]; - dest[2] += a[2] - b[2]; - dest[3] += a[3] - b[3]; -#endif -} - -/*! - * @brief mul two vectors and add result to dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec4_muladd(vec4 a, vec4 b, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_load(b), glmm_load(dest))); -#else - dest[0] += a[0] * b[0]; - dest[1] += a[1] * b[1]; - dest[2] += a[2] * b[2]; - dest[3] += a[3] * b[3]; -#endif -} - -/*! - * @brief mul vector with scalar and add result to sum - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest += (a * b) - */ -CGLM_INLINE -void -glm_vec4_muladds(vec4 a, float s, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_fmadd(glmm_load(a), glmm_set1(s), glmm_load(dest))); -#else - dest[0] += a[0] * s; - dest[1] += a[1] * s; - dest[2] += a[2] * s; - dest[3] += a[3] * s; -#endif -} - -/*! - * @brief add max of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += max(a, b) - */ -CGLM_INLINE -void -glm_vec4_maxadd(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - glmm_store(dest, vaddq_f32(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#else - dest[0] += glm_max(a[0], b[0]); - dest[1] += glm_max(a[1], b[1]); - dest[2] += glm_max(a[2], b[2]); - dest[3] += glm_max(a[3], b[3]); -#endif -} - -/*! - * @brief add min of two vectors to result/dest - * - * it applies += operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest += min(a, b) - */ -CGLM_INLINE -void -glm_vec4_minadd(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_add(glmm_load(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_add_ps(glmm_load(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - glmm_store(dest, vaddq_f32(glmm_load(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#else - dest[0] += glm_min(a[0], b[0]); - dest[1] += glm_min(a[1], b[1]); - dest[2] += glm_min(a[2], b[2]); - dest[3] += glm_min(a[3], b[3]); -#endif -} - -/*! - * @brief sub two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a - b) - */ -CGLM_INLINE -void -glm_vec4_subsub(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub( - glmm_load(dest), - wasm_f32x4_sub(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(dest), - _mm_sub_ps(glmm_load(a), - glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vsubq_f32(vld1q_f32(dest), - vsubq_f32(vld1q_f32(a), - vld1q_f32(b)))); -#else - dest[0] -= a[0] - b[0]; - dest[1] -= a[1] - b[1]; - dest[2] -= a[2] - b[2]; - dest[3] -= a[3] - b[3]; -#endif -} - -/*! - * @brief add two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a + b) - */ -CGLM_INLINE -void -glm_vec4_addsub(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub( - glmm_load(dest), - wasm_f32x4_add(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(dest), - _mm_add_ps(glmm_load(a), - glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vsubq_f32(vld1q_f32(dest), - vaddq_f32(vld1q_f32(a), - vld1q_f32(b)))); -#else - dest[0] -= a[0] + b[0]; - dest[1] -= a[1] + b[1]; - dest[2] -= a[2] + b[2]; - dest[3] -= a[3] + b[3]; -#endif -} - -/*! - * @brief mul two vectors and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec4_mulsub(vec4 a, vec4 b, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_load(b), glmm_load(dest))); -#else - dest[0] -= a[0] * b[0]; - dest[1] -= a[1] * b[1]; - dest[2] -= a[2] * b[2]; - dest[3] -= a[3] * b[3]; -#endif -} - -/*! - * @brief mul vector with scalar and sub result to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector - * @param[in] s scalar - * @param[out] dest dest -= (a * b) - */ -CGLM_INLINE -void -glm_vec4_mulsubs(vec4 a, float s, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_fnmadd(glmm_load(a), glmm_set1(s), glmm_load(dest))); -#else - dest[0] -= a[0] * s; - dest[1] -= a[1] * s; - dest[2] -= a[2] * s; - dest[3] -= a[3] * s; -#endif -} - -/*! - * @brief sub max of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= max(a, b) - */ -CGLM_INLINE -void -glm_vec4_maxsub(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - glmm_store(dest, vsubq_f32(glmm_load(dest), - glmm_max(glmm_load(a), glmm_load(b)))); -#else - dest[0] -= glm_max(a[0], b[0]); - dest[1] -= glm_max(a[1], b[1]); - dest[2] -= glm_max(a[2], b[2]); - dest[3] -= glm_max(a[3], b[3]); -#endif -} - -/*! - * @brief sub min of two vectors to dest - * - * it applies -= operator so dest must be initialized - * - * @param[in] a vector 1 - * @param[in] b vector 2 - * @param[out] dest dest -= min(a, b) - */ -CGLM_INLINE -void -glm_vec4_minsub(vec4 a, vec4 b, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_sub(glmm_load(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_sub_ps(glmm_load(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#elif defined(CGLM_NEON_FP) - glmm_store(dest, vsubq_f32(vld1q_f32(dest), - glmm_min(glmm_load(a), glmm_load(b)))); -#else - dest[0] -= glm_min(a[0], b[0]); - dest[1] -= glm_min(a[1], b[1]); - dest[2] -= glm_min(a[2], b[2]); - dest[3] -= glm_min(a[3], b[3]); -#endif -} - -/*! - * @brief negate vector components and store result in dest - * - * @param[in] v vector - * @param[out] dest result vector - */ -CGLM_INLINE -void -glm_vec4_negate_to(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(dest, wasm_f32x4_neg(glmm_load(v))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(dest, _mm_xor_ps(glmm_load(v), glmm_float32x4_SIGNMASK_NEG)); -#elif defined(CGLM_NEON_FP) - vst1q_f32(dest, vnegq_f32(vld1q_f32(v))); -#else - dest[0] = -v[0]; - dest[1] = -v[1]; - dest[2] = -v[2]; - dest[3] = -v[3]; -#endif -} - -/*! - * @brief flip sign of all vec4 members - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec4_negate(vec4 v) { - glm_vec4_negate_to(v, v); -} - -/*! - * @brief normalize vec4 to dest - * - * @param[in] v source - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_normalize_to(vec4 v, vec4 dest) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_128 xdot, x0; - float dot; - - x0 = glmm_load(v); - xdot = glmm_vdot(x0, x0); - /* dot = _mm_cvtss_f32(xdot); */ - dot = wasm_f32x4_extract_lane(xdot, 0); - - if (CGLM_UNLIKELY(dot < FLT_EPSILON)) { - glmm_store(dest, wasm_f32x4_const_splat(0.f)); - return; - } - - glmm_store(dest, glmm_div(x0, wasm_f32x4_sqrt(xdot))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - __m128 xdot, x0; - float dot; - - x0 = glmm_load(v); - xdot = glmm_vdot(x0, x0); - dot = _mm_cvtss_f32(xdot); - - if (CGLM_UNLIKELY(dot < FLT_EPSILON)) { - glmm_store(dest, _mm_setzero_ps()); - return; - } - - glmm_store(dest, glmm_div(x0, _mm_sqrt_ps(xdot))); -#else - float norm; - - norm = glm_vec4_norm(v); - - if (CGLM_UNLIKELY(norm < FLT_EPSILON)) { - glm_vec4_zero(dest); - return; - } - - glm_vec4_scale(v, 1.0f / norm, dest); -#endif -} - -/*! - * @brief normalize vec4 and store result in same vec - * - * @param[in, out] v vector - */ -CGLM_INLINE -void -glm_vec4_normalize(vec4 v) { - glm_vec4_normalize_to(v, v); -} - -/** - * @brief distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns distance - */ -CGLM_INLINE -float -glm_vec4_distance(vec4 a, vec4 b) { -#if defined(__wasm__) && defined(__wasm_simd128__) - return glmm_norm(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - return glmm_norm(_mm_sub_ps(glmm_load(a), glmm_load(b))); -#elif defined(CGLM_NEON_FP) - return glmm_norm(vsubq_f32(glmm_load(a), glmm_load(b))); -#else - return sqrtf(glm_pow2(a[0] - b[0]) - + glm_pow2(a[1] - b[1]) - + glm_pow2(a[2] - b[2]) - + glm_pow2(a[3] - b[3])); -#endif -} - -/** - * @brief squared distance between two vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @return returns squared distance - */ -CGLM_INLINE -float -glm_vec4_distance2(vec4 a, vec4 b) { -#if defined(__wasm__) && defined(__wasm_simd128__) - return glmm_norm2(wasm_f32x4_sub(glmm_load(a), glmm_load(b))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - return glmm_norm2(_mm_sub_ps(glmm_load(a), glmm_load(b))); -#elif defined(CGLM_NEON_FP) - return glmm_norm2(vsubq_f32(glmm_load(a), glmm_load(b))); -#else - return glm_pow2(a[0] - b[0]) - + glm_pow2(a[1] - b[1]) - + glm_pow2(a[2] - b[2]) - + glm_pow2(a[3] - b[3]); -#endif -} - -/*! - * @brief max values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_maxv(vec4 a, vec4 b, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_max(glmm_load(a), glmm_load(b))); -#else - dest[0] = glm_max(a[0], b[0]); - dest[1] = glm_max(a[1], b[1]); - dest[2] = glm_max(a[2], b[2]); - dest[3] = glm_max(a[3], b[3]); -#endif -} - -/*! - * @brief min values of vectors - * - * @param[in] a vector1 - * @param[in] b vector2 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_minv(vec4 a, vec4 b, vec4 dest) { -#if defined(CGLM_SIMD) - glmm_store(dest, glmm_min(glmm_load(a), glmm_load(b))); -#else - dest[0] = glm_min(a[0], b[0]); - dest[1] = glm_min(a[1], b[1]); - dest[2] = glm_min(a[2], b[2]); - dest[3] = glm_min(a[3], b[3]); -#endif -} - -/*! - * @brief clamp vector's individual members between min and max values - * - * @param[in, out] v vector - * @param[in] minVal minimum value - * @param[in] maxVal maximum value - */ -CGLM_INLINE -void -glm_vec4_clamp(vec4 v, float minVal, float maxVal) { -#if defined(__wasm__) && defined(__wasm_simd128__) - glmm_store(v, glmm_min(glmm_max(glmm_load(v), wasm_f32x4_splat(minVal)), - wasm_f32x4_splat(maxVal))); -#elif defined( __SSE__ ) || defined( __SSE2__ ) - glmm_store(v, glmm_min(glmm_max(glmm_load(v), glmm_set1(minVal)), - glmm_set1(maxVal))); -#elif defined(CGLM_NEON_FP) - glmm_store(v, glmm_min(glmm_max(vld1q_f32(v), vdupq_n_f32(minVal)), - vdupq_n_f32(maxVal))); -#else - v[0] = glm_clamp(v[0], minVal, maxVal); - v[1] = glm_clamp(v[1], minVal, maxVal); - v[2] = glm_clamp(v[2], minVal, maxVal); - v[3] = glm_clamp(v[3], minVal, maxVal); -#endif -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_lerp(vec4 from, vec4 to, float t, vec4 dest) { - vec4 s, v; - - /* from + s * (to - from) */ - glm_vec4_broadcast(t, s); - glm_vec4_sub(to, from, v); - glm_vec4_mul(s, v, v); - glm_vec4_add(from, v, dest); -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_lerpc(vec4 from, vec4 to, float t, vec4 dest) { - glm_vec4_lerp(from, to, glm_clamp_zo(t), dest); -} - -/*! - * @brief linear interpolation between two vectors - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_mix(vec4 from, vec4 to, float t, vec4 dest) { - glm_vec4_lerp(from, to, t, dest); -} - -/*! - * @brief linear interpolation between two vectors (clamped) - * - * formula: from + t * (to - from) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_mixc(vec4 from, vec4 to, float t, vec4 dest) { - glm_vec4_lerpc(from, to, t, dest); -} - -/*! - * @brief threshold function - * - * @param[in] edge threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_step(vec4 edge, vec4 x, vec4 dest) { - dest[0] = glm_step(edge[0], x[0]); - dest[1] = glm_step(edge[1], x[1]); - dest[2] = glm_step(edge[2], x[2]); - dest[3] = glm_step(edge[3], x[3]); -} - -/*! - * @brief threshold function with a smooth transition (unidimensional) - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_smoothstep_uni(float edge0, float edge1, vec4 x, vec4 dest) { - dest[0] = glm_smoothstep(edge0, edge1, x[0]); - dest[1] = glm_smoothstep(edge0, edge1, x[1]); - dest[2] = glm_smoothstep(edge0, edge1, x[2]); - dest[3] = glm_smoothstep(edge0, edge1, x[3]); -} - -/*! - * @brief threshold function with a smooth transition - * - * @param[in] edge0 low threshold - * @param[in] edge1 high threshold - * @param[in] x value to test against threshold - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_smoothstep(vec4 edge0, vec4 edge1, vec4 x, vec4 dest) { - dest[0] = glm_smoothstep(edge0[0], edge1[0], x[0]); - dest[1] = glm_smoothstep(edge0[1], edge1[1], x[1]); - dest[2] = glm_smoothstep(edge0[2], edge1[2], x[2]); - dest[3] = glm_smoothstep(edge0[3], edge1[3], x[3]); -} - -/*! - * @brief smooth Hermite interpolation between two vectors - * - * formula: t^2 * (3 - 2*t) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_smoothinterp(vec4 from, vec4 to, float t, vec4 dest) { - vec4 s, v; - - /* from + smoothstep * (to - from) */ - glm_vec4_broadcast(glm_smooth(t), s); - glm_vec4_sub(to, from, v); - glm_vec4_mul(s, v, v); - glm_vec4_add(from, v, dest); -} - -/*! - * @brief smooth Hermite interpolation between two vectors (clamped) - * - * formula: t^2 * (3 - 2*t) - * - * @param[in] from from value - * @param[in] to to value - * @param[in] t interpolant (amount) clamped between 0 and 1 - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_smoothinterpc(vec4 from, vec4 to, float t, vec4 dest) { - glm_vec4_smoothinterp(from, to, glm_clamp_zo(t), dest); -} - -/*! - * @brief helper to fill vec4 as [S^3, S^2, S, 1] - * - * @param[in] s parameter - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_cubic(float s, vec4 dest) { - float ss; - - ss = s * s; - - dest[0] = ss * s; - dest[1] = ss; - dest[2] = s; - dest[3] = 1.0f; -} - -/*! - * @brief swizzle vector components - * - * you can use existing masks e.g. GLM_XXXX, GLM_WZYX - * - * @param[in] v source - * @param[in] mask mask - * @param[out] dest destination - */ -CGLM_INLINE -void -glm_vec4_swizzle(vec4 v, int mask, vec4 dest) { - vec4 t; - - t[0] = v[(mask & (3 << 0))]; - t[1] = v[(mask & (3 << 2)) >> 2]; - t[2] = v[(mask & (3 << 4)) >> 4]; - t[3] = v[(mask & (3 << 6)) >> 6]; - - glm_vec4_copy(t, dest); -} - -/*! - * @brief Create four dimensional vector from pointer - * - * @param[in] src pointer to an array of floats - * @param[out] dest destination vector - */ -CGLM_INLINE -void -glm_vec4_make(const float * __restrict src, vec4 dest) { - dest[0] = src[0]; dest[1] = src[1]; - dest[2] = src[2]; dest[3] = src[3]; -} - -/*! - * @brief reflection vector using an incident ray and a surface normal - * - * @param[in] v incident vector - * @param[in] n normalized normal vector - * @param[out] dest destination vector for the reflection result - */ -CGLM_INLINE -void -glm_vec4_reflect(vec4 v, vec4 n, vec4 dest) { - vec4 temp; - - /* TODO: direct simd touch */ - glm_vec4_scale(n, 2.0f * glm_vec4_dot(v, n), temp); - glm_vec4_sub(v, temp, dest); - - dest[3] = v[3]; -} - -/*! - * @brief computes refraction vector for an incident vector and a surface normal. - * - * calculates the refraction vector based on Snell's law. If total internal reflection - * occurs (angle too great given eta), dest is set to zero and returns false. - * Otherwise, computes refraction vector, stores it in dest, and returns true. - * - * this implementation does not explicitly preserve the 'w' component of the - * incident vector 'I' in the output 'dest', users requiring the preservation of - * the 'w' component should manually adjust 'dest' after calling this function. - * - * @param[in] v normalized incident vector - * @param[in] n normalized normal vector - * @param[in] eta ratio of indices of refraction (incident/transmitted) - * @param[out] dest refraction vector if refraction occurs; zero vector otherwise - * - * @returns true if refraction occurs; false if total internal reflection occurs. - */ -CGLM_INLINE -bool -glm_vec4_refract(vec4 v, vec4 n, float eta, vec4 dest) { - float ndi, eni, k; - - ndi = glm_vec4_dot(n, v); - eni = eta * ndi; - k = 1.0f - eta * eta + eni * eni; - - if (k < 0.0f) { - glm_vec4_zero(dest); - return false; - } - - glm_vec4_scale(v, eta, dest); - glm_vec4_mulsubs(n, eni + sqrtf(k), dest); - return true; -} - -#endif /* cglm_vec4_h */ diff --git a/external/cglm/version.h b/external/cglm/version.h deleted file mode 100644 index 9e815d4..0000000 --- a/external/cglm/version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c), Recep Aslantas. - * - * MIT License (MIT), http://opensource.org/licenses/MIT - * Full license can be found in the LICENSE file - */ - -#ifndef cglm_version_h -#define cglm_version_h - -#define CGLM_VERSION_MAJOR 0 -#define CGLM_VERSION_MINOR 9 -#define CGLM_VERSION_PATCH 6 - -#endif /* cglm_version_h */ diff --git a/external/tinyalloc/tinyalloc.c b/external/tinyalloc/tinyalloc.c index eb9fa3f..1de3a04 100644 --- a/external/tinyalloc/tinyalloc.c +++ b/external/tinyalloc/tinyalloc.c @@ -11,24 +11,30 @@ extern void print_i(size_t); typedef struct Block Block; -struct Block { - void *addr; - Block *next; - size_t size; +struct Block +{ + void *addr; + Block *next; + size_t size; }; -typedef struct { - Block *free; // first free block - Block *used; // first used block - Block *fresh; // first available blank block - size_t top; // top free addr +typedef struct +{ + Block *free; // first free block + Block *used; // first used block + Block *fresh; // first available blank block + size_t top; // top free addr } Heap; -static Heap *heap = NULL; -static const void *heap_limit = NULL; -static size_t heap_split_thresh; -static size_t heap_alignment; -static size_t heap_max_blocks; +extern uint8_t __heap_base; +extern uint8_t __data_end; + +static Heap *heap = NULL; +static const void *heap_limit = NULL; +static size_t heap_split_thresh; +static size_t heap_alignment; +static size_t heap_max_blocks; +static size_t current_pages; /** * If compaction is enabled, inserts block @@ -36,235 +42,342 @@ static size_t heap_max_blocks; * If disabled, add block has new head of * the free list. */ -static void insert_block(Block *block) { +static void insert_block(Block *block) +{ #ifndef TA_DISABLE_COMPACT - Block *ptr = heap->free; - Block *prev = NULL; - while (ptr != NULL) { - if ((size_t)block->addr <= (size_t)ptr->addr) { - print_s("insert"); - print_i((size_t)ptr); - break; - } - prev = ptr; - ptr = ptr->next; - } - if (prev != NULL) { - if (ptr == NULL) { - print_s("new tail"); - } - prev->next = block; - } else { - print_s("new head"); - heap->free = block; - } - block->next = ptr; + Block *ptr = heap->free; + Block *prev = NULL; + while (ptr != NULL) + { + if ((size_t)block->addr <= (size_t)ptr->addr) + { + print_s("insert"); + print_i((size_t)ptr); + break; + } + prev = ptr; + ptr = ptr->next; + } + + if (prev != NULL) + { + if (ptr == NULL) + { + print_s("new tail"); + } + prev->next = block; + } + else + { + print_s("new head"); + heap->free = block; + } + block->next = ptr; #else - block->next = heap->free; - heap->free = block; + block->next = heap->free; + heap->free = block; #endif } #ifndef TA_DISABLE_COMPACT -static void release_blocks(Block *scan, Block *to) { - Block *scan_next; - while (scan != to) { - print_s("release"); - print_i((size_t)scan); - scan_next = scan->next; - scan->next = heap->fresh; - heap->fresh = scan; - scan->addr = 0; - scan->size = 0; - scan = scan_next; - } +static void release_blocks(Block *scan, Block *to) +{ + Block *scan_next; + while (scan != to) + { + print_s("release"); + print_i((size_t)scan); + scan_next = scan->next; + scan->next = heap->fresh; + heap->fresh = scan; + scan->addr = 0; + scan->size = 0; + scan = scan_next; + } } -static void compact() { - Block *ptr = heap->free; - Block *prev; - Block *scan; - while (ptr != NULL) { - prev = ptr; - scan = ptr->next; - while (scan != NULL && - (size_t)prev->addr + prev->size == (size_t)scan->addr) { - print_s("merge"); - print_i((size_t)scan); - prev = scan; - scan = scan->next; - } - if (prev != ptr) { - size_t new_size = - (size_t)prev->addr - (size_t)ptr->addr + prev->size; - print_s("new size"); - print_i(new_size); - ptr->size = new_size; - Block *next = prev->next; - // make merged blocks available - release_blocks(ptr->next, prev->next); - // relink - ptr->next = next; - } - ptr = ptr->next; - } +static void compact() +{ + Block *ptr = heap->free; + Block *prev; + Block *scan; + while (ptr != NULL) + { + prev = ptr; + scan = ptr->next; + + while (scan != NULL && (size_t)prev->addr + prev->size == (size_t)scan->addr) + { + print_s("merge"); + print_i((size_t)scan); + prev = scan; + scan = scan->next; + } + + if (prev != ptr) + { + size_t new_size = (size_t)prev->addr - (size_t)ptr->addr + prev->size; + print_s("new size"); + print_i(new_size); + ptr->size = new_size; + Block *next = prev->next; + // make merged blocks available + release_blocks(ptr->next, prev->next); + // relink + ptr->next = next; + } + + ptr = ptr->next; + } } #endif -bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment) { - heap = (Heap *)base; - heap_limit = limit; - heap_split_thresh = split_thresh; - heap_alignment = alignment; - heap_max_blocks = heap_blocks; - - heap->free = NULL; - heap->used = NULL; - heap->fresh = (Block *)(heap + 1); - heap->top = (size_t)(heap->fresh + heap_blocks); - - Block *block = heap->fresh; - size_t i = heap_max_blocks - 1; - while (i--) { - block->next = block + 1; - block++; - } - block->next = NULL; - return true; +uint32_t ta_grow(uint32_t pages) +{ + return __builtin_wasm_memory_grow(0, pages); } -bool ta_free(void *free) { - Block *block = heap->used; - Block *prev = NULL; - while (block != NULL) { - if (free == block->addr) { - if (prev) { - prev->next = block->next; - } else { - heap->used = block->next; - } - insert_block(block); +uint32_t ta_page_count() +{ + return __builtin_wasm_memory_size(0); +} + +void ta_init(const size_t heap_blocks, const size_t split_thresh, const size_t alignment) +{ + current_pages = ta_page_count(); + void *limit = (void *)ta_PAGE_SIZE(current_pages); + + heap = (Heap *)&__heap_base; + heap_limit = limit; + heap_split_thresh = split_thresh; + heap_alignment = alignment; + heap_max_blocks = heap_blocks; + + heap->free = NULL; + heap->used = NULL; + heap->fresh = (Block *)(heap + 1); + heap->top = (size_t)(heap->fresh + heap_blocks); + + Block *block = heap->fresh; + size_t i = heap_max_blocks - 1; + while (i--) + { + block->next = block + 1; + block++; + } + + block->next = NULL; +} + +void free(void *ptr) +{ + Block *block = heap->used; + Block *prev = NULL; + while (block != NULL) + { + if (ptr == block->addr) + { + if (prev) + { + prev->next = block->next; + } + else + { + heap->used = block->next; + } + insert_block(block); #ifndef TA_DISABLE_COMPACT - compact(); + compact(); #endif - return true; - } - prev = block; - block = block->next; - } - return false; + } + prev = block; + block = block->next; + } } -static Block *alloc_block(size_t num) { - Block *ptr = heap->free; - Block *prev = NULL; - size_t top = heap->top; - num = (num + heap_alignment - 1) & -heap_alignment; - while (ptr != NULL) { - const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= (size_t)heap_limit); - if (is_top || ptr->size >= num) { - if (prev != NULL) { - prev->next = ptr->next; - } else { - heap->free = ptr->next; - } - ptr->next = heap->used; - heap->used = ptr; - if (is_top) { - print_s("resize top block"); - ptr->size = num; - heap->top = (size_t)ptr->addr + num; +size_t ta_ptr_size(void *ptr) +{ + size_t result = 0; + + Block *block = heap->used; + while(block != NULL) + { + if(ptr == block->addr) + { + result = block->size; + break; + } + } + + return result; +} + +static Block *alloc_block(size_t num) +{ + Block *ptr = heap->free; + Block *prev = NULL; + size_t top = heap->top; + num = (num + heap_alignment - 1) & -heap_alignment; + while (ptr != NULL) + { + const int is_top = ((size_t)ptr->addr + ptr->size >= top) && ((size_t)ptr->addr + num <= (size_t)heap_limit); + if (is_top || ptr->size >= num) + { + if (prev != NULL) + { + prev->next = ptr->next; + } + else + { + heap->free = ptr->next; + } + ptr->next = heap->used; + heap->used = ptr; + if (is_top) + { + print_s("resize top block"); + ptr->size = num; + heap->top = (size_t)ptr->addr + num; #ifndef TA_DISABLE_SPLIT - } else if (heap->fresh != NULL) { - size_t excess = ptr->size - num; - if (excess >= heap_split_thresh) { - ptr->size = num; - Block *split = heap->fresh; - heap->fresh = split->next; - split->addr = (void *)((size_t)ptr->addr + num); - print_s("split"); - print_i((size_t)split->addr); - split->size = excess; - insert_block(split); + } + else if (heap->fresh != NULL) + { + size_t excess = ptr->size - num; + if (excess >= heap_split_thresh) + { + ptr->size = num; + Block *split = heap->fresh; + heap->fresh = split->next; + split->addr = (void *)((size_t)ptr->addr + num); + print_s("split"); + print_i((size_t)split->addr); + split->size = excess; + insert_block(split); #ifndef TA_DISABLE_COMPACT - compact(); + compact(); #endif - } + } #endif - } - return ptr; - } - prev = ptr; - ptr = ptr->next; - } - // no matching free blocks - // see if any other blocks available - size_t new_top = top + num; - if (heap->fresh != NULL && new_top <= (size_t)heap_limit) { - ptr = heap->fresh; - heap->fresh = ptr->next; - ptr->addr = (void *)top; - ptr->next = heap->used; - ptr->size = num; - heap->used = ptr; - heap->top = new_top; - return ptr; - } - return NULL; + } + + return ptr; + } + + prev = ptr; + ptr = ptr->next; + } + // no matching free blocks + // see if any other blocks available + size_t new_top = top + num; + if (heap->fresh != NULL && new_top <= (size_t)heap_limit) + { + ptr = heap->fresh; + heap->fresh = ptr->next; + ptr->addr = (void *)top; + ptr->next = heap->used; + ptr->size = num; + heap->used = ptr; + heap->top = new_top; + return ptr; + } + + return NULL; } -void *ta_alloc(size_t num) { - Block *block = alloc_block(num); - if (block != NULL) { - return block->addr; - } - return NULL; +static size_t ta_bytes_to_pages(size_t count) +{ + size_t pages = count/(1024*64); + return pages > 0 ? pages : 1; } -static void memclear(void *ptr, size_t num) { - size_t *ptrw = (size_t *)ptr; - size_t numw = (num & -sizeof(size_t)) / sizeof(size_t); - while (numw--) { - *ptrw++ = 0; - } - num &= (sizeof(size_t) - 1); - uint8_t *ptrb = (uint8_t *)ptrw; - while (num--) { - *ptrb++ = 0; - } +void *malloc(size_t num) +{ + Block *block = alloc_block(num); + + if(block == NULL) + { + ta_grow(ta_bytes_to_pages(num)); + size_t new_pages = ta_page_count(); + size_t page_diff = new_pages - current_pages; + if(page_diff > 0) + { + current_pages = new_pages; + heap_limit = (void *)ta_PAGE_SIZE(current_pages); + + block = alloc_block(num); + } + } + + return block != NULL ? block->addr : NULL; } -void *ta_calloc(size_t num, size_t size) { - num *= size; - Block *block = alloc_block(num); - if (block != NULL) { - memclear(block->addr, num); - return block->addr; - } - return NULL; +static void memclear(void *ptr, size_t num) +{ + size_t *ptrw = (size_t *)ptr; + size_t numw = (num & -sizeof(size_t)) / sizeof(size_t); + while (numw--) + { + *ptrw++ = 0; + } + num &= (sizeof(size_t) - 1); + uint8_t *ptrb = (uint8_t *)ptrw; + while (num--) + { + *ptrb++ = 0; + } } -static size_t count_blocks(Block *ptr) { - size_t num = 0; - while (ptr != NULL) { - num++; - ptr = ptr->next; - } - return num; +void *calloc(size_t num, size_t size) +{ + num *= size; + Block *block = alloc_block(num); + if (block != NULL) + { + memclear(block->addr, num); + return block->addr; + } + return NULL; } -size_t ta_num_free() { - return count_blocks(heap->free); +void *realloc(void *ptr, size_t size) +{ + void *new_ptr = malloc(size); + size_t prev_size = ta_ptr_size(ptr); + + __builtin_memcpy(new_ptr, ptr, prev_size); + + free(ptr); + + return new_ptr; } -size_t ta_num_used() { - return count_blocks(heap->used); +static size_t count_blocks(Block *ptr) +{ + size_t num = 0; + while (ptr != NULL) + { + num++; + ptr = ptr->next; + } + return num; } -size_t ta_num_fresh() { - return count_blocks(heap->fresh); +size_t ta_num_free() +{ + return count_blocks(heap->free); } -bool ta_check() { - return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh(); +size_t ta_num_used() +{ + return count_blocks(heap->used); +} + +size_t ta_num_fresh() +{ + return count_blocks(heap->fresh); +} + +bool ta_check() +{ + return heap_max_blocks == ta_num_free() + ta_num_used() + ta_num_fresh(); } diff --git a/external/tinyalloc/tinyalloc.h b/external/tinyalloc/tinyalloc.h index 0d00596..c10b68a 100644 --- a/external/tinyalloc/tinyalloc.h +++ b/external/tinyalloc/tinyalloc.h @@ -6,13 +6,18 @@ extern "C" { #include #include -uint32_t grow(uint32_t pages); +#define ta_PAGE_SIZE(x)(x*1024*64) -bool ta_init(const void *base, const void *limit, const size_t heap_blocks, const size_t split_thresh, const size_t alignment); -void *ta_alloc(size_t num); -void *ta_calloc(size_t num, size_t size); -bool ta_free(void *ptr); +void ta_init(const size_t heap_blocks, const size_t split_thresh, const size_t alignment); +uint32_t ta_grow(uint32_t pages); +uint32_t ta_page_count(); +void *malloc(size_t num); +void *calloc(size_t num, size_t size); +void free(void *ptr); +void *realloc(void *ptr, size_t num); + +size_t ta_ptr_size(void *ptr); size_t ta_num_free(); size_t ta_num_used(); size_t ta_num_fresh(); diff --git a/fonts.d b/fonts.d index 2f253f4..7a91625 100644 --- a/fonts.d +++ b/fonts.d @@ -1,13 +1,20 @@ module dlib.fonts; -import dlibincludes; +static if(NativeTarget) +{ + import dlibincludes : FT_Library, FT_Face, FT_Error, FT_Bitmap, FT_GlyphSlot, FT_Int32, FT_ULong, FT_Long, + FT_Set_Pixel_Sizes, FT_Load_Char, FT_Done_Face, FT_New_Memory_Face, FT_Done_FreeType, FT_Init_FreeType, + FT_LOAD_RENDER, FT_PIXEL_MODE_GRAY, FT_PIXEL_MODE_MONO, FT_PIXEL_MODE_BGRA; +} + +import dlib.externdecl; import dlib.aliases; import dlib.util; import dlib.alloc; import dlib.math; -const u64 FONT_MAX_BANDS = 8; -const u64 FONT_TEX_WIDTH = 4096; +const u32 FONT_MAX_BANDS = 8; +const u32 FONT_TEX_WIDTH = 4096; struct SlugTexel(T) { @@ -164,11 +171,6 @@ static if(NativeTarget) __gshared FT_Library FT_LIB; alias FontFace = FT_Face; -shared static this() -{ - FT_Init_FreeType(&FT_LIB); -} - void CloseFreeType() { @@ -410,14 +412,14 @@ BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info f32 x = cast(f32)(vtx.x); f32 y = cast(f32)(vtx.y); - switch(vtx.type) + switch(vtx.type) with(stbtt_curvetype) { - case STBTT_vmove: + case vmove: { cx = x; cy = y; } break; - case STBTT_vline: + case vline: { f32 dx = x-cx; f32 dy = y-cy; @@ -429,7 +431,7 @@ BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info break; } - f32 length = Sqrt(dx*dx + dy*dy); + f32 length = sqrt(dx*dx + dy*dy); f32 nx = -dy/length*0.05; f32 ny = -dx/length*0.05; @@ -446,7 +448,7 @@ BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info *curve_index += 1; } break; - case STBTT_vcurve: + case vcurve: { SlugCurve* curve = &font_info.curves[*curve_index]; @@ -458,7 +460,7 @@ BuildFontGlyph(Arena* arena, u32 index, u32 glyph_index, SlugFontInfo* font_info *curve_index += 1; } break; - case STBTT_vcubic: + case vcubic: { f32 cx1 = cast(f32)(vtx.cx ); f32 cy1 = cast(f32)(vtx.cy ); @@ -749,11 +751,11 @@ SlugCountCurvesForGlyph(u32 glyph_index, stbtt_fontinfo* stb_font_info) foreach(i; 0 .. vertex_count) { - switch(vertices[i].type) + switch(vertices[i].type) with(stbtt_curvetype) { - case STBTT_vline, STBTT_vcurve: result += 1; break; - case STBTT_vcubic: result += 2; break; - default: break; + case vline, vcurve: result += 1; break; + case vcubic: result += 2; break; + default: break; } } diff --git a/main.wasm b/main.wasm deleted file mode 100755 index 4b590d2ea5b1fac25467d9b53b7f1ad2aad43c9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30020 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 z 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 diff --git a/math.d b/math.d index f121f51..aa99932 100644 --- a/math.d +++ b/math.d @@ -3,15 +3,12 @@ module dlib.math; import dlib.aliases; import dlib.util; -import dlibincludes; - import std.traits; import std.math.traits; import std.meta; -static if(NativeTarget) -{ -} +public import std.math.rounding : round; +public import core.math : sqrt, cos, sin; enum PI = 3.14159L; @@ -98,6 +95,7 @@ Mul64(u64 a, u64 b) return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32); } +/* T Sqrt(T)(T x) if(isFloatingPoint!(T)) { @@ -172,6 +170,7 @@ Sqrt(T)(T x) if(isFloatingPoint!(T)) return y; } +*/ T Abs(T)(T x) if(isSigned!(T)) @@ -635,7 +634,10 @@ struct Vector(T, int N) } else { - static assert(false, "Currently not supported for platform"); + static foreach(i; 0 .. N) + { + mixin("result.v[", i, "] = this.v[", i, "] " ~op~ " operand;"); + } } return result; @@ -804,15 +806,9 @@ align(16) struct Matrix(T, int D) union { - T[N] v = 0; - Row[D] rows; + T[N] v = 0; + Row[D] rows; MatrixVec[D] vec; - static if(NativeTarget) - { - static if(D == 4) mat4 glm_mat; - static if(D == 3) mat3 glm_mat; - static if(D == 2) mat2 glm_mat; - } } // TODO: setup @@ -920,15 +916,12 @@ align(16) struct Matrix(T, int D) static if(D == 4) { - Vec4 opBinary(string op, U)(U x) if(is(U: Vec4) && is(T: f32) && (op == "*")) + Vec4 opBinary(string op)(Vec4 x) if(is(T: f32) && (op == "*")) { Vec4 result = 0.0; - static if(NativeTarget) - { - glm_mat4_mulv(glm_mat.ptr, x.v.ptr, result.v.ptr); - } - else assert(false, "Not implemented for platform"); + // TODO: optimize + Mat4MulVec4(&this, &x, &result); return result; } @@ -961,8 +954,8 @@ struct Quat { union { - f32[4] v = 0; - Vec4 vec; + f32[4] v = 0; + Vec4 vec; struct { f32 x; @@ -984,11 +977,8 @@ struct Quat { Mat4 result; - static if(NativeTarget) - { - glm_quat_mat4(vec.ptr, result.glm_mat.ptr); - } - else assert(false, "Not implemented for platform"); + // TODO: optimize + Mat4FromQuat(&this, &result); return result; } @@ -1024,25 +1014,25 @@ Mat4Mul(Mat4* l, Mat4* r, Mat4* result) movups XMM4, [R9+48]; movups XMM6, XMM1; - shufps XMM6, XMM6, 0; // XMM5 = vec.xxxx; - mulps XMM6, XMM0; // XMM6 = col1; + shufps XMM6, XMM6, 0; // XMM5 = vec.xxxx; + mulps XMM6, XMM0; // XMM6 = col1; movups XMM7, XMM2; shufps XMM7, XMM7, 0; - mulps XMM7, XMM0; // XMM7 = col2; + mulps XMM7, XMM0; // XMM7 = col2; movups XMM8, XMM3; shufps XMM8, XMM8, 0; - mulps XMM8, XMM0; // XMM8 = col3; + mulps XMM8, XMM0; // XMM8 = col3; movups XMM9, XMM4; shufps XMM9, XMM9, 0; - mulps XMM9, XMM0; // XMM9 = col4; + mulps XMM9, XMM0; // XMM9 = col4; movups XMM0, [R8+16]; movups XMM5, XMM1; - shufps XMM5, XMM5, 85; // XMM5 = vec.yyyy; + shufps XMM5, XMM5, 85; // XMM5 = vec.yyyy; mulps XMM5, XMM0; addps XMM6, XMM5; @@ -1113,6 +1103,98 @@ Mat4Mul(Mat4* l, Mat4* r, Mat4* result) } } +void +Vec4MulAddScale(Vec4* a, f32 s, Vec4* dst) // glm_vec4_muladds +{ + (*dst) += (*a)*s; +} + +void +Mat4Inv(Mat4* mat, Mat4* dst) // glm_mat4_inv +{ + f32 a = mat.rows[0][0], b = mat.rows[0][1], c = mat.rows[0][2], d = mat.rows[0][3], + e = mat.rows[1][0], f = mat.rows[1][1], g = mat.rows[1][2], h = mat.rows[1][3], + i = mat.rows[2][0], j = mat.rows[2][1], k = mat.rows[2][2], l = mat.rows[2][3], + m = mat.rows[3][0], n = mat.rows[3][1], o = mat.rows[3][2], p = mat.rows[3][3], + + c1 = k * p - l * o, c2 = c * h - d * g, c3 = i * p - l * m, + c4 = a * h - d * e, c5 = j * p - l * n, c6 = b * h - d * f, + c7 = i * n - j * m, c8 = a * f - b * e, c9 = j * o - k * n, + c10 = b * g - c * f, c11 = i * o - k * m, c12 = a * g - c * e, + + idt = 1.0f/(c8*c1+c4*c9+c10*c3+c2*c7-c12*c5-c6*c11), ndt = -idt; + + dst.rows[0][0] = (f * c1 - g * c5 + h * c9) * idt; + dst.rows[0][1] = (b * c1 - c * c5 + d * c9) * ndt; + dst.rows[0][2] = (n * c2 - o * c6 + p * c10) * idt; + dst.rows[0][3] = (j * c2 - k * c6 + l * c10) * ndt; + + dst.rows[1][0] = (e * c1 - g * c3 + h * c11) * ndt; + dst.rows[1][1] = (a * c1 - c * c3 + d * c11) * idt; + dst.rows[1][2] = (m * c2 - o * c4 + p * c12) * ndt; + dst.rows[1][3] = (i * c2 - k * c4 + l * c12) * idt; + + dst.rows[2][0] = (e * c5 - f * c3 + h * c7) * idt; + dst.rows[2][1] = (a * c5 - b * c3 + d * c7) * ndt; + dst.rows[2][2] = (m * c6 - n * c4 + p * c8) * idt; + dst.rows[2][3] = (i * c6 - j * c4 + l * c8) * ndt; + + dst.rows[3][0] = (e * c9 - f * c11 + g * c7) * ndt; + dst.rows[3][1] = (a * c9 - b * c11 + c * c7) * idt; + dst.rows[3][2] = (m * c10 - n * c12 + o * c8) * ndt; + dst.rows[3][3] = (i * c10 - j * c12 + k * c8) * idt; +} + +void +Mat4MulVec4(Mat4* m, Vec4* v, Vec4* dst) // glm_mat4_mulv +{ + dst.v[0] = m.rows[0][0] * v.v[0] + m.rows[1][0] * v.v[1] + m.rows[2][0] * v.v[2] + m.rows[3][0] * v.v[3]; + dst.v[1] = m.rows[0][1] * v.v[0] + m.rows[1][1] * v.v[1] + m.rows[2][1] * v.v[2] + m.rows[3][1] * v.v[3]; + dst.v[2] = m.rows[0][2] * v.v[0] + m.rows[1][2] * v.v[1] + m.rows[2][2] * v.v[2] + m.rows[3][2] * v.v[3]; + dst.v[3] = m.rows[0][3] * v.v[0] + m.rows[1][3] * v.v[1] + m.rows[2][3] * v.v[2] + m.rows[3][3] * v.v[3]; +} + +void +Mat4FromQuat(Quat* q, Mat4* dst) // glm_quat_mat4 +{ + f32 w, x, y, z, + xx, yy, zz, + xy, yz, xz, + wx, wy, wz, norm, s; + + norm = Norm(q); + s = norm > 0.0f ? 2.0f/norm : 0.0f; + + x = q.v[0]; + y = q.v[1]; + z = q.v[2]; + w = q.v[3]; + + xx = s * x * x; xy = s * x * y; wx = s * w * x; + yy = s * y * y; yz = s * y * z; wy = s * w * y; + zz = s * z * z; xz = s * x * z; wz = s * w * z; + + dst.rows[0][0] = 1.0f - yy - zz; + dst.rows[1][1] = 1.0f - xx - zz; + dst.rows[2][2] = 1.0f - xx - yy; + + dst.rows[0][1] = xy + wz; + dst.rows[1][2] = yz + wx; + dst.rows[2][0] = xz + wy; + + dst.rows[1][0] = xy - wz; + dst.rows[2][1] = yz - wx; + dst.rows[0][2] = xz - wy; + + dst.rows[0][3] = 0.0f; + dst.rows[1][3] = 0.0f; + dst.rows[2][3] = 0.0f; + dst.rows[3][0] = 0.0f; + dst.rows[3][1] = 0.0f; + dst.rows[3][2] = 0.0f; + dst.rows[3][3] = 1.0f; +} + pragma(inline) Mat4 Mat4Identity() { @@ -1155,15 +1237,20 @@ Mat2Identity() } pragma(inline) Quat -QuatFromAxis(f32 angle, Vec3 axis) +QuatFromAxis(f32 angle, Vec3 axis) // glm_quatv { Quat q; - static if(NativeTarget) - { - glm_quatv(q.vec.ptr, angle, axis.v.ptr); - } - else assert(false, "Not implemented for platform"); + f32 a = angle * 0.5f; + f32 c = cos(a); + f32 s = sin(a); + + Vec3 k = Normalize(axis); + + q.x = s * k.x; + q.y = s * k.y; + q.z = s * k.z; + q.w = c; return q; } @@ -1187,17 +1274,23 @@ Dot(Vec4* l, Vec4* r) return l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w; } +pragma(inline) f32 +Norm(Quat* q) +{ + return Norm(&q.vec); +} + pragma(inline) f32 Norm(Vec3* v) { - return Sqrt(Dot(v, v)); + return sqrt(Dot(v, v)); } pragma(inline) f32 Norm(Vec4* v) { // TODO: SIMD this - return Sqrt(Dot(v, v)); + return sqrt(Dot(v, v)); } pragma(inline) void @@ -1238,51 +1331,56 @@ Normalize(Quat q) q = Quat(1.0, 0.0, 0.0, 0.0); } - q.vec *= 1.0 / Sqrt(dot); + q.vec *= 1.0 / sqrt(dot); return q; } pragma(inline) Mat4 -Perspective(f32 fov, f32 aspect, f32 near, f32 far) +Perspective(bool flip_y = true)(f32 fov, f32 aspect, f32 near, f32 far) // glm_perspective_lh_zo { - Mat4 res; - MatZero(&res); + Mat4 mat; - static if(NativeTarget) + f32 f = 1.0f / tanf(fovy * 0.5f); + f32 fn = 1.0f / (nearZ - farZ); + + mat.rows[0][0] = f / aspect; + mat.rows[1][1] = f; + mat.rows[2][2] = -far * fn; + mat.rows[2][3] = 1.0f; + mat.rows[3][2] = near * far * fn; + + static if(flip_y) { - glm_perspective(fov, aspect, near, far, res.glm_mat.ptr); + mat[1, 1] *= -1.0; } - else assert(false, "Not implemented for platform"); - res[1, 1] *= -1.0; return res; } void -Ortho(Mat4* mat, f32 left, f32 bottom, f32 right, f32 top, f32 near, f32 far) +Ortho(Mat4* mat, f32 left, f32 bottom, f32 right, f32 top, f32 near, f32 far) // glm_ortho_lh_zo { MatZero(mat); - static if(NativeTarget) - { - glm_ortho(left, right, bottom, top, near, far, mat.glm_mat.ptr); - } - else assert(false, "Not implemented for platform"); + f32 rl = 1.0f / (right - left); + f32 tb = 1.0f / (top - bottom); + f32 fn =-1.0f / (far - near); + + mat.rows[0][0] = 2.0f * rl; + mat.rows[1][1] = 2.0f * tb; + mat.rows[2][2] =-fn; + mat.rows[3][0] =-(right + left) * rl; + mat.rows[3][1] =-(top + bottom) * tb; + mat.rows[3][2] = near * fn; + mat.rows[3][3] = 1.0f; } Mat4 Ortho(f32 left, f32 bottom, f32 right, f32 top, f32 near, f32 far) { Mat4 mat; - MatZero(&mat); - - static if(NativeTarget) - { - glm_ortho(left, right, bottom, top, near, far, mat.glm_mat.ptr); - } - else assert(false, "Not implemented for platform"); - + Ortho(&mat, left, bottom, right, top, near, far); return mat; } @@ -1311,16 +1409,29 @@ Rotate(Quat q, Vec3 vec) } pragma(inline) Mat4 -LookAt(Vec3 eye, Vec3 center, Vec3 up) +LookAt(Vec3 eye, Vec3 center, Vec3 up) // glm_lookat_lh { Mat4 result; - MatZero(&result); - static if(NativeTarget) - { - glm_lookat(eye.v.ptr, center.v.ptr, up.v.ptr, result.glm_mat.ptr); - } - else assert(false, "Not implemented for platform"); + Vec3 f = Normalize(center - eye); + + Vec3 s = CrossN(up, f); + Vec3 u = Cross(f, s); + + result.rows[0][0] = s[0]; + result.rows[0][1] = u[0]; + result.rows[0][2] = f[0]; + result.rows[1][0] = s[1]; + result.rows[1][1] = u[1]; + result.rows[1][2] = f[1]; + result.rows[2][0] = s[2]; + result.rows[2][1] = u[2]; + result.rows[2][2] = f[2]; + result.rows[3][0] =-Dot(&s, &eye); + result.rows[3][1] =-Dot(&u, &eye); + result.rows[3][2] =-Dot(&f, &eye); + result.rows[0][3] = result.rows[1][3] = result.rows[2][3] = 0.0f; + result.rows[3][3] = 1.0f; return result; } @@ -1352,22 +1463,15 @@ pragma(inline) void CrossN(Vec3 a, Vec3 b, Vec3* dst) { Cross(a, b, dst); - - static if(NativeTarget) - { - glm_vec3_normalize(dst.v.ptr); - } - else assert(false, "Not implemented for platform"); + Normalize(dst); } pragma(inline) void Cross(Vec3 a, Vec3 b, Vec3* dst) { - static if(NativeTarget) - { - glm_vec3_cross(a.v.ptr, b.v.ptr, dst.v.ptr); - } - else assert(false, "Not implemented for platform"); + dst.x = a.y * b.z - a.z * b.y; + dst.y = a.z * b.x - a.x * b.z; + dst.z = a.x * b.y - a.y * b.x; } pragma(inline) void @@ -1379,11 +1483,9 @@ MatZero(Mat4* mat) pragma(inline) void Translate(Mat4* mat, Vec3 vec) { - static if(NativeTarget) - { - glm_translate(mat.glm_mat.ptr, vec.v.ptr); - } - else assert(false, "Not implemented for platform"); + Vec4MulAddScale(&mat.vec[0], vec.x, &mat.vec[3]); + Vec4MulAddScale(&mat.vec[1], vec.y, &mat.vec[3]); + Vec4MulAddScale(&mat.vec[2], vec.z, &mat.vec[3]); } pragma(inline) Mat4 @@ -1392,11 +1494,8 @@ Inverse(Mat4 mat) Mat4 res; MatZero(&res); - static if(NativeTarget) - { - glm_mat4_inv(mat.glm_mat.ptr, res.glm_mat.ptr); - } - else assert(false, "Not implemented for platform"); + // TODO: optimize + Mat4Inv(&mat, &res); return res; } diff --git a/package.d b/package.d index 0c15127..6b42911 100644 --- a/package.d +++ b/package.d @@ -1,7 +1,5 @@ module dlib; -public import dlibincludes; - public import dlib.alloc; public import dlib.util; public import dlib.math; @@ -9,11 +7,26 @@ public import dlib.platform; public import dlib.aliases; public import dlib.fonts; public import dlib.assets; +public import dlib.externdecl; -version(DLIB_TEST) +version(WebAssembly) { - version(WebAssembly) + +} +else +{ + public import dlibincludes; +} + +shared static this() +{ + static if(NativeTarget) { - void _start() { main() } + FT_Init_FreeType(&FT_LIB); + } + else + { + ta_init(256, 16, (void*).sizeof*2); } } + diff --git a/platform.d b/platform.d index e314c37..63297de 100644 --- a/platform.d +++ b/platform.d @@ -2017,7 +2017,7 @@ OSTimeFreq() version (linux) { - u64 freq = 1000000; + freq = 1000000; } else static assert(false, NO_IMPL); diff --git a/test.sh b/test.sh index f0bc1fc..7b6e69f 100755 --- a/test.sh +++ b/test.sh @@ -2,16 +2,25 @@ name="Test_Runner" -flags="-P-I/usr/include/freetype2 -L-lfreetype" +shared_src="package.d platform.d fonts.d aliases.d math.d util.d alloc.d assets.d external.d" + if [ "$1" == "wasm" ]; then - flags="-mtriple=wasm32-unknown-unknown-wasm --Xcc=-DBUILD_WASM -Iexternal/arsd-webassembly" + flags="-c -mtriple=wasm32-unknown-unknown-wasm --Xcc=-DBUILD_WASM -Iexternal/arsd-webassembly -L--no-entry -L--allow-undefined -i=core -i=std -i=. --of=build/dlibmain.wasm --d-version=inline_concat -verrors=90" + + /bin/bash ./build.sh build wasm + + ldc2 $flags $shared_src external/arsd-webassembly/object.d external/arsd-webassembly/core/stdc/string.d + + wasm-ld "build/dlibmain.wasm build/dlibincludes.wasm -obuild/dlib.wasm" +else + flags="-P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name" + + /bin/bash ./build.sh build + + ldc2 $flags $shared_src build/libxxhash.a -d-version=DLIB_TEST -verrors=50 + + rm $name.o + ./$name + rm $name fi -/bin/bash ./build.sh build - -ldc2 platform.d fonts.d aliases.d math.d util.d alloc.d assets.d build/libxxhash.a build/libcglm.a build/libprintf.a $flags -d-version=DLIB_TEST --main --unittest -g --of=$name -verrors=50 - -rm $name.o -./$name -#rm $name - diff --git a/tinyalloc.o b/tinyalloc.o new file mode 100644 index 0000000000000000000000000000000000000000..654325cd64232a135dc2aba3f3868d6fc4ee133a GIT binary patch literal 4761 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 literal 0 HcmV?d00001 diff --git a/util.d b/util.d index 40a5acb..ff9c595 100644 --- a/util.d +++ b/util.d @@ -3,7 +3,8 @@ module dlib.util; import dlib.aliases; import dlib.alloc; -import dlibincludes; + +import core.stdc.string; //import std.traits; @@ -11,10 +12,13 @@ static if(NativeTarget) { import std.format : sformat; import std.stdio : write, writeln, writef, writefln, stderr; + import dlib.platform; + import dlibincludes; } else { - + extern extern(C) u64 + XXH3_64bits_withSeed(const void* input, usize length, u64 seed); } enum bool StringType(T) = (is(T: string) || is(T: u8[]) || is(T: char[]) || is(T: const(char)[])); @@ -133,9 +137,13 @@ Debugf(Args...)(string fmt, Args args) string Scratchf(Args...)(string fmt, Args args) { - assert(g_scratch.init); - char[] buf = ScratchAlloc!(char)(fmt.length < 16 ? 32 : 128); - return Str(sformat(buf, fmt, args)); + static if(NativeTarget) + { + assert(g_scratch.init); + char[] buf = ScratchAlloc!(char)(fmt.length < 16 ? 32 : 128); + return Str(sformat(buf, fmt, args)); + } + else static assert(false, NO_IMPL); } void @@ -150,20 +158,20 @@ Log(char* str) static if(NativeTarget) writeln(str); } -@nogc u64 -KB(u64 v) +@nogc usize +KB(usize v) { return v * 1024; }; -@nogc u64 -MB(u64 v) +@nogc usize +MB(usize v) { return KB(v) * 1024; }; -@nogc u64 -GB(u64 v) +@nogc usize +GB(usize v) { return MB(v) * 1024; }; @@ -267,7 +275,7 @@ ConcatInPlace(T)(T* list, T* to_concat) list.last = to_concat.last; } - MemSet(to_concat, 0, T.sizeof); + memset(to_concat, 0, T.sizeof); } } @@ -508,7 +516,7 @@ struct HashTable(K, V) } HashTable!(K, V) -CreateHashTable(K, V)(u64 size) +CreateHashTable(K, V)(usize size) { Arena arena = CreateArena(MB(4)); auto nil = Alloc!(KVPair!(K, V))(&arena); @@ -635,7 +643,7 @@ Delete(K, V)(HashTable!(K, V)* ht, K key) result.ok = true; result.value = node.value; - MemSet(&node.value, 0, node.value.sizeof); + memset(&node.value, 0, node.value.sizeof); SLLPush(&ht.free_lists, node, ht.nil); @@ -653,19 +661,19 @@ const u64 HASH_SEED = 5995; pragma(inline) u64 Hash(T)(T[] value) { - return XXH3_64bits_withSeed(value.ptr, (T.sizeof * value.length) / u8.sizeof, HASH_SEED); + return XXHash64(value.ptr, (T.sizeof * value.length) / u8.sizeof, HASH_SEED); } pragma(inline) u64 Hash(T)(T* value) { - return XXH3_64bits_withSeed(value, T.sizeof / u8.sizeof, HASH_SEED); + return XXHash64(value, T.sizeof / u8.sizeof, HASH_SEED); } pragma(inline) u64 Hash(string str) { - return XXH3_64bits_withSeed(str.ptr, str.length, HASH_SEED); + return XXHash64(str.ptr, str.length, HASH_SEED); } // TODO: probably needs improvement/testing @@ -928,6 +936,180 @@ Assign(T, Args...)(T slice, Args args) if(isArray!(T)) } } +const u64 PRIME_1 = 11400714785074694791UL; +const u64 PRIME_2 = 14029467366897019727UL; +const u64 PRIME_3 = 1609587929392839161UL; +const u64 PRIME_4 = 9650029242287828579UL; +const u64 PRIME_5 = 2870177450012600261UL; + +const u64 HASH_MAX_BUFFER_SIZE = 31+1; + +struct XXHash +{ + u64[4] state; + u8[HASH_MAX_BUFFER_SIZE] buffer; + usize buffer_size; + usize total_length; +} + +static XXHash XXHASH; + +u64 +XXHash64(const(void)* input, u64 length, u64 seed) +{ + InitHash(seed); + HashAdd(input, length); + return GetHash(); +} + +void +InitHash(u64 seed) +{ + ref XXHash xxh = XXHASH; + + xxh.state[0] = seed + PRIME_1 + PRIME_2; + xxh.state[1] = seed + PRIME_2; + xxh.state[2] = seed; + xxh.state[3] = seed - PRIME_1; + + xxh.buffer_size = 0; + xxh.total_length = 0; +} + +bool +HashAdd(const(void)* input, u64 length) +{ + if(!input || length == 0) return false; + + ref XXHash xxh = XXHASH; + + xxh.total_length += length; + + const(u8)* data = cast(const(u8)*)input; + + if(xxh.buffer_size+length < HASH_MAX_BUFFER_SIZE) + { + for(;length--;) + { + xxh.buffer[xxh.buffer_size++] = *(data++); + } + + return true; + } + + const(u8)* stop = data+length; + const(u8)* stop_block = stop - HASH_MAX_BUFFER_SIZE; + + if(xxh.buffer_size > 0) + { + for(; xxh.buffer_size < HASH_MAX_BUFFER_SIZE;) + { + xxh.buffer[xxh.buffer_size++] = *data++; + } + + ProcessHash(xxh.buffer.ptr, xxh.state[0], xxh.state[1], xxh.state[2], xxh.state[3]); + } + + u64 s0 = xxh.state[0]; + u64 s1 = xxh.state[1]; + u64 s2 = xxh.state[2]; + u64 s3 = xxh.state[3]; + + while(data <= stop_block) + { + ProcessHash(data, s0, s1, s2, s3); + data += 32; + } + + xxh.state[0] = s0; + xxh.state[1] = s1; + xxh.state[2] = s2; + xxh.state[3] = s3; + + xxh.buffer_size = stop - data; + for(u32 i = 0; i < xxh.buffer_size; i += 1) + { + xxh.buffer[i] = data[i]; + } + + return true; +} + +u64 +GetHash() +{ + ref XXHash xxh = XXHASH; + + u64 result; + if(xxh.total_length >= HASH_MAX_BUFFER_SIZE) + { + result = RotateLeft(xxh.state[0], 1) + + RotateLeft(xxh.state[1], 7) + + RotateLeft(xxh.state[2], 12) + + RotateLeft(xxh.state[3], 18); + + result = (result ^ ProcessSingleHashValue(0, xxh.state[0])) * PRIME_1 + PRIME_4; + result = (result ^ ProcessSingleHashValue(0, xxh.state[1])) * PRIME_1 + PRIME_4; + result = (result ^ ProcessSingleHashValue(0, xxh.state[2])) * PRIME_1 + PRIME_4; + result = (result ^ ProcessSingleHashValue(0, xxh.state[3])) * PRIME_1 + PRIME_4; + } + else + { + result = xxh.state[2] + PRIME_5; + } + + result += xxh.total_length; + + const(u8)* data = xxh.buffer.ptr; + const(u8)* stop = data + xxh.buffer_size; + + for(; data + 8 <= stop; data += 8) + { + result = RotateLeft(result ^ ProcessSingleHashValue(0, *cast(u64*)data), 27) * PRIME_1 + PRIME_4; + } + + if(data+4 <= stop) + { + result = RotateLeft(result ^ (*cast(u32*)data) * PRIME_1, 23) * PRIME_2 + PRIME_3; + data += 4; + } + + while(data != stop) + { + result = RotateLeft(result ^ (*data++) * PRIME_5, 11) * PRIME_1; + } + + result ^= result >> 33; + result *= PRIME_2; + result ^= result >> 29; + result *= PRIME_3; + result ^= result >> 32; + + return result; +} + +pragma(inline) u64 +RotateLeft(u64 x, u8 bits) +{ + return (x << bits) | (x >> (64 - bits)); +} + +pragma(inline) u64 +ProcessSingleHashValue(u64 previous, u64 input) +{ + return RotateLeft(previous + input*PRIME_2, 31) * PRIME_1; +} + +pragma(inline) void +ProcessHash(const(void)* data, ref u64 state_0, ref u64 state_1, ref u64 state_2, ref u64 state_3) +{ + u64* block = cast(u64*)data; + state_0 = ProcessSingleHashValue(state_0, block[0]); + state_1 = ProcessSingleHashValue(state_1, block[1]); + state_2 = ProcessSingleHashValue(state_2, block[2]); + state_3 = ProcessSingleHashValue(state_3, block[3]); +} + version(DLIB_TEST) unittest { { // Singly Linked List @@ -1162,6 +1344,7 @@ version(DLIB_TEST) unittest arr = CastArr!(u8)(char_arr); } + static if(NativeTarget) { ResetScratch(MB(4)); string str = Scratchf("%s testing %s", 55, "testing"); @@ -1173,7 +1356,7 @@ version(DLIB_TEST) unittest MemSet(slice.ptr, 0, u64.sizeof*slice.length); - for(u64 i = 0; i < slice.length; i += 1) + for(usize i = 0; i < slice.length; i += 1) { assert(slice[i] == 0); } @@ -1191,7 +1374,7 @@ version(DLIB_TEST) unittest cast(u64)(5) << 0 ); - for(u64 i = 0; i < slice.length; i += 1) + for(usize i = 0; i < slice.length; i += 1) { assert(slice[i] == cmp); } diff --git a/wasm.d b/wasm.d new file mode 100644 index 0000000..e69de29