@vib3code/sdk 2.0.1 → 2.0.3-canary.0a63e71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +245 -0
- package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
- package/DOCS/ARCHITECTURE.md +1 -0
- package/DOCS/CI_TESTING.md +2 -0
- package/DOCS/CLI_ONBOARDING.md +3 -1
- package/DOCS/CONTROL_REFERENCE.md +2 -0
- package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +119 -0
- package/DOCS/ENV_SETUP.md +2 -0
- package/DOCS/EPIC_SCROLL_EVENTS.md +775 -0
- package/DOCS/EXPANSION_DESIGN.md +979 -0
- package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
- package/DOCS/EXPORT_FORMATS.md +2 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
- package/DOCS/HANDOFF_LANDING_PAGE.md +156 -0
- package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +495 -0
- package/DOCS/LICENSING_TIERS.md +2 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +4 -2
- package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +939 -0
- package/DOCS/OBS_SETUP_GUIDE.md +2 -0
- package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
- package/DOCS/PRODUCT_STRATEGY.md +65 -0
- package/DOCS/PROJECT_SETUP.md +2 -0
- package/DOCS/README.md +105 -0
- package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +99 -0
- package/DOCS/RENDERER_LIFECYCLE.md +2 -0
- package/DOCS/REPO_MANIFEST.md +2 -0
- package/DOCS/ROADMAP.md +113 -0
- package/DOCS/SCROLL_TIMELINE_v3.md +271 -0
- package/DOCS/SITE_REFACTOR_PLAN.md +102 -0
- package/DOCS/STATUS.md +26 -0
- package/DOCS/SYSTEM_INVENTORY.md +37 -32
- package/DOCS/TELEMETRY_EXPORTS.md +2 -0
- package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +87 -0
- package/DOCS/VISUAL_ANALYSIS_FACETAD.md +135 -0
- package/DOCS/VISUAL_ANALYSIS_SIMONE.md +97 -0
- package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +88 -0
- package/DOCS/WEBGPU_STATUS.md +121 -38
- package/DOCS/XR_BENCHMARKS.md +2 -0
- package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -0
- package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -0
- package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -0
- package/DOCS/archive/SESSION_014_PLAN.md +1 -0
- package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -0
- package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -0
- package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -0
- package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -0
- package/DOCS/{DEV_TRACK_SESSION_2026-01-31.md → dev-tracks/DEV_TRACK_SESSION_2026-01-31.md} +3 -1
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +233 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +129 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +144 -0
- package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +110 -0
- package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
- package/DOCS/dev-tracks/README.md +12 -0
- package/README.md +26 -13
- package/cpp/CMakeLists.txt +236 -0
- package/cpp/bindings/embind.cpp +269 -0
- package/cpp/build.sh +129 -0
- package/cpp/geometry/Crystal.cpp +103 -0
- package/cpp/geometry/Fractal.cpp +136 -0
- package/cpp/geometry/GeometryGenerator.cpp +262 -0
- package/cpp/geometry/KleinBottle.cpp +71 -0
- package/cpp/geometry/Sphere.cpp +134 -0
- package/cpp/geometry/Tesseract.cpp +94 -0
- package/cpp/geometry/Tetrahedron.cpp +83 -0
- package/cpp/geometry/Torus.cpp +65 -0
- package/cpp/geometry/WarpFunctions.cpp +238 -0
- package/cpp/geometry/Wave.cpp +85 -0
- package/cpp/include/vib3_ffi.h +238 -0
- package/cpp/math/Mat4x4.cpp +409 -0
- package/cpp/math/Mat4x4.hpp +209 -0
- package/cpp/math/Projection.cpp +142 -0
- package/cpp/math/Projection.hpp +148 -0
- package/cpp/math/Rotor4D.cpp +322 -0
- package/cpp/math/Rotor4D.hpp +204 -0
- package/cpp/math/Vec4.cpp +303 -0
- package/cpp/math/Vec4.hpp +225 -0
- package/cpp/src/vib3_ffi.cpp +607 -0
- package/cpp/tests/Geometry_test.cpp +213 -0
- package/cpp/tests/Mat4x4_test.cpp +494 -0
- package/cpp/tests/Projection_test.cpp +298 -0
- package/cpp/tests/Rotor4D_test.cpp +423 -0
- package/cpp/tests/Vec4_test.cpp +489 -0
- package/docs/webgpu-live.html +1 -1
- package/package.json +41 -30
- package/src/agent/index.js +1 -3
- package/src/agent/mcp/MCPServer.js +1220 -144
- package/src/agent/mcp/index.js +1 -1
- package/src/agent/mcp/stdio-server.js +264 -0
- package/src/agent/mcp/tools.js +498 -31
- package/src/cli/index.js +431 -47
- package/src/core/CanvasManager.js +97 -204
- package/src/core/ErrorReporter.js +1 -1
- package/src/core/Parameters.js +1 -1
- package/src/core/VIB3Engine.js +93 -4
- package/src/core/VitalitySystem.js +53 -0
- package/src/core/index.js +18 -0
- package/src/core/renderers/FacetedRendererAdapter.js +10 -9
- package/src/core/renderers/HolographicRendererAdapter.js +13 -9
- package/src/core/renderers/QuantumRendererAdapter.js +11 -7
- package/src/creative/AestheticMapper.js +628 -0
- package/src/creative/ChoreographyPlayer.js +481 -0
- package/src/creative/index.js +11 -0
- package/src/experimental/GameLoop.js +72 -0
- package/src/experimental/LatticePhysics.js +100 -0
- package/src/experimental/LiveDirector.js +143 -0
- package/src/experimental/PlayerController4D.js +154 -0
- package/src/experimental/VIB3Actor.js +138 -0
- package/src/experimental/VIB3Compositor.js +117 -0
- package/src/experimental/VIB3Link.js +122 -0
- package/src/experimental/VIB3Orchestrator.js +146 -0
- package/src/experimental/VIB3Universe.js +109 -0
- package/src/experimental/demos/CrystalLabyrinth.js +202 -0
- package/src/export/TradingCardManager.js +3 -4
- package/src/export/index.js +11 -1
- package/src/faceted/FacetedSystem.js +260 -394
- package/src/games/glyph-war/GlyphWarVisualizer.js +641 -0
- package/src/geometry/generators/Crystal.js +2 -2
- package/src/geometry/warp/HypersphereCore.js +53 -24
- package/src/holograms/HolographicVisualizer.js +84 -98
- package/src/holograms/RealHolographicSystem.js +194 -43
- package/src/math/Mat4x4.js +308 -105
- package/src/math/Rotor4D.js +124 -40
- package/src/math/Vec4.js +200 -103
- package/src/math/index.js +7 -7
- package/src/polychora/PolychoraSystem.js +77 -0
- package/src/quantum/QuantumEngine.js +103 -66
- package/src/quantum/QuantumVisualizer.js +31 -22
- package/src/reactivity/index.js +3 -5
- package/src/render/LayerPresetManager.js +372 -0
- package/src/render/LayerReactivityBridge.js +344 -0
- package/src/render/LayerRelationshipGraph.js +610 -0
- package/src/render/MultiCanvasBridge.js +148 -25
- package/src/render/ShaderLoader.js +38 -0
- package/src/render/ShaderProgram.js +4 -4
- package/src/render/UnifiedRenderBridge.js +4 -1
- package/src/render/backends/WebGPUBackend.js +8 -4
- package/src/render/index.js +27 -2
- package/src/scene/Node4D.js +74 -24
- package/src/scene/index.js +4 -4
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +4 -4
- package/src/shaders/common/rotation4d.wgsl +2 -2
- package/src/shaders/common/uniforms.wgsl +15 -8
- package/src/shaders/faceted/faceted.frag.glsl +220 -80
- package/src/shaders/faceted/faceted.frag.wgsl +144 -90
- package/src/shaders/holographic/holographic.frag.glsl +28 -9
- package/src/shaders/holographic/holographic.frag.wgsl +112 -41
- package/src/shaders/quantum/quantum.frag.glsl +1 -0
- package/src/shaders/quantum/quantum.frag.wgsl +6 -4
- package/src/testing/ParallelTestFramework.js +2 -2
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +2 -2
- package/src/viewer/GalleryUI.js +17 -0
- package/src/viewer/ViewerPortal.js +2 -2
- package/src/viewer/index.js +1 -1
- package/tools/headless-renderer.js +258 -0
- package/tools/shader-sync-verify.js +14 -8
- package/tools/site-analysis/all-reports.json +32 -0
- package/tools/site-analysis/combined-analysis.md +50 -0
- package/tools/site-analyzer.mjs +779 -0
- package/tools/visual-catalog/capture.js +276 -0
- package/tools/visual-catalog/composite.js +138 -0
- package/types/adaptive-sdk.d.ts +204 -5
- package/types/agent/cli.d.ts +78 -0
- package/types/agent/index.d.ts +18 -0
- package/types/agent/mcp.d.ts +87 -0
- package/types/agent/telemetry.d.ts +190 -0
- package/types/core/VIB3Engine.d.ts +26 -0
- package/types/core/index.d.ts +261 -0
- package/types/creative/AestheticMapper.d.ts +72 -0
- package/types/creative/ChoreographyPlayer.d.ts +96 -0
- package/types/creative/index.d.ts +17 -0
- package/types/export/index.d.ts +243 -0
- package/types/geometry/index.d.ts +164 -0
- package/types/math/index.d.ts +214 -0
- package/types/render/LayerPresetManager.d.ts +78 -0
- package/types/render/LayerReactivityBridge.d.ts +85 -0
- package/types/render/LayerRelationshipGraph.d.ts +174 -0
- package/types/render/index.d.ts +3 -0
- package/types/scene/index.d.ts +204 -0
- package/types/systems/index.d.ts +244 -0
- package/types/variations/index.d.ts +62 -0
- package/types/viewer/index.d.ts +225 -0
- package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +0 -34
- package/DOCS/DEV_TRACK_ANALYSIS.md +0 -77
- package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +0 -42
- package/DOCS/SESSION_014_PLAN.md +0 -195
- package/DOCS/SESSION_LOG_2026-01-07.md +0 -56
- package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +0 -72
- package/DOCS/SYSTEM_AUDIT_2026-01-30.md +0 -738
- /package/src/viewer/{ReactivityManager.js → ViewerInputHandler.js} +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* embind.cpp - Emscripten JavaScript Bindings
|
|
3
|
+
*
|
|
4
|
+
* Exposes VIB3+ C++ classes to JavaScript via WebAssembly.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include <emscripten/bind.h>
|
|
8
|
+
#include "../math/Vec4.hpp"
|
|
9
|
+
#include "../math/Rotor4D.hpp"
|
|
10
|
+
#include "../math/Mat4x4.hpp"
|
|
11
|
+
#include "../math/Projection.hpp"
|
|
12
|
+
|
|
13
|
+
using namespace emscripten;
|
|
14
|
+
using namespace vib3;
|
|
15
|
+
|
|
16
|
+
// Helper to convert std::array to JS array
|
|
17
|
+
template<typename T, size_t N>
|
|
18
|
+
val arrayToVal(const std::array<T, N>& arr) {
|
|
19
|
+
val jsArray = val::array();
|
|
20
|
+
for (size_t i = 0; i < N; ++i) {
|
|
21
|
+
jsArray.call<void>("push", arr[i]);
|
|
22
|
+
}
|
|
23
|
+
return jsArray;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Helper to convert JS array to std::array
|
|
27
|
+
template<typename T, size_t N>
|
|
28
|
+
std::array<T, N> valToArray(const val& jsArray) {
|
|
29
|
+
std::array<T, N> arr;
|
|
30
|
+
for (size_t i = 0; i < N; ++i) {
|
|
31
|
+
arr[i] = jsArray[i].as<T>();
|
|
32
|
+
}
|
|
33
|
+
return arr;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
EMSCRIPTEN_BINDINGS(vib3_math) {
|
|
37
|
+
// ====== Vec4 ======
|
|
38
|
+
|
|
39
|
+
class_<Vec4>("Vec4")
|
|
40
|
+
.constructor<>()
|
|
41
|
+
.constructor<float, float, float, float>()
|
|
42
|
+
.constructor<float>()
|
|
43
|
+
|
|
44
|
+
// Properties
|
|
45
|
+
.property("x", &Vec4::x)
|
|
46
|
+
.property("y", &Vec4::y)
|
|
47
|
+
.property("z", &Vec4::z)
|
|
48
|
+
.property("w", &Vec4::w)
|
|
49
|
+
|
|
50
|
+
// Static factories
|
|
51
|
+
.class_function("zero", &Vec4::zero)
|
|
52
|
+
.class_function("one", &Vec4::one)
|
|
53
|
+
.class_function("unitX", &Vec4::unitX)
|
|
54
|
+
.class_function("unitY", &Vec4::unitY)
|
|
55
|
+
.class_function("unitZ", &Vec4::unitZ)
|
|
56
|
+
.class_function("unitW", &Vec4::unitW)
|
|
57
|
+
.class_function("randomUnit", &Vec4::randomUnit)
|
|
58
|
+
|
|
59
|
+
// Arithmetic
|
|
60
|
+
.function("add", select_overload<Vec4(const Vec4&) const>(&Vec4::operator+))
|
|
61
|
+
.function("sub", select_overload<Vec4(const Vec4&) const>(&Vec4::operator-))
|
|
62
|
+
.function("mul", select_overload<Vec4(float) const>(&Vec4::operator*))
|
|
63
|
+
.function("div", select_overload<Vec4(float) const>(&Vec4::operator/))
|
|
64
|
+
.function("neg", select_overload<Vec4() const>(&Vec4::operator-))
|
|
65
|
+
|
|
66
|
+
// Operations
|
|
67
|
+
.function("dot", &Vec4::dot)
|
|
68
|
+
.function("length", &Vec4::length)
|
|
69
|
+
.function("lengthSquared", &Vec4::lengthSquared)
|
|
70
|
+
.function("normalized", &Vec4::normalized)
|
|
71
|
+
.function("normalize", &Vec4::normalize)
|
|
72
|
+
.function("distanceTo", &Vec4::distanceTo)
|
|
73
|
+
.function("distanceSquaredTo", &Vec4::distanceSquaredTo)
|
|
74
|
+
.function("lerp", &Vec4::lerp)
|
|
75
|
+
.function("min", &Vec4::min)
|
|
76
|
+
.function("max", &Vec4::max)
|
|
77
|
+
.function("clamp", &Vec4::clamp)
|
|
78
|
+
.function("abs", &Vec4::abs)
|
|
79
|
+
.function("projectOnto", &Vec4::projectOnto)
|
|
80
|
+
.function("reflect", &Vec4::reflect)
|
|
81
|
+
.function("isZero", &Vec4::isZero)
|
|
82
|
+
.function("isNormalized", &Vec4::isNormalized)
|
|
83
|
+
|
|
84
|
+
// Projections
|
|
85
|
+
.function("projectPerspective", &Vec4::projectPerspective)
|
|
86
|
+
.function("projectStereographic", &Vec4::projectStereographic)
|
|
87
|
+
.function("projectOrthographic", &Vec4::projectOrthographic)
|
|
88
|
+
|
|
89
|
+
// Conversion
|
|
90
|
+
.function("toArray", optional_override([](const Vec4& self) {
|
|
91
|
+
return arrayToVal<float, 4>(self.data);
|
|
92
|
+
}))
|
|
93
|
+
;
|
|
94
|
+
|
|
95
|
+
// Free function for Vec4 construction from array
|
|
96
|
+
function("vec4FromArray", optional_override([](const val& arr) {
|
|
97
|
+
return Vec4(arr[0].as<float>(), arr[1].as<float>(),
|
|
98
|
+
arr[2].as<float>(), arr[3].as<float>());
|
|
99
|
+
}));
|
|
100
|
+
|
|
101
|
+
// ====== Rotor4D ======
|
|
102
|
+
|
|
103
|
+
enum_<RotationPlane>("RotationPlane")
|
|
104
|
+
.value("XY", RotationPlane::XY)
|
|
105
|
+
.value("XZ", RotationPlane::XZ)
|
|
106
|
+
.value("YZ", RotationPlane::YZ)
|
|
107
|
+
.value("XW", RotationPlane::XW)
|
|
108
|
+
.value("YW", RotationPlane::YW)
|
|
109
|
+
.value("ZW", RotationPlane::ZW)
|
|
110
|
+
;
|
|
111
|
+
|
|
112
|
+
class_<Rotor4D>("Rotor4D")
|
|
113
|
+
.constructor<>()
|
|
114
|
+
.constructor<float, float, float, float, float, float, float, float>()
|
|
115
|
+
|
|
116
|
+
// Components
|
|
117
|
+
.property("s", &Rotor4D::s)
|
|
118
|
+
.property("xy", &Rotor4D::xy)
|
|
119
|
+
.property("xz", &Rotor4D::xz)
|
|
120
|
+
.property("yz", &Rotor4D::yz)
|
|
121
|
+
.property("xw", &Rotor4D::xw)
|
|
122
|
+
.property("yw", &Rotor4D::yw)
|
|
123
|
+
.property("zw", &Rotor4D::zw)
|
|
124
|
+
.property("xyzw", &Rotor4D::xyzw)
|
|
125
|
+
|
|
126
|
+
// Static factories
|
|
127
|
+
.class_function("identity", &Rotor4D::identity)
|
|
128
|
+
.class_function("fromPlaneAngle", &Rotor4D::fromPlaneAngle)
|
|
129
|
+
.class_function("fromEuler6", select_overload<Rotor4D(float, float, float, float, float, float)>(&Rotor4D::fromEuler6))
|
|
130
|
+
|
|
131
|
+
// Operations
|
|
132
|
+
.function("mul", select_overload<Rotor4D(const Rotor4D&) const>(&Rotor4D::operator*))
|
|
133
|
+
.function("reverse", &Rotor4D::reverse)
|
|
134
|
+
.function("magnitude", &Rotor4D::magnitude)
|
|
135
|
+
.function("magnitudeSquared", &Rotor4D::magnitudeSquared)
|
|
136
|
+
.function("normalized", &Rotor4D::normalized)
|
|
137
|
+
.function("normalize", &Rotor4D::normalize)
|
|
138
|
+
.function("inverse", &Rotor4D::inverse)
|
|
139
|
+
.function("isNormalized", &Rotor4D::isNormalized)
|
|
140
|
+
|
|
141
|
+
// Vector rotation
|
|
142
|
+
.function("rotate", &Rotor4D::rotate)
|
|
143
|
+
|
|
144
|
+
// Interpolation
|
|
145
|
+
.function("slerp", &Rotor4D::slerp)
|
|
146
|
+
.function("nlerp", &Rotor4D::nlerp)
|
|
147
|
+
.function("dot", &Rotor4D::dot)
|
|
148
|
+
|
|
149
|
+
// Matrix conversion
|
|
150
|
+
.function("toMatrix", &Rotor4D::toMatrix)
|
|
151
|
+
|
|
152
|
+
// Conversion
|
|
153
|
+
.function("toArray", optional_override([](const Rotor4D& self) {
|
|
154
|
+
return arrayToVal<float, 8>(self.toArray());
|
|
155
|
+
}))
|
|
156
|
+
;
|
|
157
|
+
|
|
158
|
+
// Free function for rotor creation from angle array
|
|
159
|
+
function("rotorFromEuler6Array", optional_override([](const val& arr) {
|
|
160
|
+
return Rotor4D::fromEuler6(
|
|
161
|
+
arr[0].as<float>(), arr[1].as<float>(), arr[2].as<float>(),
|
|
162
|
+
arr[3].as<float>(), arr[4].as<float>(), arr[5].as<float>()
|
|
163
|
+
);
|
|
164
|
+
}));
|
|
165
|
+
|
|
166
|
+
// ====== Mat4x4 ======
|
|
167
|
+
|
|
168
|
+
class_<Mat4x4>("Mat4x4")
|
|
169
|
+
.constructor<>()
|
|
170
|
+
.constructor<float>()
|
|
171
|
+
|
|
172
|
+
// Static factories
|
|
173
|
+
.class_function("identity", &Mat4x4::identity)
|
|
174
|
+
.class_function("zero", &Mat4x4::zero)
|
|
175
|
+
.class_function("rotationXY", &Mat4x4::rotationXY)
|
|
176
|
+
.class_function("rotationXZ", &Mat4x4::rotationXZ)
|
|
177
|
+
.class_function("rotationYZ", &Mat4x4::rotationYZ)
|
|
178
|
+
.class_function("rotationXW", &Mat4x4::rotationXW)
|
|
179
|
+
.class_function("rotationYW", &Mat4x4::rotationYW)
|
|
180
|
+
.class_function("rotationZW", &Mat4x4::rotationZW)
|
|
181
|
+
.class_function("rotationFromAngles", select_overload<Mat4x4(float, float, float, float, float, float)>(&Mat4x4::rotationFromAngles))
|
|
182
|
+
.class_function("scale", select_overload<Mat4x4(float)>(&Mat4x4::scale))
|
|
183
|
+
|
|
184
|
+
// Element access
|
|
185
|
+
.function("at", select_overload<float&(size_t, size_t)>(&Mat4x4::at))
|
|
186
|
+
.function("column", &Mat4x4::column)
|
|
187
|
+
.function("row", &Mat4x4::row)
|
|
188
|
+
|
|
189
|
+
// Operations
|
|
190
|
+
.function("mulMat", select_overload<Mat4x4(const Mat4x4&) const>(&Mat4x4::operator*))
|
|
191
|
+
.function("mulVec", select_overload<Vec4(const Vec4&) const>(&Mat4x4::operator*))
|
|
192
|
+
.function("mulScalar", select_overload<Mat4x4(float) const>(&Mat4x4::operator*))
|
|
193
|
+
.function("add", select_overload<Mat4x4(const Mat4x4&) const>(&Mat4x4::operator+))
|
|
194
|
+
.function("sub", select_overload<Mat4x4(const Mat4x4&) const>(&Mat4x4::operator-))
|
|
195
|
+
.function("transposed", &Mat4x4::transposed)
|
|
196
|
+
.function("transpose", &Mat4x4::transpose)
|
|
197
|
+
.function("determinant", &Mat4x4::determinant)
|
|
198
|
+
.function("inverse", &Mat4x4::inverse)
|
|
199
|
+
.function("isOrthogonal", &Mat4x4::isOrthogonal)
|
|
200
|
+
.function("isIdentity", &Mat4x4::isIdentity)
|
|
201
|
+
|
|
202
|
+
// Conversion
|
|
203
|
+
.function("toArray", optional_override([](const Mat4x4& self) {
|
|
204
|
+
return arrayToVal<float, 16>(self.data);
|
|
205
|
+
}))
|
|
206
|
+
;
|
|
207
|
+
|
|
208
|
+
// Free function for matrix from angles array
|
|
209
|
+
function("matrixFromAnglesArray", optional_override([](const val& arr) {
|
|
210
|
+
return Mat4x4::rotationFromAngles(
|
|
211
|
+
arr[0].as<float>(), arr[1].as<float>(), arr[2].as<float>(),
|
|
212
|
+
arr[3].as<float>(), arr[4].as<float>(), arr[5].as<float>()
|
|
213
|
+
);
|
|
214
|
+
}));
|
|
215
|
+
|
|
216
|
+
// ====== Projection ======
|
|
217
|
+
|
|
218
|
+
value_object<Projection3D>("Projection3D")
|
|
219
|
+
.field("x", &Projection3D::x)
|
|
220
|
+
.field("y", &Projection3D::y)
|
|
221
|
+
.field("z", &Projection3D::z)
|
|
222
|
+
;
|
|
223
|
+
|
|
224
|
+
value_object<SliceResult>("SliceResult")
|
|
225
|
+
.field("point", &SliceResult::point)
|
|
226
|
+
.field("alpha", &SliceResult::alpha)
|
|
227
|
+
.field("valid", &SliceResult::valid)
|
|
228
|
+
;
|
|
229
|
+
|
|
230
|
+
// Projection functions
|
|
231
|
+
function("projectPerspective", &projectPerspective);
|
|
232
|
+
function("projectStereographic", &projectStereographic);
|
|
233
|
+
function("projectOrthographic", &projectOrthographic);
|
|
234
|
+
function("projectOblique", &projectOblique);
|
|
235
|
+
function("projectSlice", &projectSlice);
|
|
236
|
+
|
|
237
|
+
// Batch projections (returns typed array for efficiency)
|
|
238
|
+
function("projectToFloatArray", optional_override([](const val& jsPoints, float distance) {
|
|
239
|
+
std::vector<Vec4> points;
|
|
240
|
+
size_t len = jsPoints["length"].as<size_t>();
|
|
241
|
+
points.reserve(len);
|
|
242
|
+
|
|
243
|
+
for (size_t i = 0; i < len; ++i) {
|
|
244
|
+
points.push_back(jsPoints[i].as<Vec4>());
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
auto result = projectToFloatArray(points, distance);
|
|
248
|
+
|
|
249
|
+
// Return as Float32Array for efficient GPU upload
|
|
250
|
+
return val::global("Float32Array").new_(typed_memory_view(result.size(), result.data()));
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Module initialization
|
|
255
|
+
EMSCRIPTEN_BINDINGS(vib3_module) {
|
|
256
|
+
// Version info
|
|
257
|
+
function("getVersion", optional_override([]() {
|
|
258
|
+
return std::string("1.0.0");
|
|
259
|
+
}));
|
|
260
|
+
|
|
261
|
+
// Feature detection
|
|
262
|
+
function("hasSimd", optional_override([]() {
|
|
263
|
+
#if defined(VIB3_HAS_SSE41) || defined(__wasm_simd128__)
|
|
264
|
+
return true;
|
|
265
|
+
#else
|
|
266
|
+
return false;
|
|
267
|
+
#endif
|
|
268
|
+
}));
|
|
269
|
+
}
|
package/cpp/build.sh
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# VIB3+ WASM Build Script
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ./build.sh # Build release WASM
|
|
7
|
+
# ./build.sh debug # Build debug WASM
|
|
8
|
+
# ./build.sh native # Build native (with tests)
|
|
9
|
+
# ./build.sh clean # Clean build directory
|
|
10
|
+
#
|
|
11
|
+
# Requirements:
|
|
12
|
+
# - CMake 3.20+
|
|
13
|
+
# - Emscripten SDK (for WASM builds)
|
|
14
|
+
# - C++20 compiler (for native builds)
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
20
|
+
BUILD_DIR="${SCRIPT_DIR}/build"
|
|
21
|
+
DIST_DIR="${SCRIPT_DIR}/../dist/wasm"
|
|
22
|
+
BUILD_TYPE="${1:-release}"
|
|
23
|
+
NPROC=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
|
24
|
+
|
|
25
|
+
# Colors for output
|
|
26
|
+
RED='\033[0;31m'
|
|
27
|
+
GREEN='\033[0;32m'
|
|
28
|
+
YELLOW='\033[1;33m'
|
|
29
|
+
NC='\033[0m' # No Color
|
|
30
|
+
|
|
31
|
+
log() { echo -e "${GREEN}[VIB3]${NC} $*"; }
|
|
32
|
+
warn() { echo -e "${YELLOW}[VIB3]${NC} $*"; }
|
|
33
|
+
error() { echo -e "${RED}[VIB3]${NC} $*" >&2; }
|
|
34
|
+
|
|
35
|
+
case "${BUILD_TYPE}" in
|
|
36
|
+
clean)
|
|
37
|
+
log "Cleaning build directory..."
|
|
38
|
+
rm -rf "${BUILD_DIR}"
|
|
39
|
+
log "Done."
|
|
40
|
+
exit 0
|
|
41
|
+
;;
|
|
42
|
+
|
|
43
|
+
debug)
|
|
44
|
+
log "Building WASM (Debug)..."
|
|
45
|
+
|
|
46
|
+
if ! command -v emcmake &>/dev/null; then
|
|
47
|
+
error "Emscripten not found. Install emsdk and activate it:"
|
|
48
|
+
error " git clone https://github.com/emscripten-core/emsdk.git"
|
|
49
|
+
error " cd emsdk && ./emsdk install latest && ./emsdk activate latest"
|
|
50
|
+
error " source emsdk_env.sh"
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
mkdir -p "${BUILD_DIR}/wasm-debug"
|
|
55
|
+
cd "${BUILD_DIR}/wasm-debug"
|
|
56
|
+
|
|
57
|
+
emcmake cmake "${SCRIPT_DIR}" \
|
|
58
|
+
-DCMAKE_BUILD_TYPE=Debug \
|
|
59
|
+
-DVIB3_BUILD_WASM=ON \
|
|
60
|
+
-DVIB3_BUILD_TESTS=OFF \
|
|
61
|
+
-DVIB3_ENABLE_SIMD=ON
|
|
62
|
+
|
|
63
|
+
cmake --build . -j"${NPROC}"
|
|
64
|
+
|
|
65
|
+
# Copy outputs
|
|
66
|
+
mkdir -p "${DIST_DIR}"
|
|
67
|
+
cp -f bin/vib3.js bin/vib3.wasm "${DIST_DIR}/"
|
|
68
|
+
[ -f bin/vib3.d.ts ] && cp -f bin/vib3.d.ts "${DIST_DIR}/"
|
|
69
|
+
|
|
70
|
+
log "Debug WASM build complete. Output: ${DIST_DIR}/"
|
|
71
|
+
;;
|
|
72
|
+
|
|
73
|
+
release)
|
|
74
|
+
log "Building WASM (Release)..."
|
|
75
|
+
|
|
76
|
+
if ! command -v emcmake &>/dev/null; then
|
|
77
|
+
error "Emscripten not found. Install emsdk and activate it:"
|
|
78
|
+
error " git clone https://github.com/emscripten-core/emsdk.git"
|
|
79
|
+
error " cd emsdk && ./emsdk install latest && ./emsdk activate latest"
|
|
80
|
+
error " source emsdk_env.sh"
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
mkdir -p "${BUILD_DIR}/wasm-release"
|
|
85
|
+
cd "${BUILD_DIR}/wasm-release"
|
|
86
|
+
|
|
87
|
+
emcmake cmake "${SCRIPT_DIR}" \
|
|
88
|
+
-DCMAKE_BUILD_TYPE=Release \
|
|
89
|
+
-DVIB3_BUILD_WASM=ON \
|
|
90
|
+
-DVIB3_BUILD_TESTS=OFF \
|
|
91
|
+
-DVIB3_ENABLE_SIMD=ON
|
|
92
|
+
|
|
93
|
+
cmake --build . -j"${NPROC}"
|
|
94
|
+
|
|
95
|
+
# Copy outputs
|
|
96
|
+
mkdir -p "${DIST_DIR}"
|
|
97
|
+
cp -f bin/vib3.js bin/vib3.wasm "${DIST_DIR}/"
|
|
98
|
+
[ -f bin/vib3.d.ts ] && cp -f bin/vib3.d.ts "${DIST_DIR}/"
|
|
99
|
+
|
|
100
|
+
log "Release WASM build complete. Output: ${DIST_DIR}/"
|
|
101
|
+
ls -lh "${DIST_DIR}/"
|
|
102
|
+
;;
|
|
103
|
+
|
|
104
|
+
native)
|
|
105
|
+
log "Building native (with tests)..."
|
|
106
|
+
|
|
107
|
+
mkdir -p "${BUILD_DIR}/native"
|
|
108
|
+
cd "${BUILD_DIR}/native"
|
|
109
|
+
|
|
110
|
+
cmake "${SCRIPT_DIR}" \
|
|
111
|
+
-DCMAKE_BUILD_TYPE=Debug \
|
|
112
|
+
-DVIB3_BUILD_WASM=OFF \
|
|
113
|
+
-DVIB3_BUILD_TESTS=ON \
|
|
114
|
+
-DVIB3_ENABLE_SIMD=ON
|
|
115
|
+
|
|
116
|
+
cmake --build . -j"${NPROC}"
|
|
117
|
+
|
|
118
|
+
log "Running tests..."
|
|
119
|
+
ctest --output-on-failure
|
|
120
|
+
|
|
121
|
+
log "Native build and tests complete."
|
|
122
|
+
;;
|
|
123
|
+
|
|
124
|
+
*)
|
|
125
|
+
error "Unknown build type: ${BUILD_TYPE}"
|
|
126
|
+
echo "Usage: $0 [release|debug|native|clean]"
|
|
127
|
+
exit 1
|
|
128
|
+
;;
|
|
129
|
+
esac
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crystal.cpp - Octahedral / Crystalline Structure in 4D
|
|
3
|
+
*
|
|
4
|
+
* Generates vertices and edge geometry for crystalline structures
|
|
5
|
+
* in 4D: the regular octahedron (cross-polytope) and its dual,
|
|
6
|
+
* extended with 4D vertices along the W axis.
|
|
7
|
+
*
|
|
8
|
+
* The 4D cross-polytope (hyperoctahedron / 16-cell) has 8 vertices
|
|
9
|
+
* at the 4 axis-aligned unit positions and their negations.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "math/Vec4.hpp"
|
|
13
|
+
#include <vector>
|
|
14
|
+
#include <cmath>
|
|
15
|
+
#include <numbers>
|
|
16
|
+
|
|
17
|
+
namespace vib3 {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate the 8 vertices of a 4D cross-polytope (hyperoctahedron / 16-cell).
|
|
21
|
+
*
|
|
22
|
+
* Vertices lie at (+-1, 0, 0, 0), (0, +-1, 0, 0), (0, 0, +-1, 0), (0, 0, 0, +-1).
|
|
23
|
+
*/
|
|
24
|
+
std::vector<Vec4> generateCrossPolytopeVertices() noexcept {
|
|
25
|
+
std::vector<Vec4> vertices;
|
|
26
|
+
vertices.reserve(8);
|
|
27
|
+
|
|
28
|
+
vertices.emplace_back( 1.0f, 0.0f, 0.0f, 0.0f);
|
|
29
|
+
vertices.emplace_back(-1.0f, 0.0f, 0.0f, 0.0f);
|
|
30
|
+
vertices.emplace_back( 0.0f, 1.0f, 0.0f, 0.0f);
|
|
31
|
+
vertices.emplace_back( 0.0f, -1.0f, 0.0f, 0.0f);
|
|
32
|
+
vertices.emplace_back( 0.0f, 0.0f, 1.0f, 0.0f);
|
|
33
|
+
vertices.emplace_back( 0.0f, 0.0f, -1.0f, 0.0f);
|
|
34
|
+
vertices.emplace_back( 0.0f, 0.0f, 0.0f, 1.0f);
|
|
35
|
+
vertices.emplace_back( 0.0f, 0.0f, 0.0f, -1.0f);
|
|
36
|
+
|
|
37
|
+
return vertices;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate crystalline geometry with edge interpolation.
|
|
42
|
+
*
|
|
43
|
+
* The 4D cross-polytope has 24 edges: every pair of non-antipodal vertices
|
|
44
|
+
* is connected (i.e., vertices i and j are connected unless they lie on
|
|
45
|
+
* the same axis). Each edge is subdivided into `resolution` segments.
|
|
46
|
+
*
|
|
47
|
+
* Additionally generates midpoint vertices for a dual-lattice structure
|
|
48
|
+
* (the 4D hypercube formed by the dual vertices at the edge midpoints).
|
|
49
|
+
*
|
|
50
|
+
* @param resolution Number of subdivisions per edge (minimum 2)
|
|
51
|
+
* @return Vector of 4D points forming the crystal wireframe
|
|
52
|
+
*/
|
|
53
|
+
std::vector<Vec4> generateCrystal(int resolution) noexcept {
|
|
54
|
+
if (resolution < 2) resolution = 2;
|
|
55
|
+
|
|
56
|
+
auto baseVertices = generateCrossPolytopeVertices();
|
|
57
|
+
|
|
58
|
+
// Edges of the 16-cell: connect every pair of vertices that are
|
|
59
|
+
// NOT antipodal (not on the same axis).
|
|
60
|
+
// 8 vertices, 24 edges total.
|
|
61
|
+
struct Edge { int a, b; };
|
|
62
|
+
std::vector<Edge> edges;
|
|
63
|
+
edges.reserve(24);
|
|
64
|
+
|
|
65
|
+
for (int i = 0; i < 8; ++i) {
|
|
66
|
+
for (int j = i + 1; j < 8; ++j) {
|
|
67
|
+
// Antipodal pairs: (0,1), (2,3), (4,5), (6,7)
|
|
68
|
+
// Skip if on same axis (differ by 1 and i is even)
|
|
69
|
+
if ((i ^ j) == 1 && (i % 2 == 0)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
edges.push_back({i, j});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
std::vector<Vec4> vertices;
|
|
77
|
+
vertices.reserve(edges.size() * static_cast<size_t>(resolution) + 16);
|
|
78
|
+
|
|
79
|
+
// Edge wireframe
|
|
80
|
+
for (const auto& edge : edges) {
|
|
81
|
+
const Vec4& a = baseVertices[static_cast<size_t>(edge.a)];
|
|
82
|
+
const Vec4& b = baseVertices[static_cast<size_t>(edge.b)];
|
|
83
|
+
|
|
84
|
+
for (int i = 0; i < resolution; ++i) {
|
|
85
|
+
float t = static_cast<float>(i) / static_cast<float>(resolution - 1);
|
|
86
|
+
vertices.push_back(a.lerp(b, t));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Dual vertices (tesseract / hypercube dual): midpoints of faces
|
|
91
|
+
// These are the 16 vertices of the dual polytope at (+-0.5, +-0.5, +-0.5, +-0.5)
|
|
92
|
+
for (int i = 0; i < 16; ++i) {
|
|
93
|
+
float x = (i & 1) ? 0.5f : -0.5f;
|
|
94
|
+
float y = (i & 2) ? 0.5f : -0.5f;
|
|
95
|
+
float z = (i & 4) ? 0.5f : -0.5f;
|
|
96
|
+
float w = (i & 8) ? 0.5f : -0.5f;
|
|
97
|
+
vertices.emplace_back(x, y, z, w);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return vertices;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
} // namespace vib3
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fractal.cpp - 4D Iterated Function System Fractal
|
|
3
|
+
*
|
|
4
|
+
* Generates recursive subdivision geometry in 4D using an IFS approach.
|
|
5
|
+
* Starts from an initial set of points and iteratively applies affine
|
|
6
|
+
* contractions toward attractor vertices, building a self-similar
|
|
7
|
+
* fractal structure (a 4D analogue of the Sierpinski tetrahedron).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "math/Vec4.hpp"
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include <cmath>
|
|
13
|
+
#include <numbers>
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
|
|
16
|
+
namespace vib3 {
|
|
17
|
+
|
|
18
|
+
namespace {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 4D Sierpinski-style attractor vertices.
|
|
22
|
+
*
|
|
23
|
+
* Five vertices of a regular 5-cell (pentatope) provide a natural
|
|
24
|
+
* set of contraction centers for a 4D IFS.
|
|
25
|
+
*/
|
|
26
|
+
constexpr int kNumAttractors = 5;
|
|
27
|
+
|
|
28
|
+
Vec4 getAttractorVertex(int index) noexcept {
|
|
29
|
+
// Regular pentatope vertices (5-cell), embedded in R4
|
|
30
|
+
// These are the vertices of a regular simplex in 4D.
|
|
31
|
+
switch (index) {
|
|
32
|
+
case 0: return Vec4( 1.0f, 1.0f, 1.0f, -1.0f / std::numbers::sqrt2_v<float>);
|
|
33
|
+
case 1: return Vec4( 1.0f, -1.0f, -1.0f, -1.0f / std::numbers::sqrt2_v<float>);
|
|
34
|
+
case 2: return Vec4(-1.0f, 1.0f, -1.0f, -1.0f / std::numbers::sqrt2_v<float>);
|
|
35
|
+
case 3: return Vec4(-1.0f, -1.0f, 1.0f, -1.0f / std::numbers::sqrt2_v<float>);
|
|
36
|
+
case 4: return Vec4( 0.0f, 0.0f, 0.0f, 4.0f / std::numbers::sqrt2_v<float>);
|
|
37
|
+
default: return Vec4::zero();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Simple deterministic hash for reproducible pseudo-random attractor selection.
|
|
43
|
+
*/
|
|
44
|
+
constexpr uint32_t hashStep(uint32_t seed) noexcept {
|
|
45
|
+
seed ^= seed << 13;
|
|
46
|
+
seed ^= seed >> 17;
|
|
47
|
+
seed ^= seed << 5;
|
|
48
|
+
return seed;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
} // anonymous namespace
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Generate a 4D IFS fractal via the chaos game.
|
|
55
|
+
*
|
|
56
|
+
* Uses the classic chaos game algorithm: starting from a seed point,
|
|
57
|
+
* repeatedly pick a random attractor and move halfway toward it.
|
|
58
|
+
* After a warm-up period, the trajectory traces out the fractal.
|
|
59
|
+
*
|
|
60
|
+
* @param resolution Controls the number of output points (resolution^2 points)
|
|
61
|
+
* @return Vector of 4D fractal points
|
|
62
|
+
*/
|
|
63
|
+
std::vector<Vec4> generateFractal(int resolution) noexcept {
|
|
64
|
+
if (resolution < 4) resolution = 4;
|
|
65
|
+
|
|
66
|
+
int numPoints = resolution * resolution;
|
|
67
|
+
constexpr int warmUp = 64;
|
|
68
|
+
constexpr float contractionFactor = 0.5f;
|
|
69
|
+
|
|
70
|
+
std::vector<Vec4> vertices;
|
|
71
|
+
vertices.reserve(static_cast<size_t>(numPoints));
|
|
72
|
+
|
|
73
|
+
// Start at the origin
|
|
74
|
+
Vec4 current = Vec4::zero();
|
|
75
|
+
uint32_t seed = 0xDEADBEEF;
|
|
76
|
+
|
|
77
|
+
// Warm-up iterations (discard to converge onto attractor)
|
|
78
|
+
for (int i = 0; i < warmUp; ++i) {
|
|
79
|
+
seed = hashStep(seed);
|
|
80
|
+
int attIdx = static_cast<int>(seed % kNumAttractors);
|
|
81
|
+
Vec4 target = getAttractorVertex(attIdx);
|
|
82
|
+
current = current.lerp(target, contractionFactor);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Generate fractal points
|
|
86
|
+
for (int i = 0; i < numPoints; ++i) {
|
|
87
|
+
seed = hashStep(seed);
|
|
88
|
+
int attIdx = static_cast<int>(seed % kNumAttractors);
|
|
89
|
+
Vec4 target = getAttractorVertex(attIdx);
|
|
90
|
+
current = current.lerp(target, contractionFactor);
|
|
91
|
+
vertices.push_back(current);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return vertices;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Generate a 4D IFS fractal via recursive subdivision.
|
|
99
|
+
*
|
|
100
|
+
* Starts from attractor vertices and recursively subdivides midpoints
|
|
101
|
+
* to a given depth, producing a deterministic point set.
|
|
102
|
+
*
|
|
103
|
+
* @param depth Recursion depth (0 = just vertices, each level multiplies points by 5)
|
|
104
|
+
* @return Vector of 4D fractal points
|
|
105
|
+
*/
|
|
106
|
+
std::vector<Vec4> generateFractalSubdivision(int depth) noexcept {
|
|
107
|
+
if (depth < 0) depth = 0;
|
|
108
|
+
if (depth > 6) depth = 6; // Cap to avoid excessive memory
|
|
109
|
+
|
|
110
|
+
std::vector<Vec4> current;
|
|
111
|
+
current.reserve(static_cast<size_t>(kNumAttractors));
|
|
112
|
+
|
|
113
|
+
// Seed with attractor vertices
|
|
114
|
+
for (int i = 0; i < kNumAttractors; ++i) {
|
|
115
|
+
current.push_back(getAttractorVertex(i));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Recursive subdivision
|
|
119
|
+
for (int d = 0; d < depth; ++d) {
|
|
120
|
+
std::vector<Vec4> next;
|
|
121
|
+
next.reserve(current.size() * static_cast<size_t>(kNumAttractors));
|
|
122
|
+
|
|
123
|
+
for (const auto& point : current) {
|
|
124
|
+
for (int a = 0; a < kNumAttractors; ++a) {
|
|
125
|
+
Vec4 target = getAttractorVertex(a);
|
|
126
|
+
next.push_back(point.lerp(target, 0.5f));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
current = std::move(next);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return current;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
} // namespace vib3
|