@nayan-ui/engine 0.0.0-stage → 1.0.0-beta.3
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/LICENSE +21 -0
- package/NayanEngine.podspec +28 -0
- package/README.md +210 -2
- package/lib/module/assets/AssetBytesCache.js +76 -0
- package/lib/module/assets/AssetCache.js +19 -0
- package/lib/module/assets/AssetLoader.js +52 -0
- package/lib/module/assets/CacheGeneration.js +7 -0
- package/lib/module/assets/IndexedDbCache.web.js +149 -0
- package/lib/module/assets/ProceduralCache.js +222 -0
- package/lib/module/assets/font.js +136 -0
- package/lib/module/assets/loft.js +142 -0
- package/lib/module/assets/model.js +74 -0
- package/lib/module/assets/modelling.js +254 -0
- package/lib/module/assets/shape.js +926 -0
- package/lib/module/assets/source.js +58 -0
- package/lib/module/assets/source.web.js +22 -0
- package/lib/module/assets/storage.js +4 -0
- package/lib/module/assets/storage.shared.js +36 -0
- package/lib/module/assets/storage.web.js +37 -0
- package/lib/module/assets/surface.js +47 -0
- package/lib/module/assets/texture.js +66 -0
- package/lib/module/drawing/DrawingCanvas.js +38 -0
- package/lib/module/drawing/DrawingCanvas.web.js +206 -0
- package/lib/module/drawing/DrawingDocument.js +256 -0
- package/lib/module/drawing/types.js +4 -0
- package/lib/module/globals.d.ts +12 -0
- package/lib/module/index.js +36 -0
- package/lib/module/input/Joystick.js +84 -0
- package/lib/module/input/Joystick.web.js +93 -0
- package/lib/module/input/keyboard.js +250 -0
- package/lib/module/media/audio-worklet.js +34 -0
- package/lib/module/media/audio.js +94 -0
- package/lib/module/media/haptics.js +82 -0
- package/lib/module/media/output.web.js +66 -0
- package/lib/module/native/BrowserEngine.js +551 -0
- package/lib/module/native/EngineBridge.js +4 -0
- package/lib/module/native/NativeNayanEngine.js +7 -0
- package/lib/module/native/NativeNayanEngine.web.js +62 -0
- package/lib/module/native/prepare.js +7 -0
- package/lib/module/native/prepare.web.js +17 -0
- package/lib/module/native/spec/NativeNayanEngine.js +17 -0
- package/lib/module/package.json +1 -0
- package/lib/module/render/GameView.js +249 -0
- package/lib/module/render/camera.js +34 -0
- package/lib/module/render/host.js +39 -0
- package/lib/module/render/host.web.js +104 -0
- package/lib/module/render/meshes.js +159 -0
- package/lib/module/render/quality.js +112 -0
- package/lib/module/render/responder.js +4 -0
- package/lib/module/render/responder.web.js +97 -0
- package/lib/module/render/touch.js +185 -0
- package/lib/module/types.js +30 -0
- package/lib/module/world/Scoreboard.js +143 -0
- package/lib/module/world/TransformBatch.js +126 -0
- package/lib/module/world/World.js +690 -0
- package/lib/module/world/desc.js +186 -0
- package/lib/module/world/effects.js +451 -0
- package/lib/module/world/quat.js +86 -0
- package/lib/module/world/types.js +4 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/assets/AssetBytesCache.d.ts +7 -0
- package/lib/typescript/src/assets/AssetCache.d.ts +9 -0
- package/lib/typescript/src/assets/AssetLoader.d.ts +11 -0
- package/lib/typescript/src/assets/CacheGeneration.d.ts +3 -0
- package/lib/typescript/src/assets/IndexedDbCache.web.d.ts +20 -0
- package/lib/typescript/src/assets/ProceduralCache.d.ts +33 -0
- package/lib/typescript/src/assets/font.d.ts +53 -0
- package/lib/typescript/src/assets/loft.d.ts +31 -0
- package/lib/typescript/src/assets/model.d.ts +48 -0
- package/lib/typescript/src/assets/modelling.d.ts +157 -0
- package/lib/typescript/src/assets/shape.d.ts +203 -0
- package/lib/typescript/src/assets/source.d.ts +10 -0
- package/lib/typescript/src/assets/source.web.d.ts +8 -0
- package/lib/typescript/src/assets/storage.d.ts +2 -0
- package/lib/typescript/src/assets/storage.shared.d.ts +7 -0
- package/lib/typescript/src/assets/storage.web.d.ts +7 -0
- package/lib/typescript/src/assets/surface.d.ts +17 -0
- package/lib/typescript/src/assets/texture.d.ts +30 -0
- package/lib/typescript/src/drawing/DrawingCanvas.d.ts +5 -0
- package/lib/typescript/src/drawing/DrawingCanvas.web.d.ts +4 -0
- package/lib/typescript/src/drawing/DrawingDocument.d.ts +210 -0
- package/lib/typescript/src/drawing/types.d.ts +12 -0
- package/lib/typescript/src/index.d.ts +42 -0
- package/lib/typescript/src/input/Joystick.d.ts +20 -0
- package/lib/typescript/src/input/Joystick.web.d.ts +13 -0
- package/lib/typescript/src/input/keyboard.d.ts +17 -0
- package/lib/typescript/src/media/audio.d.ts +46 -0
- package/lib/typescript/src/media/haptics.d.ts +22 -0
- package/lib/typescript/src/media/output.web.d.ts +4 -0
- package/lib/typescript/src/native/BrowserEngine.d.ts +8 -0
- package/lib/typescript/src/native/EngineBridge.d.ts +22 -0
- package/lib/typescript/src/native/NativeNayanEngine.d.ts +5 -0
- package/lib/typescript/src/native/NativeNayanEngine.web.d.ts +10 -0
- package/lib/typescript/src/native/prepare.d.ts +3 -0
- package/lib/typescript/src/native/prepare.web.d.ts +2 -0
- package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +182 -0
- package/lib/typescript/src/render/GameView.d.ts +95 -0
- package/lib/typescript/src/render/camera.d.ts +6 -0
- package/lib/typescript/src/render/host.d.ts +29 -0
- package/lib/typescript/src/render/host.web.d.ts +16 -0
- package/lib/typescript/src/render/meshes.d.ts +45 -0
- package/lib/typescript/src/render/quality.d.ts +46 -0
- package/lib/typescript/src/render/responder.d.ts +2 -0
- package/lib/typescript/src/render/responder.web.d.ts +40 -0
- package/lib/typescript/src/render/touch.d.ts +26 -0
- package/lib/typescript/src/types.d.ts +72 -0
- package/lib/typescript/src/world/Scoreboard.d.ts +65 -0
- package/lib/typescript/src/world/TransformBatch.d.ts +39 -0
- package/lib/typescript/src/world/World.d.ts +199 -0
- package/lib/typescript/src/world/desc.d.ts +17 -0
- package/lib/typescript/src/world/effects.d.ts +156 -0
- package/lib/typescript/src/world/quat.d.ts +31 -0
- package/lib/typescript/src/world/types.d.ts +233 -0
- package/lib/web/audio-worklet.js +29 -0
- package/lib/web/engine_core_bg.wasm +0 -0
- package/lib/web/index.js +7974 -0
- package/lib/web/types/src/assets/AssetBytesCache.d.ts +6 -0
- package/lib/web/types/src/assets/AssetCache.d.ts +8 -0
- package/lib/web/types/src/assets/AssetLoader.d.ts +10 -0
- package/lib/web/types/src/assets/CacheGeneration.d.ts +2 -0
- package/lib/web/types/src/assets/IndexedDbCache.d.ts +19 -0
- package/lib/web/types/src/assets/ProceduralCache.d.ts +32 -0
- package/lib/web/types/src/assets/font.d.ts +52 -0
- package/lib/web/types/src/assets/loft.d.ts +30 -0
- package/lib/web/types/src/assets/model.d.ts +47 -0
- package/lib/web/types/src/assets/modelling.d.ts +156 -0
- package/lib/web/types/src/assets/shape.d.ts +202 -0
- package/lib/web/types/src/assets/source.d.ts +7 -0
- package/lib/web/types/src/assets/storage.d.ts +6 -0
- package/lib/web/types/src/assets/storage.shared.d.ts +6 -0
- package/lib/web/types/src/assets/surface.d.ts +16 -0
- package/lib/web/types/src/assets/texture.d.ts +29 -0
- package/lib/web/types/src/drawing/DrawingCanvas.d.ts +3 -0
- package/lib/web/types/src/drawing/DrawingDocument.d.ts +209 -0
- package/lib/web/types/src/drawing/types.d.ts +11 -0
- package/lib/web/types/src/index.d.ts +41 -0
- package/lib/web/types/src/input/Joystick.d.ts +12 -0
- package/lib/web/types/src/input/keyboard.d.ts +16 -0
- package/lib/web/types/src/media/audio.d.ts +45 -0
- package/lib/web/types/src/media/haptics.d.ts +21 -0
- package/lib/web/types/src/media/output.d.ts +3 -0
- package/lib/web/types/src/native/BrowserEngine.d.ts +7 -0
- package/lib/web/types/src/native/EngineBridge.d.ts +21 -0
- package/lib/web/types/src/native/NativeNayanEngine.d.ts +9 -0
- package/lib/web/types/src/native/prepare.d.ts +1 -0
- package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +181 -0
- package/lib/web/types/src/render/GameView.d.ts +94 -0
- package/lib/web/types/src/render/camera.d.ts +5 -0
- package/lib/web/types/src/render/host.d.ts +15 -0
- package/lib/web/types/src/render/meshes.d.ts +44 -0
- package/lib/web/types/src/render/quality.d.ts +45 -0
- package/lib/web/types/src/render/responder.d.ts +39 -0
- package/lib/web/types/src/render/touch.d.ts +25 -0
- package/lib/web/types/src/types.d.ts +71 -0
- package/lib/web/types/src/world/Scoreboard.d.ts +64 -0
- package/lib/web/types/src/world/TransformBatch.d.ts +38 -0
- package/lib/web/types/src/world/World.d.ts +198 -0
- package/lib/web/types/src/world/desc.d.ts +16 -0
- package/lib/web/types/src/world/effects.d.ts +155 -0
- package/lib/web/types/src/world/quat.d.ts +30 -0
- package/lib/web/types/src/world/types.d.ts +232 -0
- package/native/android/CMakeLists.txt +34 -0
- package/native/android/NayanEngineSpec.h +15 -0
- package/native/android/build.gradle +26 -0
- package/native/android/codegen/CMakeLists.txt +3 -0
- package/native/android/proguard-rules.pro +2 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +234 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceViewManager.java +45 -0
- package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +24 -0
- package/native/core/build/EngineCore.xcframework/Info.plist +43 -0
- package/native/core/build/EngineCore.xcframework/ios-arm64/libengine_core.a +0 -0
- package/native/core/build/EngineCore.xcframework/ios-arm64-simulator/libengine_core.a +0 -0
- package/native/core/build/android/arm64-v8a/libengine_core.a +0 -0
- package/native/core/build/android/armeabi-v7a/libengine_core.a +0 -0
- package/native/core/build/android/x86/libengine_core.a +0 -0
- package/native/core/build/android/x86_64/libengine_core.a +0 -0
- package/native/core/include/drawing-licenses.txt +58 -0
- package/native/core/include/engine_core.h +322 -0
- package/native/cpp/NayanEngineModule.cpp +827 -0
- package/native/cpp/NayanEngineModule.h +144 -0
- package/native/cpp/generated/NayanEngineSpecJSI.cpp +2 -0
- package/native/cpp/generated/NayanEngineSpecJSI.h +921 -0
- package/native/ios/NayanEngineProvider.h +5 -0
- package/native/ios/NayanEngineProvider.mm +21 -0
- package/native/ios/NayanEngineSurface.mm +223 -0
- package/native/scripts/check-package.mjs +39 -0
- package/package.json +162 -4
- package/react-native.config.js +18 -0
- package/src/native/spec/NativeNayanEngine.ts +226 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
#include "NayanEngineModule.h"
|
|
2
|
+
|
|
3
|
+
#include <engine_core.h>
|
|
4
|
+
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
#include <cstring>
|
|
7
|
+
|
|
8
|
+
#ifdef __ANDROID__
|
|
9
|
+
#include <fbjni/fbjni.h>
|
|
10
|
+
#include <jni.h>
|
|
11
|
+
#endif
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
namespace facebook::react {
|
|
16
|
+
|
|
17
|
+
namespace {
|
|
18
|
+
|
|
19
|
+
// Exposes Rust-owned memory to JS as an ArrayBuffer without copying (capacity is fixed, so it never
|
|
20
|
+
// moves). Holds a reference to the owning world, so a buffer JS keeps after destroyWorld stays valid.
|
|
21
|
+
// Memory owned by the buffer itself (results the core copies out).
|
|
22
|
+
class OwnedBuffer : public jsi::MutableBuffer {
|
|
23
|
+
public:
|
|
24
|
+
explicit OwnedBuffer(size_t size) : bytes_(size) {}
|
|
25
|
+
size_t size() const override { return bytes_.size(); }
|
|
26
|
+
uint8_t *data() override { return bytes_.data(); }
|
|
27
|
+
|
|
28
|
+
private:
|
|
29
|
+
std::vector<uint8_t> bytes_;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
class ExternalBuffer : public jsi::MutableBuffer {
|
|
33
|
+
public:
|
|
34
|
+
ExternalBuffer(std::shared_ptr<void> owner, uint8_t *data, size_t size)
|
|
35
|
+
: owner_(std::move(owner)), data_(data), size_(size) {}
|
|
36
|
+
size_t size() const override { return size_; }
|
|
37
|
+
uint8_t *data() override { return data_; }
|
|
38
|
+
|
|
39
|
+
private:
|
|
40
|
+
std::shared_ptr<void> owner_;
|
|
41
|
+
uint8_t *data_;
|
|
42
|
+
size_t size_;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
jsi::Object geometryResult(jsi::Runtime &rt, EngineGeometry *raw) {
|
|
46
|
+
std::unique_ptr<EngineGeometry, decltype(&engine_geometry_free)> result(raw, engine_geometry_free);
|
|
47
|
+
const char *error = engine_geometry_error(result.get());
|
|
48
|
+
if (error[0] != '\0') throw jsi::JSError(rt, std::string("NayanEngine modelling: ") + error);
|
|
49
|
+
const uint32_t *data = engine_geometry_data(result.get());
|
|
50
|
+
const size_t bytes = engine_geometry_size(result.get());
|
|
51
|
+
if (data == nullptr || bytes < 8) throw jsi::JSError(rt, "NayanEngine modelling: invalid result");
|
|
52
|
+
const size_t vertexBytes = static_cast<size_t>(data[0]) * 11 * sizeof(float);
|
|
53
|
+
const size_t indexBytes = static_cast<size_t>(data[1]) * sizeof(uint32_t);
|
|
54
|
+
if (bytes != 8 + vertexBytes + indexBytes) throw jsi::JSError(rt, "NayanEngine modelling: invalid buffers");
|
|
55
|
+
auto vertices = std::make_shared<OwnedBuffer>(vertexBytes);
|
|
56
|
+
auto indices = std::make_shared<OwnedBuffer>(indexBytes);
|
|
57
|
+
if (vertexBytes > 0) std::memcpy(vertices->data(), data + 2, vertexBytes);
|
|
58
|
+
if (indexBytes > 0) std::memcpy(indices->data(), reinterpret_cast<const uint8_t *>(data + 2) + vertexBytes, indexBytes);
|
|
59
|
+
jsi::Object out(rt);
|
|
60
|
+
out.setProperty(rt, "vertices", jsi::ArrayBuffer(rt, std::move(vertices)));
|
|
61
|
+
out.setProperty(rt, "indices", jsi::ArrayBuffer(rt, std::move(indices)));
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// JS numbers -> entity ids. Negative or out-of-range values (e.g. -1 for "none") map to NO_ENTITY.
|
|
66
|
+
uint32_t id(double v) {
|
|
67
|
+
return (v >= 0 && v <= static_cast<double>(UINT32_MAX)) ? static_cast<uint32_t>(v) : ENGINE_NO_ENTITY;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// JS numbers -> layer/mask bit sets (layers are 32 bits; -1 or 0xffffffff means "all").
|
|
71
|
+
uint32_t bits(double v) {
|
|
72
|
+
if (!(v >= -2147483648.0 && v <= 4294967295.0)) {
|
|
73
|
+
return 0; // NaN or out of range (the cast below would be undefined)
|
|
74
|
+
}
|
|
75
|
+
return static_cast<uint32_t>(static_cast<int64_t>(v) & 0xffffffff);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#ifdef __ANDROID__
|
|
79
|
+
// Gives the core the JavaVM and the Application context, which audio (cpal's AAudio backend) and
|
|
80
|
+
// haptics (the Vibrator service) need. Runs once; any failure leaves audio and haptics silent.
|
|
81
|
+
void initAndroid() {
|
|
82
|
+
static bool done = false;
|
|
83
|
+
if (done) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
done = true;
|
|
87
|
+
try {
|
|
88
|
+
JNIEnv *env = facebook::jni::Environment::current();
|
|
89
|
+
JavaVM *vm = nullptr;
|
|
90
|
+
if (env == nullptr || env->GetJavaVM(&vm) != JNI_OK || vm == nullptr) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
jclass activityThread = env->FindClass("android/app/ActivityThread");
|
|
94
|
+
jmethodID currentApplication = activityThread == nullptr
|
|
95
|
+
? nullptr
|
|
96
|
+
: env->GetStaticMethodID(activityThread, "currentApplication", "()Landroid/app/Application;");
|
|
97
|
+
jobject app = currentApplication == nullptr ? nullptr : env->CallStaticObjectMethod(activityThread, currentApplication);
|
|
98
|
+
if (env->ExceptionCheck()) {
|
|
99
|
+
env->ExceptionClear();
|
|
100
|
+
}
|
|
101
|
+
if (app != nullptr) {
|
|
102
|
+
// Android's files directory is durable app-private data, not the OS-purgeable cache.
|
|
103
|
+
jclass appClass = env->GetObjectClass(app);
|
|
104
|
+
jmethodID getFilesDir = env->GetMethodID(appClass, "getFilesDir", "()Ljava/io/File;");
|
|
105
|
+
jobject files = getFilesDir == nullptr ? nullptr : env->CallObjectMethod(app, getFilesDir);
|
|
106
|
+
if (files != nullptr && !env->ExceptionCheck()) {
|
|
107
|
+
jclass fileClass = env->GetObjectClass(files);
|
|
108
|
+
jmethodID getPath = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
|
|
109
|
+
jstring path = getPath == nullptr ? nullptr : static_cast<jstring>(env->CallObjectMethod(files, getPath));
|
|
110
|
+
if (path != nullptr && !env->ExceptionCheck()) {
|
|
111
|
+
const char *text = env->GetStringUTFChars(path, nullptr);
|
|
112
|
+
if (text != nullptr) { engine_cache_directory(reinterpret_cast<const uint8_t *>(text), std::strlen(text)); env->ReleaseStringUTFChars(path, text); }
|
|
113
|
+
env->DeleteLocalRef(path);
|
|
114
|
+
}
|
|
115
|
+
env->DeleteLocalRef(fileClass); env->DeleteLocalRef(files);
|
|
116
|
+
}
|
|
117
|
+
if (env->ExceptionCheck()) env->ExceptionClear();
|
|
118
|
+
env->DeleteLocalRef(appClass);
|
|
119
|
+
engine_android_init(vm, env->NewGlobalRef(app)); // global ref: lives for the whole process
|
|
120
|
+
env->DeleteLocalRef(app);
|
|
121
|
+
}
|
|
122
|
+
if (activityThread != nullptr) {
|
|
123
|
+
env->DeleteLocalRef(activityThread);
|
|
124
|
+
}
|
|
125
|
+
} catch (...) {
|
|
126
|
+
// No JNI environment on this thread: audio and haptics stay off rather than crash.
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
#endif
|
|
130
|
+
|
|
131
|
+
} // namespace
|
|
132
|
+
|
|
133
|
+
NayanEngineModule::NayanEngineModule(std::shared_ptr<CallInvoker> jsInvoker)
|
|
134
|
+
: NativeNayanEngineCxxSpec(std::move(jsInvoker)) {
|
|
135
|
+
#ifdef __ANDROID__
|
|
136
|
+
initAndroid();
|
|
137
|
+
#endif
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Worlds are freed when the module and every buffer aliasing them are gone.
|
|
141
|
+
NayanEngineModule::~NayanEngineModule() {
|
|
142
|
+
for (int document : drawings_) engine_drawing_destroy(document);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
namespace {
|
|
146
|
+
// NaN, fractional and out-of-range ids are unknown (casting them to int is undefined or aliases another id).
|
|
147
|
+
bool knownWorldId(double worldId, int next) {
|
|
148
|
+
return worldId >= 1 && worldId < next && worldId == static_cast<int>(worldId);
|
|
149
|
+
}
|
|
150
|
+
} // namespace
|
|
151
|
+
|
|
152
|
+
std::shared_ptr<::World> NayanEngineModule::owner(double worldId) const {
|
|
153
|
+
if (!knownWorldId(worldId, next_)) {
|
|
154
|
+
return nullptr;
|
|
155
|
+
}
|
|
156
|
+
auto it = worlds_.find(static_cast<int>(worldId));
|
|
157
|
+
return it == worlds_.end() ? nullptr : it->second;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
::World *NayanEngineModule::find(double worldId) const {
|
|
161
|
+
if (!knownWorldId(worldId, next_)) {
|
|
162
|
+
return nullptr;
|
|
163
|
+
}
|
|
164
|
+
// No shared_ptr copy (atomic refcount) per call: the map owns the world, and every caller runs on
|
|
165
|
+
// the JS thread, which is also the only thread that can erase it (destroyWorld).
|
|
166
|
+
auto it = worlds_.find(static_cast<int>(worldId));
|
|
167
|
+
return it == worlds_.end() ? nullptr : it->second.get();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
jsi::Object NayanEngineModule::external(
|
|
171
|
+
jsi::Runtime &rt, std::shared_ptr<void> owner, const void *data, size_t bytes) const {
|
|
172
|
+
if (data == nullptr) {
|
|
173
|
+
throw jsi::JSError(rt, "NayanEngine: unknown world, mesh or texture");
|
|
174
|
+
}
|
|
175
|
+
jsi::ArrayBuffer buffer(
|
|
176
|
+
rt,
|
|
177
|
+
std::make_shared<ExternalBuffer>(
|
|
178
|
+
std::move(owner), reinterpret_cast<uint8_t *>(const_cast<void *>(data)), bytes));
|
|
179
|
+
return jsi::Object(std::move(buffer));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
double NayanEngineModule::createWorld(jsi::Runtime &, double capacity) {
|
|
183
|
+
int worldId = next_++;
|
|
184
|
+
// NaN / negative -> 0; the core clamps very large values.
|
|
185
|
+
uint32_t n = capacity >= 1 ? static_cast<uint32_t>(std::min(capacity, 1048576.0)) : 0;
|
|
186
|
+
worlds_[worldId] = std::shared_ptr<::World>(engine_world_new(n), engine_world_free);
|
|
187
|
+
return worldId;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void NayanEngineModule::destroyWorld(jsi::Runtime &, double world) {
|
|
191
|
+
if (owner(world) != nullptr) {
|
|
192
|
+
worlds_.erase(static_cast<int>(world));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
namespace {
|
|
197
|
+
|
|
198
|
+
// An encoded description (entity, animation, burst): a Float64Array's ArrayBuffer of doubles.
|
|
199
|
+
const double *descData(jsi::Runtime &rt, jsi::Object &desc, size_t &len) {
|
|
200
|
+
if (!desc.isArrayBuffer(rt)) {
|
|
201
|
+
throw jsi::JSError(rt, "NayanEngine: expected an ArrayBuffer description");
|
|
202
|
+
}
|
|
203
|
+
jsi::ArrayBuffer buffer = desc.getArrayBuffer(rt);
|
|
204
|
+
len = buffer.size(rt) / sizeof(double);
|
|
205
|
+
return reinterpret_cast<const double *>(buffer.data(rt));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Bytes of a file passed from JS (copied by the core).
|
|
209
|
+
jsi::ArrayBuffer fileData(jsi::Runtime &rt, jsi::Object &data, const char *method) {
|
|
210
|
+
if (!data.isArrayBuffer(rt)) {
|
|
211
|
+
throw jsi::JSError(rt, std::string("NayanEngine.") + method + ": expected an ArrayBuffer");
|
|
212
|
+
}
|
|
213
|
+
return data.getArrayBuffer(rt);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
} // namespace
|
|
217
|
+
|
|
218
|
+
double NayanEngineModule::spawnDesc(jsi::Runtime &rt, double world, jsi::Object desc) {
|
|
219
|
+
size_t len = 0;
|
|
220
|
+
const double *data = descData(rt, desc, len);
|
|
221
|
+
uint32_t entity = engine_world_spawn_desc(find(world), data, len);
|
|
222
|
+
return entity == ENGINE_NO_ENTITY ? -1 : static_cast<double>(entity);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
bool NayanEngineModule::setDesc(jsi::Runtime &rt, double world, double entity, jsi::Object desc) {
|
|
226
|
+
size_t len = 0;
|
|
227
|
+
const double *data = descData(rt, desc, len);
|
|
228
|
+
return engine_world_set_desc(find(world), id(entity), data, len) != 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
bool NayanEngineModule::despawn(jsi::Runtime &, double world, double entity) {
|
|
232
|
+
return engine_world_despawn(find(world), id(entity)) != 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
double NayanEngineModule::setTransforms(jsi::Runtime &rt, double world, jsi::Object data, double count) {
|
|
236
|
+
size_t len = 0;
|
|
237
|
+
const double *values = descData(rt, data, len);
|
|
238
|
+
return engine_world_set_transforms(find(world), values, len, count > 0 ? static_cast<size_t>(std::min(count, static_cast<double>(len / 16))) : 0);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void NayanEngineModule::impulse(jsi::Runtime &, double world, double entity, double x, double y, double z) {
|
|
242
|
+
engine_world_apply_impulse(find(world), id(entity), x, y, z);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
void NayanEngineModule::setGravity(jsi::Runtime &, double world, double x, double y, double z) {
|
|
246
|
+
engine_world_set_gravity(find(world), x, y, z);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
void NayanEngineModule::setBounds(
|
|
250
|
+
jsi::Runtime &, double world, double minX, double minZ, double maxX, double maxZ) {
|
|
251
|
+
engine_world_set_bounds(find(world), minX, minZ, maxX, maxZ);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
double NayanEngineModule::raycast(
|
|
255
|
+
jsi::Runtime &, double world, double ox, double oy, double oz, double dx, double dy, double dz,
|
|
256
|
+
double maxDistance, double mask) {
|
|
257
|
+
uint32_t hit = engine_world_raycast(find(world), ox, oy, oz, dx, dy, dz, maxDistance, bits(mask));
|
|
258
|
+
return hit == ENGINE_NO_ENTITY ? -1 : static_cast<double>(hit);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
double NayanEngineModule::pick(jsi::Runtime &, double world, double ox, double oy, double oz, double dx, double dy, double dz) {
|
|
262
|
+
uint32_t hit = engine_world_pick(find(world), ox, oy, oz, dx, dy, dz);
|
|
263
|
+
return hit == ENGINE_NO_ENTITY ? -1 : static_cast<double>(hit);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
double NayanEngineModule::pickScreen(jsi::Runtime &, double world, double x, double y) {
|
|
267
|
+
uint32_t hit = engine_world_pick_screen(find(world), x, y);
|
|
268
|
+
return hit == ENGINE_NO_ENTITY ? -1 : static_cast<double>(hit);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void NayanEngineModule::setView(jsi::Runtime &rt, double world, jsi::Object viewProj, double width, double height) {
|
|
272
|
+
jsi::ArrayBuffer vp = fileData(rt, viewProj, "setView");
|
|
273
|
+
engine_world_set_view(find(world), reinterpret_cast<const float *>(vp.data(rt)), width, height);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
bool NayanEngineModule::screenRay(jsi::Runtime &, double world, double x, double y) {
|
|
277
|
+
return engine_world_screen_ray(find(world), x, y) != 0;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
bool NayanEngineModule::screenToWorld(
|
|
281
|
+
jsi::Runtime &, double world, double x, double y,
|
|
282
|
+
double ppx, double ppy, double ppz, double pnx, double pny, double pnz) {
|
|
283
|
+
return engine_world_screen_to_world(find(world), x, y, ppx, ppy, ppz, pnx, pny, pnz) != 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
bool NayanEngineModule::toScreen(jsi::Runtime &, double world, double x, double y, double z) {
|
|
287
|
+
return engine_world_to_screen(find(world), x, y, z) != 0;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
bool NayanEngineModule::readPosition(jsi::Runtime &, double world, double entity, bool rendered) {
|
|
291
|
+
return engine_world_read_position(find(world), id(entity), rendered ? 1 : 0) != 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
double NayanEngineModule::animate(jsi::Runtime &rt, double world, jsi::Object animation) {
|
|
295
|
+
size_t len = 0;
|
|
296
|
+
const double *data = descData(rt, animation, len);
|
|
297
|
+
return engine_world_animate(find(world), data, len);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
bool NayanEngineModule::stopAnimation(jsi::Runtime &, double world, double entity) {
|
|
301
|
+
return engine_world_stop_animation(find(world), id(entity)) != 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
double NayanEngineModule::burst(jsi::Runtime &rt, double world, jsi::Object burst) {
|
|
305
|
+
size_t len = 0;
|
|
306
|
+
const double *data = descData(rt, burst, len);
|
|
307
|
+
return engine_world_burst(find(world), data, len);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
bool NayanEngineModule::readVelocity(jsi::Runtime &, double world, double entity) {
|
|
311
|
+
return engine_world_read_velocity(find(world), id(entity)) != 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
void NayanEngineModule::update(jsi::Runtime &, double world, double dt) {
|
|
315
|
+
engine_world_update(find(world), static_cast<float>(dt));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
double NayanEngineModule::after(jsi::Runtime &, double world, double seconds) {
|
|
319
|
+
return engine_world_after(find(world), static_cast<float>(seconds));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
double NayanEngineModule::cancelTimers(jsi::Runtime &, double world) {
|
|
323
|
+
return engine_world_cancel_timers(find(world));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
double NayanEngineModule::scoreboard(jsi::Runtime &, double world, double op, double a, double b) {
|
|
327
|
+
return engine_world_scoreboard(find(world), op >= 0 ? static_cast<uint32_t>(op) : UINT32_MAX, a, b);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
jsi::Object NayanEngineModule::getScoreboard(jsi::Runtime &rt, double world) {
|
|
331
|
+
auto w = owner(world);
|
|
332
|
+
return external(rt, w, engine_world_scoreboard_state(w.get()), ENGINE_SCOREBOARD_LEN * sizeof(double));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
double NayanEngineModule::count(jsi::Runtime &, double world) {
|
|
336
|
+
return engine_world_count(find(world));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
jsi::Object NayanEngineModule::getMatrices(jsi::Runtime &rt, double world) {
|
|
340
|
+
auto w = owner(world);
|
|
341
|
+
return external(rt, w, engine_world_matrices(w.get()), static_cast<size_t>(engine_world_capacity(w.get())) * 16 * sizeof(float));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
jsi::Object NayanEngineModule::getColors(jsi::Runtime &rt, double world) {
|
|
345
|
+
auto w = owner(world);
|
|
346
|
+
return external(rt, w, engine_world_colors(w.get()), static_cast<size_t>(engine_world_capacity(w.get())) * 4 * sizeof(float));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
jsi::Object NayanEngineModule::getRegions(jsi::Runtime &rt, double world) {
|
|
350
|
+
auto w = owner(world);
|
|
351
|
+
return external(rt, w, engine_world_regions(w.get()), static_cast<size_t>(engine_world_capacity(w.get())) * 4 * sizeof(float));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
jsi::Object NayanEngineModule::getRanges(jsi::Runtime &rt, double world) {
|
|
355
|
+
auto w = owner(world);
|
|
356
|
+
return external(rt, w, engine_world_ranges(w.get()), ENGINE_MAX_MESHES * 4 * sizeof(uint32_t));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
jsi::Object NayanEngineModule::getDone(jsi::Runtime &rt, double world) {
|
|
360
|
+
auto w = owner(world);
|
|
361
|
+
size_t room = static_cast<size_t>(engine_world_capacity(w.get())) * ENGINE_DONE_PER_ENTITY + 64;
|
|
362
|
+
return external(rt, w, engine_world_done(w.get()), room * sizeof(uint32_t));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
double NayanEngineModule::doneLength(jsi::Runtime &, double world) {
|
|
366
|
+
return engine_world_done_len(find(world));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
jsi::Object NayanEngineModule::getEvents(jsi::Runtime &rt, double world) {
|
|
370
|
+
auto w = owner(world);
|
|
371
|
+
return external(rt, w, engine_world_events(w.get()), ENGINE_MAX_EVENTS * ENGINE_EVENT_STRIDE * sizeof(uint32_t));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
double NayanEngineModule::eventLength(jsi::Runtime &, double world) {
|
|
375
|
+
return engine_world_event_len(find(world));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
jsi::Object NayanEngineModule::getScratch(jsi::Runtime &rt, double world) {
|
|
379
|
+
auto w = owner(world);
|
|
380
|
+
return external(rt, w, engine_world_scratch(w.get()), 16 * sizeof(float));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
void NayanEngineModule::setListener(jsi::Runtime &, double world, double entity) {
|
|
384
|
+
engine_world_set_listener(find(world), id(entity));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
jsi::String NayanEngineModule::modelRig(jsi::Runtime &rt, double mesh) {
|
|
388
|
+
std::string metadata(engine_model_rig(id(mesh), nullptr, 0) + 1, '\0');
|
|
389
|
+
metadata.resize(engine_model_rig(id(mesh), reinterpret_cast<uint8_t *>(metadata.data()), metadata.size()));
|
|
390
|
+
return jsi::String::createFromUtf8(rt, metadata);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
bool NayanEngineModule::playClip(jsi::Runtime &rt, double world, double entity, jsi::String clip, bool loop, double speed, double fade, double time) {
|
|
394
|
+
std::string name = clip.utf8(rt);
|
|
395
|
+
return engine_world_play_clip(find(world), id(entity), reinterpret_cast<const uint8_t *>(name.data()), name.size(), loop ? 1 : 0, speed, fade, time) != 0;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
bool NayanEngineModule::stopClip(jsi::Runtime &, double world, double entity, bool reset) {
|
|
399
|
+
return engine_world_stop_clip(find(world), id(entity), reset ? 1 : 0) != 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
bool NayanEngineModule::skinPoints(jsi::Runtime &rt, double world, double entity, jsi::Object vertices, jsi::Object output, double after) {
|
|
403
|
+
auto indices = fileData(rt, vertices, "skinPoints");
|
|
404
|
+
auto out = fileData(rt, output, "skinPoints");
|
|
405
|
+
size_t count = indices.size(rt) / sizeof(uint32_t);
|
|
406
|
+
if (out.size(rt) / sizeof(float) / 3 < count) return false;
|
|
407
|
+
return engine_world_skin_points(find(world), id(entity), reinterpret_cast<const uint32_t *>(indices.data(rt)), count, reinterpret_cast<float *>(out.data(rt)), after) != 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
jsi::Object NayanEngineModule::cacheRead(jsi::Runtime &rt, jsi::String key) {
|
|
411
|
+
const auto text = key.utf8(rt);
|
|
412
|
+
auto raw = engine_cache_read(reinterpret_cast<const uint8_t *>(text.data()), text.size());
|
|
413
|
+
if (raw == nullptr) return jsi::ArrayBuffer(rt, std::make_shared<OwnedBuffer>(0));
|
|
414
|
+
std::shared_ptr<void> owner(raw, [](void *value) { engine_cache_free(static_cast<EngineCacheBlob *>(value)); });
|
|
415
|
+
return external(rt, std::move(owner), engine_cache_data(raw), engine_cache_size(raw));
|
|
416
|
+
}
|
|
417
|
+
bool NayanEngineModule::cacheWrite(jsi::Runtime &rt, jsi::String key, jsi::Object data) {
|
|
418
|
+
const auto text = key.utf8(rt); auto bytes = fileData(rt, data, "cacheWrite");
|
|
419
|
+
return engine_cache_write(reinterpret_cast<const uint8_t *>(text.data()), text.size(), bytes.data(rt), bytes.size(rt)) != 0;
|
|
420
|
+
}
|
|
421
|
+
bool NayanEngineModule::cacheRemove(jsi::Runtime &rt, jsi::String key) {
|
|
422
|
+
const auto text = key.utf8(rt);
|
|
423
|
+
return engine_cache_remove(reinterpret_cast<const uint8_t *>(text.data()), text.size()) != 0;
|
|
424
|
+
}
|
|
425
|
+
bool NayanEngineModule::cacheClear(jsi::Runtime &) { return engine_cache_clear() != 0; }
|
|
426
|
+
double NayanEngineModule::shapePrepare(jsi::Runtime &rt, jsi::Object vertices, jsi::Object indices, jsi::String options) {
|
|
427
|
+
const auto text = options.utf8(rt); auto v = fileData(rt, vertices, "shapePrepare"); auto i = fileData(rt, indices, "shapePrepare");
|
|
428
|
+
return engine_shape_prepare(reinterpret_cast<const float *>(v.data(rt)), v.size(rt)/4,
|
|
429
|
+
reinterpret_cast<const uint32_t *>(i.data(rt)), i.size(rt)/4, reinterpret_cast<const uint8_t *>(text.data()), text.size());
|
|
430
|
+
}
|
|
431
|
+
double NayanEngineModule::solidPrepare(jsi::Runtime &rt, jsi::String recipe, jsi::String options) {
|
|
432
|
+
const auto r = recipe.utf8(rt); const auto o = options.utf8(rt);
|
|
433
|
+
return engine_solid_prepare(reinterpret_cast<const uint8_t *>(r.data()), r.size(), reinterpret_cast<const uint8_t *>(o.data()), o.size());
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
double NayanEngineModule::modelLoad(jsi::Runtime &rt, jsi::Object data, bool center, double fit) {
|
|
437
|
+
jsi::ArrayBuffer buffer = fileData(rt, data, "modelLoad");
|
|
438
|
+
return engine_model_load(buffer.data(rt), buffer.size(rt), center ? 1 : 0, static_cast<float>(fit)); // copied
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
jsi::Object NayanEngineModule::modelVertices(jsi::Runtime &rt, double mesh) {
|
|
442
|
+
uint32_t m = id(mesh);
|
|
443
|
+
return external(rt, nullptr, engine_model_vertices(m), static_cast<size_t>(engine_model_vertex_count(m)) * 11 * sizeof(float));
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
jsi::Object NayanEngineModule::modelIndices(jsi::Runtime &rt, double mesh) {
|
|
447
|
+
uint32_t m = id(mesh);
|
|
448
|
+
return external(rt, nullptr, engine_model_indices(m), static_cast<size_t>(engine_model_index_count(m)) * sizeof(uint32_t));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
jsi::Array NayanEngineModule::modelSize(jsi::Runtime &rt, double mesh) {
|
|
452
|
+
float size[3] = {0, 0, 0};
|
|
453
|
+
engine_model_size(id(mesh), size);
|
|
454
|
+
return jsi::Array::createWithElements(rt, size[0], size[1], size[2]);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
double NayanEngineModule::modelTexture(jsi::Runtime &, double mesh) {
|
|
458
|
+
return engine_model_texture(id(mesh));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
double NayanEngineModule::meshAlias(jsi::Runtime &, double base) {
|
|
462
|
+
return engine_mesh_alias(id(base));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
double NayanEngineModule::meshCreate(jsi::Runtime &rt, jsi::Object vertices, jsi::Object indices) {
|
|
466
|
+
jsi::ArrayBuffer v = fileData(rt, vertices, "meshCreate");
|
|
467
|
+
jsi::ArrayBuffer i = fileData(rt, indices, "meshCreate");
|
|
468
|
+
return engine_mesh_create(
|
|
469
|
+
reinterpret_cast<const float *>(v.data(rt)), v.size(rt) / (11 * sizeof(float)),
|
|
470
|
+
reinterpret_cast<const uint32_t *>(i.data(rt)), i.size(rt) / sizeof(uint32_t)); // copied
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
jsi::Object NayanEngineModule::pathExtrude(jsi::Runtime &rt, jsi::Object points, jsi::Array counts, double depth, bool evenOdd) {
|
|
474
|
+
jsi::ArrayBuffer p = fileData(rt, points, "pathExtrude");
|
|
475
|
+
size_t available = p.size(rt) / (2 * sizeof(float));
|
|
476
|
+
std::vector<uint32_t> n(counts.size(rt));
|
|
477
|
+
size_t total = 0;
|
|
478
|
+
for (size_t k = 0; k < n.size(); k++) {
|
|
479
|
+
double c = counts.getValueAtIndex(rt, k).asNumber();
|
|
480
|
+
n[k] = c >= 0 && c <= static_cast<double>(UINT32_MAX) ? static_cast<uint32_t>(c) : 0;
|
|
481
|
+
total += n[k];
|
|
482
|
+
}
|
|
483
|
+
if (total > available) {
|
|
484
|
+
throw jsi::JSError(rt, "NayanEngine.pathExtrude: the counts add up to more points than given");
|
|
485
|
+
}
|
|
486
|
+
size_t floats = engine_path_extrude(reinterpret_cast<const float *>(p.data(rt)), n.data(), n.size(), static_cast<float>(depth), evenOdd ? 1 : 0);
|
|
487
|
+
auto out = std::make_shared<OwnedBuffer>(floats * sizeof(float));
|
|
488
|
+
engine_path_extrude_copy(reinterpret_cast<float *>(out->data()), floats);
|
|
489
|
+
return jsi::Object(jsi::ArrayBuffer(rt, std::move(out)));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
void NayanEngineModule::geometrySmoothNormals(jsi::Runtime &rt, jsi::Object vertices, jsi::Object indices) {
|
|
493
|
+
jsi::ArrayBuffer v = fileData(rt, vertices, "geometrySmoothNormals");
|
|
494
|
+
jsi::ArrayBuffer i = fileData(rt, indices, "geometrySmoothNormals");
|
|
495
|
+
engine_geometry_smooth_normals(
|
|
496
|
+
reinterpret_cast<float *>(v.data(rt)), v.size(rt) / (11 * sizeof(float)),
|
|
497
|
+
reinterpret_cast<const uint32_t *>(i.data(rt)), i.size(rt) / sizeof(uint32_t));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
jsi::Object NayanEngineModule::geometrySolid(jsi::Runtime &rt, jsi::String recipe) {
|
|
501
|
+
const auto json = recipe.utf8(rt);
|
|
502
|
+
return geometryResult(rt, engine_geometry_solid(reinterpret_cast<const uint8_t *>(json.data()), json.size()));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
jsi::Object NayanEngineModule::geometryOptimize(jsi::Runtime &rt, jsi::Object vertices, jsi::Object indices, double ratio, double error, bool lockBorders) {
|
|
506
|
+
auto v = fileData(rt, vertices, "geometryOptimize");
|
|
507
|
+
auto i = fileData(rt, indices, "geometryOptimize");
|
|
508
|
+
if (v.size(rt) % (11 * sizeof(float)) != 0 || i.size(rt) % (3 * sizeof(uint32_t)) != 0) {
|
|
509
|
+
throw jsi::JSError(rt, "NayanEngine.geometryOptimize: incomplete vertices or triangles");
|
|
510
|
+
}
|
|
511
|
+
return geometryResult(rt, engine_geometry_optimize(reinterpret_cast<const float *>(v.data(rt)), v.size(rt) / sizeof(float),
|
|
512
|
+
reinterpret_cast<const uint32_t *>(i.data(rt)), i.size(rt) / sizeof(uint32_t), static_cast<float>(ratio), static_cast<float>(error), lockBorders ? 1 : 0));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
void NayanEngineModule::geometryFaceOutward(jsi::Runtime &rt, jsi::Object vertices, jsi::Object indices) {
|
|
516
|
+
jsi::ArrayBuffer v = fileData(rt, vertices, "geometryFaceOutward");
|
|
517
|
+
jsi::ArrayBuffer i = fileData(rt, indices, "geometryFaceOutward");
|
|
518
|
+
engine_geometry_face_outward(
|
|
519
|
+
reinterpret_cast<const float *>(v.data(rt)), v.size(rt) / (11 * sizeof(float)),
|
|
520
|
+
reinterpret_cast<uint32_t *>(i.data(rt)), i.size(rt) / sizeof(uint32_t));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
void NayanEngineModule::geometryPlace(
|
|
524
|
+
jsi::Runtime &rt,
|
|
525
|
+
jsi::Object vertices,
|
|
526
|
+
jsi::Object indices,
|
|
527
|
+
jsi::Array placement,
|
|
528
|
+
double first,
|
|
529
|
+
jsi::Object outVertices,
|
|
530
|
+
double vertexOffset,
|
|
531
|
+
jsi::Object outIndices,
|
|
532
|
+
double indexOffset) {
|
|
533
|
+
jsi::ArrayBuffer v = fileData(rt, vertices, "geometryPlace");
|
|
534
|
+
jsi::ArrayBuffer i = fileData(rt, indices, "geometryPlace");
|
|
535
|
+
jsi::ArrayBuffer ov = fileData(rt, outVertices, "geometryPlace");
|
|
536
|
+
jsi::ArrayBuffer oi = fileData(rt, outIndices, "geometryPlace");
|
|
537
|
+
if (placement.size(rt) < 13) {
|
|
538
|
+
throw jsi::JSError(rt, "NayanEngine.geometryPlace: placement needs 13 numbers");
|
|
539
|
+
}
|
|
540
|
+
float p[13];
|
|
541
|
+
for (size_t k = 0; k < 13; k++) p[k] = static_cast<float>(placement.getValueAtIndex(rt, k).asNumber());
|
|
542
|
+
size_t vertexCount = v.size(rt) / (11 * sizeof(float));
|
|
543
|
+
size_t indexCount = i.size(rt) / sizeof(uint32_t);
|
|
544
|
+
size_t vo = vertexOffset > 0 ? static_cast<size_t>(vertexOffset) : 0; // floats
|
|
545
|
+
size_t io = indexOffset > 0 ? static_cast<size_t>(indexOffset) : 0;
|
|
546
|
+
if (vo + vertexCount * 11 > ov.size(rt) / sizeof(float) || io + indexCount > oi.size(rt) / sizeof(uint32_t)) {
|
|
547
|
+
throw jsi::JSError(rt, "NayanEngine.geometryPlace: the output is too small");
|
|
548
|
+
}
|
|
549
|
+
engine_geometry_place(
|
|
550
|
+
reinterpret_cast<const float *>(v.data(rt)), vertexCount, reinterpret_cast<const uint32_t *>(i.data(rt)), indexCount, p,
|
|
551
|
+
first > 0 ? static_cast<uint32_t>(first) : 0, reinterpret_cast<float *>(ov.data(rt)) + vo, reinterpret_cast<uint32_t *>(oi.data(rt)) + io);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
double NayanEngineModule::textureLoad(jsi::Runtime &rt, jsi::Object data) {
|
|
555
|
+
jsi::ArrayBuffer buffer = fileData(rt, data, "textureLoad");
|
|
556
|
+
return engine_texture_load(buffer.data(rt), buffer.size(rt)); // decoded and copied
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
jsi::Object NayanEngineModule::texturePixels(jsi::Runtime &rt, double texture) {
|
|
560
|
+
uint32_t size[2] = {0, 0};
|
|
561
|
+
engine_texture_size(id(texture), size);
|
|
562
|
+
return external(rt, nullptr, engine_texture_pixels(id(texture)), static_cast<size_t>(size[0]) * size[1] * 4);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
jsi::Array NayanEngineModule::textureSize(jsi::Runtime &rt, double texture) {
|
|
566
|
+
uint32_t size[2] = {0, 0};
|
|
567
|
+
engine_texture_size(id(texture), size);
|
|
568
|
+
return jsi::Array::createWithElements(rt, static_cast<double>(size[0]), static_cast<double>(size[1]));
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
double NayanEngineModule::fontLoad(jsi::Runtime &rt, jsi::Object data, double depth, jsi::String chars, double weight) {
|
|
572
|
+
jsi::ArrayBuffer buffer = fileData(rt, data, "fontLoad");
|
|
573
|
+
std::string utf8 = chars.utf8(rt);
|
|
574
|
+
return engine_font_load(buffer.data(rt), buffer.size(rt), static_cast<float>(depth), utf8.data(), utf8.size(), static_cast<float>(weight));
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
jsi::Array NayanEngineModule::fontGlyphs(jsi::Runtime &rt, double font) {
|
|
578
|
+
uint32_t f = id(font);
|
|
579
|
+
const float *glyphs = engine_font_glyphs(f);
|
|
580
|
+
size_t n = glyphs == nullptr ? 0 : engine_font_glyph_floats(f);
|
|
581
|
+
jsi::Array out(rt, n + 1);
|
|
582
|
+
for (size_t i = 0; i < n; i++) {
|
|
583
|
+
out.setValueAtIndex(rt, i, static_cast<double>(glyphs[i]));
|
|
584
|
+
}
|
|
585
|
+
out.setValueAtIndex(rt, n, static_cast<double>(engine_font_cap_height(f)));
|
|
586
|
+
return out;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
jsi::String NayanEngineModule::loadError(jsi::Runtime &rt) {
|
|
590
|
+
// Sized to the full message: truncating could split a UTF-8 sequence.
|
|
591
|
+
std::string message(engine_load_error(nullptr, 0) + 1, '\0');
|
|
592
|
+
message.resize(engine_load_error(message.data(), message.size()));
|
|
593
|
+
return jsi::String::createFromUtf8(rt, message);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
void NayanEngineModule::generateBuiltinMeshes(jsi::Runtime &) {
|
|
597
|
+
engine_generate_builtin_meshes();
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
void NayanEngineModule::renderWarmUp(jsi::Runtime &) {
|
|
601
|
+
engine_render_warm_up();
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
jsi::Object NayanEngineModule::renderMeshVertices(jsi::Runtime &rt, double mesh) {
|
|
605
|
+
uint32_t m = id(mesh);
|
|
606
|
+
size_t vertexCount = engine_render_mesh_vertex_count(m);
|
|
607
|
+
size_t floats = vertexCount * 11;
|
|
608
|
+
auto buf = std::make_shared<OwnedBuffer>(floats * sizeof(float));
|
|
609
|
+
engine_render_mesh_vertices(m, reinterpret_cast<float *>(buf->data()), floats);
|
|
610
|
+
return jsi::Object(jsi::ArrayBuffer(rt, std::move(buf)));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
jsi::Object NayanEngineModule::renderMeshIndices(jsi::Runtime &rt, double mesh) {
|
|
614
|
+
uint32_t m = id(mesh);
|
|
615
|
+
size_t indexCount = engine_render_mesh_index_count(m);
|
|
616
|
+
auto buf = std::make_shared<OwnedBuffer>(indexCount * sizeof(uint32_t));
|
|
617
|
+
engine_render_mesh_indices(m, reinterpret_cast<uint32_t *>(buf->data()), indexCount);
|
|
618
|
+
return jsi::Object(jsi::ArrayBuffer(rt, std::move(buf)));
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
void NayanEngineModule::renderMesh(
|
|
622
|
+
jsi::Runtime &rt, double mesh, jsi::Object vertices, jsi::Object indices, double texture, double shine) {
|
|
623
|
+
jsi::ArrayBuffer v = fileData(rt, vertices, "renderMesh");
|
|
624
|
+
jsi::ArrayBuffer i = fileData(rt, indices, "renderMesh");
|
|
625
|
+
engine_render_mesh(
|
|
626
|
+
id(mesh), reinterpret_cast<const float *>(v.data(rt)), v.size(rt) / (11 * sizeof(float)),
|
|
627
|
+
reinterpret_cast<const uint32_t *>(i.data(rt)), i.size(rt) / sizeof(uint32_t),
|
|
628
|
+
texture >= 0 ? static_cast<int32_t>(texture) : -1, static_cast<float>(shine)); // copied
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
double NayanEngineModule::renderFrame(
|
|
632
|
+
jsi::Runtime &rt,
|
|
633
|
+
double surface,
|
|
634
|
+
jsi::Object frame,
|
|
635
|
+
jsi::Object matrices,
|
|
636
|
+
jsi::Object colors,
|
|
637
|
+
jsi::Object regions,
|
|
638
|
+
jsi::Object ranges,
|
|
639
|
+
double count,
|
|
640
|
+
jsi::Object viewProj,
|
|
641
|
+
double world) {
|
|
642
|
+
jsi::ArrayBuffer f = fileData(rt, frame, "renderFrame");
|
|
643
|
+
jsi::ArrayBuffer m = fileData(rt, matrices, "renderFrame");
|
|
644
|
+
jsi::ArrayBuffer c = fileData(rt, colors, "renderFrame");
|
|
645
|
+
jsi::ArrayBuffer g = fileData(rt, regions, "renderFrame");
|
|
646
|
+
jsi::ArrayBuffer r = fileData(rt, ranges, "renderFrame");
|
|
647
|
+
jsi::ArrayBuffer out = fileData(rt, viewProj, "renderFrame");
|
|
648
|
+
// The instance count every buffer has room for.
|
|
649
|
+
size_t capacity = std::min({m.size(rt) / (16 * sizeof(float)), c.size(rt) / (4 * sizeof(float)), g.size(rt) / (4 * sizeof(float))});
|
|
650
|
+
size_t n = count > 0 ? std::min(static_cast<size_t>(count), capacity) : 0;
|
|
651
|
+
return engine_render_frame(
|
|
652
|
+
static_cast<int32_t>(surface), reinterpret_cast<const double *>(f.data(rt)), f.size(rt) / sizeof(double),
|
|
653
|
+
reinterpret_cast<const float *>(m.data(rt)), reinterpret_cast<const float *>(c.data(rt)),
|
|
654
|
+
reinterpret_cast<const float *>(g.data(rt)), capacity, reinterpret_cast<const uint32_t *>(r.data(rt)),
|
|
655
|
+
r.size(rt) / sizeof(uint32_t), n, out.size(rt) >= 16 * sizeof(float) ? reinterpret_cast<float *>(out.data(rt)) : nullptr, find(world));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
void NayanEngineModule::renderOverlay(
|
|
659
|
+
jsi::Runtime &rt,
|
|
660
|
+
double surface,
|
|
661
|
+
jsi::Object matrices,
|
|
662
|
+
jsi::Object colors,
|
|
663
|
+
jsi::Object regions,
|
|
664
|
+
jsi::Object ranges,
|
|
665
|
+
double count,
|
|
666
|
+
double width,
|
|
667
|
+
double height) {
|
|
668
|
+
jsi::ArrayBuffer m = fileData(rt, matrices, "renderOverlay");
|
|
669
|
+
jsi::ArrayBuffer c = fileData(rt, colors, "renderOverlay");
|
|
670
|
+
jsi::ArrayBuffer g = fileData(rt, regions, "renderOverlay");
|
|
671
|
+
jsi::ArrayBuffer r = fileData(rt, ranges, "renderOverlay");
|
|
672
|
+
size_t capacity = std::min({m.size(rt) / (16 * sizeof(float)), c.size(rt) / (4 * sizeof(float)), g.size(rt) / (4 * sizeof(float))});
|
|
673
|
+
size_t n = count > 0 ? std::min(static_cast<size_t>(count), capacity) : 0;
|
|
674
|
+
engine_render_overlay(
|
|
675
|
+
static_cast<int32_t>(surface), reinterpret_cast<const float *>(m.data(rt)), reinterpret_cast<const float *>(c.data(rt)),
|
|
676
|
+
reinterpret_cast<const float *>(g.data(rt)), capacity, reinterpret_cast<const uint32_t *>(r.data(rt)), r.size(rt) / sizeof(uint32_t), n,
|
|
677
|
+
static_cast<float>(width), static_cast<float>(height));
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
jsi::String NayanEngineModule::renderError(jsi::Runtime &rt) {
|
|
681
|
+
std::string message(engine_render_error(nullptr, 0) + 1, '\0');
|
|
682
|
+
message.resize(engine_render_error(message.data(), message.size()));
|
|
683
|
+
return jsi::String::createFromUtf8(rt, message);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
jsi::String NayanEngineModule::renderBackend(jsi::Runtime &rt) {
|
|
687
|
+
char name[16] = {0};
|
|
688
|
+
engine_render_backend(name, sizeof(name));
|
|
689
|
+
return jsi::String::createFromAscii(rt, name);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
double NayanEngineModule::drawingCreate(jsi::Runtime &, double width, double height, double ratio) {
|
|
693
|
+
const int document = engine_drawing_create(width, height, ratio);
|
|
694
|
+
if (document >= 0) drawings_.insert(document);
|
|
695
|
+
return document;
|
|
696
|
+
}
|
|
697
|
+
jsi::String NayanEngineModule::drawingCommand(jsi::Runtime &rt, double document, jsi::String command) {
|
|
698
|
+
if (!(document >= 0 && document <= INT32_MAX) || document != static_cast<int32_t>(document)) throw jsi::JSError(rt, "Invalid drawing identifier");
|
|
699
|
+
const auto text = command.utf8(rt);
|
|
700
|
+
std::unique_ptr<char, decltype(&engine_drawing_result_free)> result(
|
|
701
|
+
engine_drawing_command(static_cast<int32_t>(document), reinterpret_cast<const uint8_t *>(text.data()), text.size()), engine_drawing_result_free);
|
|
702
|
+
if (!result) throw jsi::JSError(rt, "Drawing command failed");
|
|
703
|
+
return jsi::String::createFromUtf8(rt, result.get());
|
|
704
|
+
}
|
|
705
|
+
void NayanEngineModule::drawingDestroy(jsi::Runtime &, double document) {
|
|
706
|
+
if (!(document >= 0 && document <= INT32_MAX) || document != static_cast<int32_t>(document)) return;
|
|
707
|
+
engine_drawing_destroy(static_cast<int32_t>(document));
|
|
708
|
+
drawings_.erase(static_cast<int>(document));
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
double NayanEngineModule::audioLoad(jsi::Runtime &rt, jsi::Object data) {
|
|
712
|
+
jsi::ArrayBuffer buffer = fileData(rt, data, "audioLoad");
|
|
713
|
+
return engine_audio_load_wav(buffer.data(rt), buffer.size(rt)); // copied by the core
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
double NayanEngineModule::audioPlay(jsi::Runtime &, double sound, double volume, double pan, double pitch, bool loop) {
|
|
717
|
+
return static_cast<double>(engine_audio_play(id(sound), volume, pan, pitch, loop ? 1 : 0));
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
void NayanEngineModule::audioStop(jsi::Runtime &, double voice) {
|
|
721
|
+
if (voice >= 1 && voice <= 9007199254740992.0) {
|
|
722
|
+
engine_audio_stop(static_cast<uint64_t>(voice));
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
void NayanEngineModule::audioSetVolume(jsi::Runtime &, double volume) {
|
|
727
|
+
engine_audio_set_volume(volume);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
void NayanEngineModule::audioSetMuted(jsi::Runtime &, bool muted) {
|
|
731
|
+
engine_audio_set_muted(muted ? 1 : 0);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
bool NayanEngineModule::audioIsRunning(jsi::Runtime &) {
|
|
735
|
+
return engine_audio_is_running() != 0;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
bool NayanEngineModule::hapticsSupported(jsi::Runtime &) {
|
|
739
|
+
return engine_haptics_supported() != 0;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
void NayanEngineModule::hapticsPlay(jsi::Runtime &rt, jsi::Array taps, bool throttle) {
|
|
743
|
+
size_t n = taps.size(rt) / 3 * 3;
|
|
744
|
+
std::vector<float> values(n);
|
|
745
|
+
for (size_t i = 0; i < n; i++) {
|
|
746
|
+
jsi::Value v = taps.getValueAtIndex(rt, i);
|
|
747
|
+
values[i] = v.isNumber() ? static_cast<float>(v.asNumber()) : 0.0f;
|
|
748
|
+
}
|
|
749
|
+
engine_haptics_play(values.data(), static_cast<uint32_t>(n / 3), throttle ? 1 : 0);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
} // namespace facebook::react
|
|
753
|
+
|
|
754
|
+
#ifdef __ANDROID__
|
|
755
|
+
#include <android/native_window_jni.h>
|
|
756
|
+
|
|
757
|
+
#include <mutex>
|
|
758
|
+
#include <unordered_map>
|
|
759
|
+
|
|
760
|
+
// JNI for com.nayanui.engine.EngineSurfaceView: hands its Surface to the renderer. Called on the UI
|
|
761
|
+
// thread; the renderer draws from the JS thread and serializes both with its own lock.
|
|
762
|
+
namespace {
|
|
763
|
+
std::mutex windowsMutex;
|
|
764
|
+
std::unordered_map<int, ANativeWindow *> windows;
|
|
765
|
+
|
|
766
|
+
void releaseWindow(int surface) {
|
|
767
|
+
engine_render_detach(surface); // the renderer stops using the window before it's released
|
|
768
|
+
std::lock_guard<std::mutex> lock(windowsMutex);
|
|
769
|
+
auto it = windows.find(surface);
|
|
770
|
+
if (it != windows.end()) {
|
|
771
|
+
ANativeWindow_release(it->second);
|
|
772
|
+
windows.erase(it);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
} // namespace
|
|
776
|
+
|
|
777
|
+
extern "C" JNIEXPORT jboolean JNICALL
|
|
778
|
+
Java_com_nayanui_engine_EngineSurfaceView_nativeAttach(JNIEnv *env, jclass, jint surface, jobject javaSurface, jint width, jint height) {
|
|
779
|
+
ANativeWindow *window = ANativeWindow_fromSurface(env, javaSurface);
|
|
780
|
+
if (window == nullptr) {
|
|
781
|
+
return JNI_FALSE;
|
|
782
|
+
}
|
|
783
|
+
{
|
|
784
|
+
std::lock_guard<std::mutex> lock(windowsMutex);
|
|
785
|
+
auto it = windows.find(surface);
|
|
786
|
+
if (it != windows.end() && it->second == window) {
|
|
787
|
+
ANativeWindow_release(window); // same window: just a resize
|
|
788
|
+
window = it->second;
|
|
789
|
+
} else if (it != windows.end()) {
|
|
790
|
+
engine_render_detach(surface);
|
|
791
|
+
ANativeWindow_release(it->second);
|
|
792
|
+
it->second = window;
|
|
793
|
+
} else {
|
|
794
|
+
windows[surface] = window;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return engine_render_attach(surface, window, static_cast<uint32_t>(width), static_cast<uint32_t>(height)) == 1 ? JNI_TRUE : JNI_FALSE;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
extern "C" JNIEXPORT void JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDetach(JNIEnv *, jclass, jint surface) {
|
|
801
|
+
releaseWindow(surface);
|
|
802
|
+
}
|
|
803
|
+
extern "C" JNIEXPORT void JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDrawingPresent(JNIEnv *, jclass, jint drawing, jint surface, jfloat width, jfloat height, jint color) {
|
|
804
|
+
engine_drawing_present(drawing, surface, width, height, static_cast<uint32_t>(color));
|
|
805
|
+
}
|
|
806
|
+
extern "C" JNIEXPORT void JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDrawingTouch(JNIEnv *, jclass, jint drawing, jint phase, jfloat x, jfloat y, jfloat pressure) {
|
|
807
|
+
engine_drawing_touch(drawing, phase, x, y, pressure);
|
|
808
|
+
}
|
|
809
|
+
extern "C" JNIEXPORT void JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDrawingTransform(JNIEnv *, jclass, jint drawing, jfloat dx, jfloat dy, jfloat scale) {
|
|
810
|
+
engine_drawing_transform(drawing, dx, dy, scale);
|
|
811
|
+
}
|
|
812
|
+
extern "C" JNIEXPORT void JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDrawingInvalidate(JNIEnv *, jclass, jint drawing) {
|
|
813
|
+
engine_drawing_invalidate(drawing);
|
|
814
|
+
}
|
|
815
|
+
#endif
|
|
816
|
+
|
|
817
|
+
#ifdef __ANDROID__
|
|
818
|
+
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_nayanui_engine_EngineSurfaceView_nativeDrawingEvent(JNIEnv *env, jclass, jint drawing) {
|
|
819
|
+
char *event = engine_drawing_take_event(drawing);
|
|
820
|
+
if (event == nullptr) return nullptr;
|
|
821
|
+
const size_t length = std::strlen(event);
|
|
822
|
+
jbyteArray result = env->NewByteArray(static_cast<jsize>(length));
|
|
823
|
+
if (result != nullptr) env->SetByteArrayRegion(result, 0, static_cast<jsize>(length), reinterpret_cast<const jbyte *>(event));
|
|
824
|
+
engine_drawing_result_free(event);
|
|
825
|
+
return result;
|
|
826
|
+
}
|
|
827
|
+
#endif
|