@nayan-ui/engine 1.0.0-beta.5 → 1.0.0-beta.6
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/README.md +95 -4
- package/lib/module/assets/ProceduralCache.js +5 -0
- package/lib/module/assets/loft.js +15 -63
- package/lib/module/assets/procedural.js +500 -0
- package/lib/module/assets/shape.js +147 -245
- package/lib/module/assets/texture.js +65 -0
- package/lib/module/drawing/DrawingDocument.js +1 -1
- package/lib/module/index.js +4 -1
- package/lib/module/media/audio-worklet.js +27 -0
- package/lib/module/media/audio.js +20 -0
- package/lib/module/media/input.web.js +107 -0
- package/lib/module/media/microphone.js +89 -0
- package/lib/module/media/speech.js +80 -0
- package/lib/module/media/speechPlatform.js +12 -0
- package/lib/module/media/speechPlatform.web.js +16 -0
- package/lib/module/native/BrowserEngine.js +122 -0
- package/lib/module/native/NativeNayanEngine.web.js +2 -0
- package/lib/module/render/GameView.js +45 -13
- package/lib/module/render/quality.js +151 -17
- package/lib/module/world/World.js +63 -0
- package/lib/typescript/src/assets/ProceduralCache.d.ts +2 -0
- package/lib/typescript/src/assets/loft.d.ts +3 -1
- package/lib/typescript/src/assets/procedural.d.ts +394 -0
- package/lib/typescript/src/assets/shape.d.ts +13 -7
- package/lib/typescript/src/assets/texture.d.ts +63 -0
- package/lib/typescript/src/index.d.ts +8 -2
- package/lib/typescript/src/media/audio.d.ts +13 -0
- package/lib/typescript/src/media/input.web.d.ts +4 -0
- package/lib/typescript/src/media/microphone.d.ts +51 -0
- package/lib/typescript/src/media/speech.d.ts +38 -0
- package/lib/typescript/src/media/speechPlatform.d.ts +5 -0
- package/lib/typescript/src/media/speechPlatform.web.d.ts +5 -0
- package/lib/typescript/src/native/EngineBridge.d.ts +7 -1
- package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +72 -0
- package/lib/typescript/src/render/GameView.d.ts +30 -3
- package/lib/typescript/src/render/quality.d.ts +54 -2
- package/lib/typescript/src/types.d.ts +9 -2
- package/lib/typescript/src/world/World.d.ts +16 -0
- package/lib/typescript/src/world/types.d.ts +8 -0
- package/lib/web/audio-worklet.js +27 -0
- package/lib/web/engine_core_bg.wasm +0 -0
- package/lib/web/index.js +1181 -422
- package/lib/web/types/src/assets/ProceduralCache.d.ts +2 -0
- package/lib/web/types/src/assets/loft.d.ts +3 -1
- package/lib/web/types/src/assets/procedural.d.ts +393 -0
- package/lib/web/types/src/assets/shape.d.ts +13 -7
- package/lib/web/types/src/assets/texture.d.ts +63 -0
- package/lib/web/types/src/index.d.ts +8 -2
- package/lib/web/types/src/media/audio.d.ts +13 -0
- package/lib/web/types/src/media/input.d.ts +3 -0
- package/lib/web/types/src/media/microphone.d.ts +50 -0
- package/lib/web/types/src/media/speech.d.ts +37 -0
- package/lib/web/types/src/media/speechPlatform.d.ts +4 -0
- package/lib/web/types/src/native/EngineBridge.d.ts +7 -1
- package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +72 -0
- package/lib/web/types/src/render/GameView.d.ts +30 -3
- package/lib/web/types/src/render/quality.d.ts +54 -2
- package/lib/web/types/src/types.d.ts +9 -2
- package/lib/web/types/src/world/World.d.ts +16 -0
- package/lib/web/types/src/world/types.d.ts +8 -0
- package/native/android/src/main/AndroidManifest.xml +10 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineMicrophone.java +60 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSpeech.java +28 -0
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +1 -0
- package/native/android/src/main/java/com/nayanui/engine/NayanEnginePackage.java +2 -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/engine_core.h +63 -1
- package/native/cpp/NayanEngineModule.cpp +296 -0
- package/native/cpp/NayanEngineModule.h +40 -0
- package/native/cpp/generated/NayanEngineSpecJSI.h +397 -0
- package/package.json +1 -1
- package/src/native/spec/NativeNayanEngine.ts +77 -0
package/lib/web/index.js
CHANGED
|
@@ -53,6 +53,12 @@ function restore_asset_record(name, bytes) {
|
|
|
53
53
|
const ret = wasm.restore_asset_record(ptr0, len0, ptr1, len1);
|
|
54
54
|
return ret !== 0;
|
|
55
55
|
}
|
|
56
|
+
function speech_request(command) {
|
|
57
|
+
const ptr0 = passStringToWasm0(command, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
58
|
+
const len0 = WASM_VECTOR_LEN;
|
|
59
|
+
const ret = wasm.speech_request(ptr0, len0);
|
|
60
|
+
return takeObject(ret);
|
|
61
|
+
}
|
|
56
62
|
function __wbg_get_imports() {
|
|
57
63
|
const import0 = {
|
|
58
64
|
__proto__: null,
|
|
@@ -238,6 +244,9 @@ function __wbg_get_imports() {
|
|
|
238
244
|
return addHeapObject(ret);
|
|
239
245
|
}, arguments);
|
|
240
246
|
},
|
|
247
|
+
__wbg_cancel_fa9c526b1bfea1fa: function(arg0) {
|
|
248
|
+
getObject(arg0).cancel();
|
|
249
|
+
},
|
|
241
250
|
__wbg_clearBufferfv_05f7fc7252e623eb: function(arg0, arg1, arg2, arg3, arg4) {
|
|
242
251
|
getObject(arg0).clearBufferfv(arg1 >>> 0, arg2, getArrayF32FromWasm0(arg3, arg4));
|
|
243
252
|
},
|
|
@@ -762,6 +771,10 @@ function __wbg_get_imports() {
|
|
|
762
771
|
const ret = getObject(arg0).getUniformLocation(getObject(arg1), getStringFromWasm0(arg2, arg3));
|
|
763
772
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
764
773
|
},
|
|
774
|
+
__wbg_getVoices_a94654c567778a75: function(arg0) {
|
|
775
|
+
const ret = getObject(arg0).getVoices();
|
|
776
|
+
return addHeapObject(ret);
|
|
777
|
+
},
|
|
765
778
|
__wbg_get_31af05bd4842a84f: function() {
|
|
766
779
|
return handleError(function(arg0, arg1) {
|
|
767
780
|
const ret = Reflect.get(getObject(arg0), getObject(arg1));
|
|
@@ -862,6 +875,13 @@ function __wbg_get_imports() {
|
|
|
862
875
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
863
876
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
864
877
|
},
|
|
878
|
+
__wbg_lang_124ac9807c8fd7c7: function(arg0, arg1) {
|
|
879
|
+
const ret = getObject(arg1).lang;
|
|
880
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
881
|
+
const len1 = WASM_VECTOR_LEN;
|
|
882
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
883
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
884
|
+
},
|
|
865
885
|
__wbg_length_7f3c00c40364105e: function(arg0) {
|
|
866
886
|
const ret = getObject(arg0).length;
|
|
867
887
|
return ret;
|
|
@@ -1025,6 +1045,13 @@ function __wbg_get_imports() {
|
|
|
1025
1045
|
const ret = getObject(arg0).minUniformBufferOffsetAlignment;
|
|
1026
1046
|
return ret;
|
|
1027
1047
|
},
|
|
1048
|
+
__wbg_name_73552c55bcab8bef: function(arg0, arg1) {
|
|
1049
|
+
const ret = getObject(arg1).name;
|
|
1050
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
1051
|
+
const len1 = WASM_VECTOR_LEN;
|
|
1052
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
1053
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
1054
|
+
},
|
|
1028
1055
|
__wbg_navigator_2156486643462a87: function(arg0) {
|
|
1029
1056
|
const ret = getObject(arg0).navigator;
|
|
1030
1057
|
return addHeapObject(ret);
|
|
@@ -1037,6 +1064,24 @@ function __wbg_get_imports() {
|
|
|
1037
1064
|
const ret = new Uint8Array(getObject(arg0));
|
|
1038
1065
|
return addHeapObject(ret);
|
|
1039
1066
|
},
|
|
1067
|
+
__wbg_new_5502aad30c185fc8: function(arg0, arg1) {
|
|
1068
|
+
try {
|
|
1069
|
+
var state0 = { a: arg0, b: arg1 };
|
|
1070
|
+
var cb0 = (arg0, arg1) => {
|
|
1071
|
+
const a = state0.a;
|
|
1072
|
+
state0.a = 0;
|
|
1073
|
+
try {
|
|
1074
|
+
return __wasm_bindgen_func_elem_10645(a, state0.b, arg0, arg1);
|
|
1075
|
+
} finally {
|
|
1076
|
+
state0.a = a;
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
const ret = new Promise(cb0);
|
|
1080
|
+
return addHeapObject(ret);
|
|
1081
|
+
} finally {
|
|
1082
|
+
state0.a = 0;
|
|
1083
|
+
}
|
|
1084
|
+
},
|
|
1040
1085
|
__wbg_new_617a8cdb8bb1130e: function() {
|
|
1041
1086
|
const ret = new Object;
|
|
1042
1087
|
return addHeapObject(ret);
|
|
@@ -1066,7 +1111,7 @@ function __wbg_get_imports() {
|
|
|
1066
1111
|
const a = state0.a;
|
|
1067
1112
|
state0.a = 0;
|
|
1068
1113
|
try {
|
|
1069
|
-
return
|
|
1114
|
+
return __wasm_bindgen_func_elem_10645(a, state0.b, arg0, arg1);
|
|
1070
1115
|
} finally {
|
|
1071
1116
|
state0.a = a;
|
|
1072
1117
|
}
|
|
@@ -1081,6 +1126,12 @@ function __wbg_get_imports() {
|
|
|
1081
1126
|
const ret = new Uint8Array(arg0 >>> 0);
|
|
1082
1127
|
return addHeapObject(ret);
|
|
1083
1128
|
},
|
|
1129
|
+
__wbg_new_with_text_de120aa95bd08db1: function() {
|
|
1130
|
+
return handleError(function(arg0, arg1) {
|
|
1131
|
+
const ret = new SpeechSynthesisUtterance(getStringFromWasm0(arg0, arg1));
|
|
1132
|
+
return addHeapObject(ret);
|
|
1133
|
+
}, arguments);
|
|
1134
|
+
},
|
|
1084
1135
|
__wbg_now_aa4ccb83129e9e55: function() {
|
|
1085
1136
|
const ret = Date.now();
|
|
1086
1137
|
return ret;
|
|
@@ -1093,6 +1144,13 @@ function __wbg_get_imports() {
|
|
|
1093
1144
|
const ret = getObject(arg0).onSubmittedWorkDone();
|
|
1094
1145
|
return addHeapObject(ret);
|
|
1095
1146
|
},
|
|
1147
|
+
__wbg_pause_b7da1d13ff23f1f3: function(arg0) {
|
|
1148
|
+
getObject(arg0).pause();
|
|
1149
|
+
},
|
|
1150
|
+
__wbg_pending_decfa19ee64ef69d: function(arg0) {
|
|
1151
|
+
const ret = getObject(arg0).pending;
|
|
1152
|
+
return ret;
|
|
1153
|
+
},
|
|
1096
1154
|
__wbg_pixelStorei_af18e636b3e7b725: function(arg0, arg1, arg2) {
|
|
1097
1155
|
getObject(arg0).pixelStorei(arg1 >>> 0, arg2);
|
|
1098
1156
|
},
|
|
@@ -1177,6 +1235,9 @@ function __wbg_get_imports() {
|
|
|
1177
1235
|
const ret = Promise.resolve(getObject(arg0));
|
|
1178
1236
|
return addHeapObject(ret);
|
|
1179
1237
|
},
|
|
1238
|
+
__wbg_resume_8132df443cbde759: function(arg0) {
|
|
1239
|
+
getObject(arg0).resume();
|
|
1240
|
+
},
|
|
1180
1241
|
__wbg_samplerParameterf_2d62cb907392e2d6: function(arg0, arg1, arg2, arg3) {
|
|
1181
1242
|
getObject(arg0).samplerParameterf(getObject(arg1), arg2 >>> 0, arg3);
|
|
1182
1243
|
},
|
|
@@ -1206,6 +1267,12 @@ function __wbg_get_imports() {
|
|
|
1206
1267
|
__wbg_setPipeline_b6f981027e02cd16: function(arg0, arg1) {
|
|
1207
1268
|
getObject(arg0).setPipeline(getObject(arg1));
|
|
1208
1269
|
},
|
|
1270
|
+
__wbg_setTimeout_db7bbc18a17e152a: function() {
|
|
1271
|
+
return handleError(function(arg0, arg1, arg2) {
|
|
1272
|
+
const ret = getObject(arg0).setTimeout(getObject(arg1), arg2);
|
|
1273
|
+
return ret;
|
|
1274
|
+
}, arguments);
|
|
1275
|
+
},
|
|
1209
1276
|
__wbg_setVertexBuffer_6db3b60e99280744: function(arg0, arg1, arg2, arg3) {
|
|
1210
1277
|
getObject(arg0).setVertexBuffer(arg1 >>> 0, getObject(arg2), arg3);
|
|
1211
1278
|
},
|
|
@@ -1470,6 +1537,9 @@ function __wbg_get_imports() {
|
|
|
1470
1537
|
__wbg_set_label_ee172cd5f6a96961: function(arg0, arg1, arg2) {
|
|
1471
1538
|
getObject(arg0).label = getStringFromWasm0(arg1, arg2);
|
|
1472
1539
|
},
|
|
1540
|
+
__wbg_set_lang_fdb29fe7a7f6b538: function(arg0, arg1, arg2) {
|
|
1541
|
+
getObject(arg0).lang = getStringFromWasm0(arg1, arg2);
|
|
1542
|
+
},
|
|
1473
1543
|
__wbg_set_layout_454e3a091b390cd4: function(arg0, arg1) {
|
|
1474
1544
|
getObject(arg0).layout = getObject(arg1);
|
|
1475
1545
|
},
|
|
@@ -1554,6 +1624,9 @@ function __wbg_get_imports() {
|
|
|
1554
1624
|
__wbg_set_pass_op_3cf10feb3d76ab97: function(arg0, arg1) {
|
|
1555
1625
|
getObject(arg0).passOp = __wbindgen_enum_GpuStencilOperation[arg1];
|
|
1556
1626
|
},
|
|
1627
|
+
__wbg_set_pitch_793c4498ea6e6817: function(arg0, arg1) {
|
|
1628
|
+
getObject(arg0).pitch = arg1;
|
|
1629
|
+
},
|
|
1557
1630
|
__wbg_set_power_preference_b42d00a8facfbade: function(arg0, arg1) {
|
|
1558
1631
|
getObject(arg0).powerPreference = __wbindgen_enum_GpuPowerPreference[arg1];
|
|
1559
1632
|
},
|
|
@@ -1566,6 +1639,9 @@ function __wbg_get_imports() {
|
|
|
1566
1639
|
__wbg_set_r_6ece4d74af63364f: function(arg0, arg1) {
|
|
1567
1640
|
getObject(arg0).r = arg1;
|
|
1568
1641
|
},
|
|
1642
|
+
__wbg_set_rate_caba1c2a5e041669: function(arg0, arg1) {
|
|
1643
|
+
getObject(arg0).rate = arg1;
|
|
1644
|
+
},
|
|
1569
1645
|
__wbg_set_required_features_bbab71414c45e621: function(arg0, arg1, arg2) {
|
|
1570
1646
|
getObject(arg0).requiredFeatures = getArrayJsValueViewFromWasm0(arg1, arg2);
|
|
1571
1647
|
},
|
|
@@ -1710,6 +1786,12 @@ function __wbg_get_imports() {
|
|
|
1710
1786
|
__wbg_set_visibility_d8a6821789538c25: function(arg0, arg1) {
|
|
1711
1787
|
getObject(arg0).visibility = arg1 >>> 0;
|
|
1712
1788
|
},
|
|
1789
|
+
__wbg_set_voice_3e1a3ef98a8d5ecd: function(arg0, arg1) {
|
|
1790
|
+
getObject(arg0).voice = getObject(arg1);
|
|
1791
|
+
},
|
|
1792
|
+
__wbg_set_volume_d84050ffb0189f47: function(arg0, arg1) {
|
|
1793
|
+
getObject(arg0).volume = arg1;
|
|
1794
|
+
},
|
|
1713
1795
|
__wbg_set_width_0ca908d167690992: function(arg0, arg1) {
|
|
1714
1796
|
getObject(arg0).width = arg1 >>> 0;
|
|
1715
1797
|
},
|
|
@@ -1737,6 +1819,19 @@ function __wbg_get_imports() {
|
|
|
1737
1819
|
__wbg_shaderSource_c8812639b47d87b9: function(arg0, arg1, arg2, arg3) {
|
|
1738
1820
|
getObject(arg0).shaderSource(getObject(arg1), getStringFromWasm0(arg2, arg3));
|
|
1739
1821
|
},
|
|
1822
|
+
__wbg_speak_0522b6116a03fd31: function(arg0, arg1) {
|
|
1823
|
+
getObject(arg0).speak(getObject(arg1));
|
|
1824
|
+
},
|
|
1825
|
+
__wbg_speaking_bbf159df39686677: function(arg0) {
|
|
1826
|
+
const ret = getObject(arg0).speaking;
|
|
1827
|
+
return ret;
|
|
1828
|
+
},
|
|
1829
|
+
__wbg_speechSynthesis_9178be485e9e2ef1: function() {
|
|
1830
|
+
return handleError(function(arg0) {
|
|
1831
|
+
const ret = getObject(arg0).speechSynthesis;
|
|
1832
|
+
return addHeapObject(ret);
|
|
1833
|
+
}, arguments);
|
|
1834
|
+
},
|
|
1740
1835
|
__wbg_static_accessor_GLOBAL_266715b9d96ba635: function() {
|
|
1741
1836
|
const ret = typeof global === "undefined" ? null : global;
|
|
1742
1837
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
@@ -2054,6 +2149,13 @@ function __wbg_get_imports() {
|
|
|
2054
2149
|
__wbg_viewport_e35d16c542d2ce70: function(arg0, arg1, arg2, arg3, arg4) {
|
|
2055
2150
|
getObject(arg0).viewport(arg1, arg2, arg3, arg4);
|
|
2056
2151
|
},
|
|
2152
|
+
__wbg_voiceURI_85f8d4604a52970f: function(arg0, arg1) {
|
|
2153
|
+
const ret = getObject(arg1).voiceURI;
|
|
2154
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
2155
|
+
const len1 = WASM_VECTOR_LEN;
|
|
2156
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
2157
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
2158
|
+
},
|
|
2057
2159
|
__wbg_width_3d0dce3d9892e35e: function(arg0) {
|
|
2058
2160
|
const ret = getObject(arg0).width;
|
|
2059
2161
|
return ret;
|
|
@@ -2069,23 +2171,23 @@ function __wbg_get_imports() {
|
|
|
2069
2171
|
}, arguments);
|
|
2070
2172
|
},
|
|
2071
2173
|
__wbindgen_generic_0000000000000001: function(arg0, arg1) {
|
|
2072
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2174
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_10643);
|
|
2073
2175
|
return addHeapObject(ret);
|
|
2074
2176
|
},
|
|
2075
2177
|
__wbindgen_generic_0000000000000002: function(arg0, arg1) {
|
|
2076
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2178
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_3241);
|
|
2077
2179
|
return addHeapObject(ret);
|
|
2078
2180
|
},
|
|
2079
2181
|
__wbindgen_generic_0000000000000003: function(arg0, arg1) {
|
|
2080
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2182
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_3242);
|
|
2081
2183
|
return addHeapObject(ret);
|
|
2082
2184
|
},
|
|
2083
2185
|
__wbindgen_generic_0000000000000004: function(arg0, arg1) {
|
|
2084
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2186
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_3241_10);
|
|
2085
2187
|
return addHeapObject(ret);
|
|
2086
2188
|
},
|
|
2087
2189
|
__wbindgen_generic_0000000000000005: function(arg0, arg1) {
|
|
2088
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2190
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_3241_11);
|
|
2089
2191
|
return addHeapObject(ret);
|
|
2090
2192
|
},
|
|
2091
2193
|
__wbindgen_generic_0000000000000006: function(arg0) {
|
|
@@ -2138,16 +2240,16 @@ function __wbg_get_imports() {
|
|
|
2138
2240
|
"./snippets/engine-core-64626f8edd8232bb/inline0.js": exports_inline0
|
|
2139
2241
|
};
|
|
2140
2242
|
}
|
|
2141
|
-
function
|
|
2142
|
-
wasm.
|
|
2243
|
+
function __wasm_bindgen_func_elem_3242(arg0, arg1, arg2) {
|
|
2244
|
+
wasm.__wasm_bindgen_func_elem_3242(arg0, arg1, addHeapObject(arg2));
|
|
2143
2245
|
}
|
|
2144
|
-
function
|
|
2145
|
-
wasm.
|
|
2246
|
+
function __wasm_bindgen_func_elem_10645(arg0, arg1, arg2, arg3) {
|
|
2247
|
+
wasm.__wasm_bindgen_func_elem_10645(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
2146
2248
|
}
|
|
2147
|
-
function
|
|
2249
|
+
function __wasm_bindgen_func_elem_10643(arg0, arg1, arg2) {
|
|
2148
2250
|
try {
|
|
2149
2251
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2150
|
-
wasm.
|
|
2252
|
+
wasm.__wasm_bindgen_func_elem_10643(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2151
2253
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2152
2254
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2153
2255
|
if (r1) {
|
|
@@ -2157,10 +2259,10 @@ function __wasm_bindgen_func_elem_9777(arg0, arg1, arg2) {
|
|
|
2157
2259
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2158
2260
|
}
|
|
2159
2261
|
}
|
|
2160
|
-
function
|
|
2262
|
+
function __wasm_bindgen_func_elem_3241(arg0, arg1, arg2) {
|
|
2161
2263
|
try {
|
|
2162
2264
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2163
|
-
wasm.
|
|
2265
|
+
wasm.__wasm_bindgen_func_elem_3241(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2164
2266
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2165
2267
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2166
2268
|
if (r1) {
|
|
@@ -2170,10 +2272,10 @@ function __wasm_bindgen_func_elem_2414(arg0, arg1, arg2) {
|
|
|
2170
2272
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2171
2273
|
}
|
|
2172
2274
|
}
|
|
2173
|
-
function
|
|
2275
|
+
function __wasm_bindgen_func_elem_3241_10(arg0, arg1, arg2) {
|
|
2174
2276
|
try {
|
|
2175
2277
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2176
|
-
wasm.
|
|
2278
|
+
wasm.__wasm_bindgen_func_elem_3241_10(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2177
2279
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2178
2280
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2179
2281
|
if (r1) {
|
|
@@ -2183,10 +2285,10 @@ function __wasm_bindgen_func_elem_2414_9(arg0, arg1, arg2) {
|
|
|
2183
2285
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2184
2286
|
}
|
|
2185
2287
|
}
|
|
2186
|
-
function
|
|
2288
|
+
function __wasm_bindgen_func_elem_3241_11(arg0, arg1, arg2) {
|
|
2187
2289
|
try {
|
|
2188
2290
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2189
|
-
wasm.
|
|
2291
|
+
wasm.__wasm_bindgen_func_elem_3241_11(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2190
2292
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2191
2293
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2192
2294
|
if (r1) {
|
|
@@ -2723,6 +2825,99 @@ class IndexedDbCache {
|
|
|
2723
2825
|
}
|
|
2724
2826
|
}
|
|
2725
2827
|
|
|
2828
|
+
// src/media/input.web.ts
|
|
2829
|
+
var BLOCK = 2048;
|
|
2830
|
+
var MIC_FAILED = -1;
|
|
2831
|
+
function installMicrophoneInput(core, bridge) {
|
|
2832
|
+
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia)
|
|
2833
|
+
return;
|
|
2834
|
+
let permission = 0;
|
|
2835
|
+
let stream = null;
|
|
2836
|
+
let context = null;
|
|
2837
|
+
let failed = false;
|
|
2838
|
+
let session = 0;
|
|
2839
|
+
const startCore = bridge.micStart;
|
|
2840
|
+
const stopCore = bridge.micStop;
|
|
2841
|
+
const stateCore = bridge.micState;
|
|
2842
|
+
const allocate = core.engine_web_alloc;
|
|
2843
|
+
const push = core.engine_audio_mic_push;
|
|
2844
|
+
let pointer = 0;
|
|
2845
|
+
navigator.permissions?.query({ name: "microphone" }).then((status) => {
|
|
2846
|
+
const read = () => {
|
|
2847
|
+
permission = status.state === "granted" ? 1 : status.state === "denied" ? -1 : 0;
|
|
2848
|
+
};
|
|
2849
|
+
read();
|
|
2850
|
+
status.onchange = read;
|
|
2851
|
+
}).catch(() => {});
|
|
2852
|
+
const open = async () => {
|
|
2853
|
+
stream ??= await navigator.mediaDevices.getUserMedia({
|
|
2854
|
+
audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true, channelCount: 1 }
|
|
2855
|
+
});
|
|
2856
|
+
permission = 1;
|
|
2857
|
+
return stream;
|
|
2858
|
+
};
|
|
2859
|
+
const close = () => {
|
|
2860
|
+
stream?.getTracks().forEach((track) => track.stop());
|
|
2861
|
+
stream = null;
|
|
2862
|
+
context?.close().catch(() => {});
|
|
2863
|
+
context = null;
|
|
2864
|
+
};
|
|
2865
|
+
bridge.micPermission = () => permission;
|
|
2866
|
+
bridge.micRequestPermission = async () => {
|
|
2867
|
+
try {
|
|
2868
|
+
await open();
|
|
2869
|
+
return true;
|
|
2870
|
+
} catch {
|
|
2871
|
+
permission = -1;
|
|
2872
|
+
return false;
|
|
2873
|
+
}
|
|
2874
|
+
};
|
|
2875
|
+
bridge.micStart = (maxSeconds) => {
|
|
2876
|
+
session++;
|
|
2877
|
+
const current = session;
|
|
2878
|
+
close();
|
|
2879
|
+
failed = false;
|
|
2880
|
+
if (!startCore(maxSeconds))
|
|
2881
|
+
return false;
|
|
2882
|
+
(async () => {
|
|
2883
|
+
const input = await open();
|
|
2884
|
+
const audio = new AudioContext;
|
|
2885
|
+
context = audio;
|
|
2886
|
+
await audio.audioWorklet.addModule(new URL("./audio-worklet.js", import.meta.url));
|
|
2887
|
+
if (current !== session)
|
|
2888
|
+
return audio.close();
|
|
2889
|
+
const node = new AudioWorkletNode(audio, "nayan-microphone", { numberOfInputs: 1, numberOfOutputs: 1 });
|
|
2890
|
+
const muted = audio.createGain();
|
|
2891
|
+
muted.gain.value = 0;
|
|
2892
|
+
audio.createMediaStreamSource(input).connect(node).connect(muted).connect(audio.destination);
|
|
2893
|
+
pointer ||= allocate(BLOCK * 4);
|
|
2894
|
+
node.port.onmessage = ({ data }) => {
|
|
2895
|
+
if (current !== session)
|
|
2896
|
+
return;
|
|
2897
|
+
new Float32Array(core.memory.buffer, pointer, data.length).set(data);
|
|
2898
|
+
push(pointer, data.length, audio.sampleRate);
|
|
2899
|
+
};
|
|
2900
|
+
await audio.resume();
|
|
2901
|
+
})().catch(() => {
|
|
2902
|
+
if (current !== session)
|
|
2903
|
+
return;
|
|
2904
|
+
failed = true;
|
|
2905
|
+
if (permission === 0)
|
|
2906
|
+
permission = -1;
|
|
2907
|
+
stopCore();
|
|
2908
|
+
close();
|
|
2909
|
+
});
|
|
2910
|
+
return true;
|
|
2911
|
+
};
|
|
2912
|
+
bridge.micStop = () => {
|
|
2913
|
+
session++;
|
|
2914
|
+
failed = false;
|
|
2915
|
+
stopCore();
|
|
2916
|
+
close();
|
|
2917
|
+
};
|
|
2918
|
+
bridge.micState = () => failed ? MIC_FAILED : stateCore();
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2726
2921
|
// src/media/output.web.ts
|
|
2727
2922
|
function installAudioOutput(core) {
|
|
2728
2923
|
if (typeof window === "undefined")
|
|
@@ -2940,6 +3135,16 @@ function createBrowserEngine(core) {
|
|
|
2940
3135
|
end++;
|
|
2941
3136
|
return decoder.decode(b.subarray(pointer, end));
|
|
2942
3137
|
};
|
|
3138
|
+
const text = (index, value) => {
|
|
3139
|
+
const b = encoder.encode(value);
|
|
3140
|
+
return [put(index, b), b.length];
|
|
3141
|
+
};
|
|
3142
|
+
const readDoubles = (read) => {
|
|
3143
|
+
const count = read(0, 0);
|
|
3144
|
+
const out = zeroed(2, Math.max(8, count * 8));
|
|
3145
|
+
read(out, count);
|
|
3146
|
+
return copy(out, count * 8);
|
|
3147
|
+
};
|
|
2943
3148
|
const geometry = (handle) => {
|
|
2944
3149
|
try {
|
|
2945
3150
|
const error = cString(fn("geometry_error", handle));
|
|
@@ -3173,6 +3378,18 @@ function createBrowserEngine(core) {
|
|
|
3173
3378
|
const [x, y, z] = dimensions("model_size", mesh, 3, true);
|
|
3174
3379
|
return [x, y, z];
|
|
3175
3380
|
},
|
|
3381
|
+
bakeKept(key) {
|
|
3382
|
+
const [k, length] = text(0, key);
|
|
3383
|
+
return fn("bake_kept", k, length) !== 0;
|
|
3384
|
+
},
|
|
3385
|
+
modelBake(mesh, spec) {
|
|
3386
|
+
const [s, length] = text(0, spec);
|
|
3387
|
+
const out = zeroed(1, 16);
|
|
3388
|
+
if (!fn("model_bake", mesh, s, length, out))
|
|
3389
|
+
return [];
|
|
3390
|
+
const [texture, x, y, extent] = new Float32Array(u8().slice(out, out + 16).buffer);
|
|
3391
|
+
return [texture, x, y, extent];
|
|
3392
|
+
},
|
|
3176
3393
|
modelLoadAsync(value, center, fit) {
|
|
3177
3394
|
return settle(() => engine.modelLoad(value, center, fit));
|
|
3178
3395
|
},
|
|
@@ -3287,6 +3504,14 @@ function createBrowserEngine(core) {
|
|
|
3287
3504
|
const buckets = source(4, ranges);
|
|
3288
3505
|
ex("render_overlay")(surface, m, c, r, capacity, buckets, ranges.byteLength / 4, count, width, height);
|
|
3289
3506
|
},
|
|
3507
|
+
renderBackdrop(surface, matrices, colors, regions, ranges, count) {
|
|
3508
|
+
const capacity = Math.min(buf(matrices).byteLength / MATRIX_BYTES, buf(colors).byteLength / VEC4_BYTES, buf(regions).byteLength / VEC4_BYTES);
|
|
3509
|
+
const m = source(1, matrices);
|
|
3510
|
+
const c = source(2, colors);
|
|
3511
|
+
const r = source(3, regions);
|
|
3512
|
+
const buckets = source(4, ranges);
|
|
3513
|
+
ex("render_backdrop")(surface, m, c, r, capacity, buckets, ranges.byteLength / 4, count);
|
|
3514
|
+
},
|
|
3290
3515
|
renderError: () => string("render_error"),
|
|
3291
3516
|
renderBackend: () => string("render_backend"),
|
|
3292
3517
|
drawingCreate: (width, height, ratio) => fn("drawing_create", width, height, ratio),
|
|
@@ -3327,10 +3552,100 @@ function createBrowserEngine(core) {
|
|
|
3327
3552
|
fn("audio_set_muted", +muted);
|
|
3328
3553
|
},
|
|
3329
3554
|
audioIsRunning: () => fn("audio_is_running") !== 0,
|
|
3555
|
+
audioRelease(sound) {
|
|
3556
|
+
fn("audio_release", sound);
|
|
3557
|
+
},
|
|
3558
|
+
audioDuration: (sound) => fn("audio_duration", sound),
|
|
3559
|
+
audioLevels(sound, perSecond) {
|
|
3560
|
+
const count = fn("audio_levels", sound, perSecond, 0, 0);
|
|
3561
|
+
if (!count)
|
|
3562
|
+
return new ArrayBuffer(0);
|
|
3563
|
+
const p = zeroed(0, count * 4);
|
|
3564
|
+
fn("audio_levels", sound, perSecond, p, count);
|
|
3565
|
+
return copy(p, count * 4);
|
|
3566
|
+
},
|
|
3567
|
+
micPermission: () => 0,
|
|
3568
|
+
micRequestPermission: () => Promise.resolve(false),
|
|
3569
|
+
micStart: (maxSeconds) => fn("audio_mic_start", maxSeconds) !== 0,
|
|
3570
|
+
micStop() {
|
|
3571
|
+
fn("audio_mic_stop");
|
|
3572
|
+
},
|
|
3573
|
+
micState: () => fn("audio_mic_state"),
|
|
3574
|
+
micLevel: () => fn("audio_mic_level"),
|
|
3575
|
+
micHeld: () => fn("audio_mic_held"),
|
|
3576
|
+
micTake: (seconds, skipEnd) => fn("audio_mic_take", seconds, skipEnd),
|
|
3330
3577
|
hapticsSupported: () => fn("haptics_supported") !== 0,
|
|
3331
3578
|
hapticsPlay(taps, throttle) {
|
|
3332
3579
|
const p = put(0, new Uint8Array(new Float32Array(taps).buffer));
|
|
3333
3580
|
fn("haptics_play", p, taps.length / 3, +throttle);
|
|
3581
|
+
},
|
|
3582
|
+
worldgenBuild: (recipe, key, prepareTerrain) => {
|
|
3583
|
+
const [r, rl] = text(0, recipe);
|
|
3584
|
+
const [k, kl] = text(1, key);
|
|
3585
|
+
return fn("worldgen_build", r, rl, k, kl, +prepareTerrain) >>> 0;
|
|
3586
|
+
},
|
|
3587
|
+
worldgenBuildAsync: async (recipe, key, prepareTerrain) => engine.worldgenBuild(recipe, key, prepareTerrain),
|
|
3588
|
+
worldgenError: () => string("worldgen_error"),
|
|
3589
|
+
worldgenKept(key) {
|
|
3590
|
+
const [k, kl] = text(0, key);
|
|
3591
|
+
return fn("worldgen_kept", k, kl) !== 0;
|
|
3592
|
+
},
|
|
3593
|
+
worldgenFree(world) {
|
|
3594
|
+
fn("worldgen_free", world);
|
|
3595
|
+
},
|
|
3596
|
+
worldgenInfo: (world) => string("worldgen_info", [world]),
|
|
3597
|
+
worldgenLayer(world, name) {
|
|
3598
|
+
const [n, nl] = text(1, name);
|
|
3599
|
+
return readDoubles((out, capacity) => fn("worldgen_layer", world, n, nl, out, capacity));
|
|
3600
|
+
},
|
|
3601
|
+
worldgenReachable: (world) => readDoubles((out, capacity) => fn("worldgen_reachable", world, out, capacity)),
|
|
3602
|
+
worldgenOverview(world) {
|
|
3603
|
+
const count = fn("worldgen_overview", world, 0, 0);
|
|
3604
|
+
const out = zeroed(0, Math.max(1, count));
|
|
3605
|
+
fn("worldgen_overview", world, out, count);
|
|
3606
|
+
return copy(out, count);
|
|
3607
|
+
},
|
|
3608
|
+
worldgenPick: (world, run) => fn("worldgen_pick", world, run) !== 0,
|
|
3609
|
+
worldgenTerrain: (world, material) => geometry(fn("worldgen_terrain", world, material)),
|
|
3610
|
+
worldgenMesh(recipe) {
|
|
3611
|
+
const [r, rl] = text(0, recipe);
|
|
3612
|
+
return geometry(fn("worldgen_mesh", r, rl));
|
|
3613
|
+
},
|
|
3614
|
+
worldgenPaint(vertices, recipe) {
|
|
3615
|
+
const [v] = data(vertices);
|
|
3616
|
+
const [r, rl] = text(1, recipe);
|
|
3617
|
+
const ok = fn("worldgen_paint", v, bytes(vertices).length / 44, r, rl) !== 0;
|
|
3618
|
+
if (ok)
|
|
3619
|
+
bytes(vertices).set(u8().subarray(v, v + vertices.byteLength));
|
|
3620
|
+
return ok;
|
|
3621
|
+
},
|
|
3622
|
+
worldgenGround: (world, x, z) => fn("worldgen_ground", world, x, z),
|
|
3623
|
+
worldgenSurface: (world, x, z) => fn("worldgen_surface", world, x, z),
|
|
3624
|
+
worldgenPlatform: (world, x, z) => fn("worldgen_platform", world, x, z),
|
|
3625
|
+
worldgenWalkable: (world, x, z, radius) => fn("worldgen_walkable", world, x, z, radius) !== 0,
|
|
3626
|
+
worldgenClearance: (world, x, z, radius) => fn("worldgen_clearance", world, x, z, radius),
|
|
3627
|
+
worldgenSolidClearance: (world, x, z, radius, bottom, top) => fn("worldgen_solid_clearance", world, x, z, radius, bottom, top),
|
|
3628
|
+
worldgenFieldIndex(world, name) {
|
|
3629
|
+
const [n, nl] = text(0, name);
|
|
3630
|
+
return fn("worldgen_field_index", world, n, nl);
|
|
3631
|
+
},
|
|
3632
|
+
worldgenField: (world, field, x, z) => fn("worldgen_field", world, field, x, z),
|
|
3633
|
+
worldgenTilt(world, x, z, yaw) {
|
|
3634
|
+
const out = zeroed(0, 32);
|
|
3635
|
+
fn("worldgen_tilt", world, x, z, yaw, out);
|
|
3636
|
+
const at = out >> 3;
|
|
3637
|
+
const q = f64();
|
|
3638
|
+
return [q[at], q[at + 1], q[at + 2], q[at + 3]];
|
|
3639
|
+
},
|
|
3640
|
+
worldgenSight: (world, ax, az, bx, bz, radius, step, rise) => fn("worldgen_sight", world, ax, az, bx, bz, radius, step, rise) !== 0,
|
|
3641
|
+
worldgenMove(world, x, z, dx, dz, radius, bodies) {
|
|
3642
|
+
const list = bytes(bodies);
|
|
3643
|
+
const b = put(1, list);
|
|
3644
|
+
const p = zeroed(0, 16);
|
|
3645
|
+
f64().set([x, z], p >> 3);
|
|
3646
|
+
fn("worldgen_move", world, p, dx, dz, radius, b, Math.floor(list.byteLength / 24));
|
|
3647
|
+
const q = f64();
|
|
3648
|
+
return [q[p >> 3], q[(p >> 3) + 1]];
|
|
3334
3649
|
}
|
|
3335
3650
|
};
|
|
3336
3651
|
return engine;
|
|
@@ -3351,6 +3666,7 @@ function prepareEngine() {
|
|
|
3351
3666
|
} catch {}
|
|
3352
3667
|
const ready = createBrowserEngine(core);
|
|
3353
3668
|
ready.audioIsRunning = installAudioOutput(core);
|
|
3669
|
+
installMicrophoneInput(core, ready);
|
|
3354
3670
|
Object.assign(browser, ready);
|
|
3355
3671
|
})().catch((error) => {
|
|
3356
3672
|
pending = undefined;
|
|
@@ -3619,50 +3935,6 @@ var SHAPE_MESH = {
|
|
|
3619
3935
|
|
|
3620
3936
|
// src/render/meshes.ts
|
|
3621
3937
|
var VERTEX_FLOATS = 11;
|
|
3622
|
-
|
|
3623
|
-
class Builder {
|
|
3624
|
-
vertices = [];
|
|
3625
|
-
indices = [];
|
|
3626
|
-
vertex(p, n, u, v) {
|
|
3627
|
-
this.vertices.push(p[0], p[1], p[2], n[0], n[1], n[2], 1, 1, 1, u, v);
|
|
3628
|
-
return this.vertices.length / VERTEX_FLOATS - 1;
|
|
3629
|
-
}
|
|
3630
|
-
quad(a, b, c, d) {
|
|
3631
|
-
this.indices.push(a, b, c, a, c, d);
|
|
3632
|
-
}
|
|
3633
|
-
grid(rows, cols, at) {
|
|
3634
|
-
const first = this.vertices.length / VERTEX_FLOATS;
|
|
3635
|
-
for (let i = 0;i <= rows; i++) {
|
|
3636
|
-
for (let j = 0;j <= cols; j++) {
|
|
3637
|
-
const [p, n] = at(j / cols, i / rows);
|
|
3638
|
-
this.vertex(p, n, j / cols, i / rows);
|
|
3639
|
-
}
|
|
3640
|
-
}
|
|
3641
|
-
for (let i = 0;i < rows; i++) {
|
|
3642
|
-
for (let j = 0;j < cols; j++) {
|
|
3643
|
-
const a = first + i * (cols + 1) + j;
|
|
3644
|
-
const b = a + cols + 1;
|
|
3645
|
-
this.indices.push(a, b, a + 1, a + 1, b, b + 1);
|
|
3646
|
-
}
|
|
3647
|
-
}
|
|
3648
|
-
}
|
|
3649
|
-
disc(y, radius, facing, segments) {
|
|
3650
|
-
const center = this.vertex([0, y, 0], [0, facing, 0], 0.5, 0.5);
|
|
3651
|
-
const first = center + 1;
|
|
3652
|
-
for (let j = 0;j <= segments; j++) {
|
|
3653
|
-
const t = j / segments * TAU;
|
|
3654
|
-
const x = Math.cos(t);
|
|
3655
|
-
const z = Math.sin(t);
|
|
3656
|
-
this.vertex([x * radius, y, z * radius], [0, facing, 0], 0.5 + x / 2, 0.5 + z / 2);
|
|
3657
|
-
}
|
|
3658
|
-
for (let j = 0;j < segments; j++) {
|
|
3659
|
-
if (facing === 1)
|
|
3660
|
-
this.indices.push(center, first + j + 1, first + j);
|
|
3661
|
-
else
|
|
3662
|
-
this.indices.push(center, first + j, first + j + 1);
|
|
3663
|
-
}
|
|
3664
|
-
}
|
|
3665
|
-
}
|
|
3666
3938
|
var TAU = Math.PI * 2;
|
|
3667
3939
|
var registered = new Map;
|
|
3668
3940
|
var idLimit = 16;
|
|
@@ -3906,36 +4178,6 @@ function layoutText(font, text, align, options = {}) {
|
|
|
3906
4178
|
return placed;
|
|
3907
4179
|
}
|
|
3908
4180
|
|
|
3909
|
-
// src/assets/texture.ts
|
|
3910
|
-
var loader3 = new AssetLoader("loadTexture");
|
|
3911
|
-
function loadTexture(source) {
|
|
3912
|
-
return loader3.load(source, (native, bytes) => {
|
|
3913
|
-
const finish = (id) => {
|
|
3914
|
-
if (id < 0)
|
|
3915
|
-
throw new Error(native.loadError() || "not a PNG or JPEG image");
|
|
3916
|
-
const [width, height] = native.textureSize(id);
|
|
3917
|
-
return { id, width, height };
|
|
3918
|
-
};
|
|
3919
|
-
return typeof native.textureLoadAsync === "function" ? native.textureLoadAsync(bytes).then(finish) : finish(native.textureLoad(bytes));
|
|
3920
|
-
});
|
|
3921
|
-
}
|
|
3922
|
-
var variants = new Map;
|
|
3923
|
-
function texturedMesh(mesh, texture) {
|
|
3924
|
-
const key = `${mesh}:${texture.id}`;
|
|
3925
|
-
let id = variants.get(key);
|
|
3926
|
-
if (id === undefined) {
|
|
3927
|
-
const base = meshInfo(mesh);
|
|
3928
|
-
if (!base)
|
|
3929
|
-
throw new Error("texture: this mesh has nothing to draw");
|
|
3930
|
-
id = NativeNayanEngine_web_default.meshAlias(mesh);
|
|
3931
|
-
if (id < 0)
|
|
3932
|
-
throw new Error(`texture: ${NativeNayanEngine_web_default.loadError()}`);
|
|
3933
|
-
registerCoreMesh(id, { texture: texture.id, shine: base.shine }, () => base.geometry);
|
|
3934
|
-
variants.set(key, id);
|
|
3935
|
-
}
|
|
3936
|
-
return id;
|
|
3937
|
-
}
|
|
3938
|
-
|
|
3939
4181
|
// src/world/color.ts
|
|
3940
4182
|
var HEX = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
3941
4183
|
var RGB = /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+%?)\s*)?\)$/i;
|
|
@@ -4000,6 +4242,77 @@ function resolveColors(colors) {
|
|
|
4000
4242
|
return colors.map(resolveColor);
|
|
4001
4243
|
}
|
|
4002
4244
|
|
|
4245
|
+
// src/assets/texture.ts
|
|
4246
|
+
var loader3 = new AssetLoader("loadTexture");
|
|
4247
|
+
function loadTexture(source) {
|
|
4248
|
+
return loader3.load(source, (native, bytes) => {
|
|
4249
|
+
const finish = (id) => {
|
|
4250
|
+
if (id < 0)
|
|
4251
|
+
throw new Error(native.loadError() || "not a PNG or JPEG image");
|
|
4252
|
+
const [width, height] = native.textureSize(id);
|
|
4253
|
+
return { id, width, height };
|
|
4254
|
+
};
|
|
4255
|
+
return typeof native.textureLoadAsync === "function" ? native.textureLoadAsync(bytes).then(finish) : finish(native.textureLoad(bytes));
|
|
4256
|
+
});
|
|
4257
|
+
}
|
|
4258
|
+
var variants = new Map;
|
|
4259
|
+
function texturedMesh(mesh, texture) {
|
|
4260
|
+
const key = `${mesh}:${texture.id}`;
|
|
4261
|
+
let id = variants.get(key);
|
|
4262
|
+
if (id === undefined) {
|
|
4263
|
+
const base = meshInfo(mesh);
|
|
4264
|
+
if (!base)
|
|
4265
|
+
throw new Error("texture: this mesh has nothing to draw");
|
|
4266
|
+
id = NativeNayanEngine_web_default.meshAlias(mesh);
|
|
4267
|
+
if (id < 0)
|
|
4268
|
+
throw new Error(`texture: ${NativeNayanEngine_web_default.loadError()}`);
|
|
4269
|
+
registerCoreMesh(id, { texture: texture.id, shine: base.shine }, () => base.geometry);
|
|
4270
|
+
variants.set(key, id);
|
|
4271
|
+
}
|
|
4272
|
+
return id;
|
|
4273
|
+
}
|
|
4274
|
+
function bakeModel(model, options) {
|
|
4275
|
+
const mesh = model == null ? -1 : typeof model === "number" ? model : model.id;
|
|
4276
|
+
const native = NativeNayanEngine_web_default;
|
|
4277
|
+
if (typeof native.modelBake !== "function")
|
|
4278
|
+
throw new Error("bakeModel: this app's native core predates baked models: rebuild it");
|
|
4279
|
+
const { light } = options;
|
|
4280
|
+
const lightColor = resolveColor(light.color ?? [1, 1, 1]);
|
|
4281
|
+
const sky = resolveColor(options.background ?? [0, 0, 0]);
|
|
4282
|
+
const spec = {
|
|
4283
|
+
size: Math.max(1, Math.min(1024, Math.round(options.size))),
|
|
4284
|
+
supersample: options.supersample ?? 4,
|
|
4285
|
+
light: light.direction,
|
|
4286
|
+
ambient: light.ambient,
|
|
4287
|
+
lightColor: [lightColor[0], lightColor[1], lightColor[2]],
|
|
4288
|
+
sky: [sky[0], sky[1], sky[2]],
|
|
4289
|
+
shine: options.shine ?? meshInfo(mesh)?.shine ?? 0,
|
|
4290
|
+
padding: options.padding ?? 0.04,
|
|
4291
|
+
parts: options.parts?.map((part) => {
|
|
4292
|
+
const id = typeof part.model === "number" ? part.model : part.model.id;
|
|
4293
|
+
const scale = part.scale ?? 1;
|
|
4294
|
+
const color = resolveColor(part.color ?? [1, 1, 1]);
|
|
4295
|
+
return {
|
|
4296
|
+
mesh: id,
|
|
4297
|
+
position: part.position ?? [0, 0, 0],
|
|
4298
|
+
scale: typeof scale === "number" ? [scale, scale, scale] : scale,
|
|
4299
|
+
color: [color[0], color[1], color[2]],
|
|
4300
|
+
shine: part.shine ?? meshInfo(id)?.shine ?? 0
|
|
4301
|
+
};
|
|
4302
|
+
}),
|
|
4303
|
+
frame: options.frame && [options.frame.center[0], options.frame.center[1], options.frame.extent],
|
|
4304
|
+
key: options.key
|
|
4305
|
+
};
|
|
4306
|
+
const baked = native.modelBake(Math.max(0, mesh), JSON.stringify(spec));
|
|
4307
|
+
if (baked.length !== 4)
|
|
4308
|
+
throw new Error(`bakeModel: ${native.loadError() || "failed"}`);
|
|
4309
|
+
const [texture, x, y, extent] = baked;
|
|
4310
|
+
return { texture: { id: texture, width: spec.size, height: spec.size }, center: [x, y], extent };
|
|
4311
|
+
}
|
|
4312
|
+
function isBakeKept(key) {
|
|
4313
|
+
return typeof NativeNayanEngine_web_default?.bakeKept === "function" && NativeNayanEngine_web_default.bakeKept(key);
|
|
4314
|
+
}
|
|
4315
|
+
|
|
4003
4316
|
// src/world/desc.ts
|
|
4004
4317
|
var DESC_LEN = 64;
|
|
4005
4318
|
var FLAG = {
|
|
@@ -4463,6 +4776,9 @@ class World {
|
|
|
4463
4776
|
boundsValue = null;
|
|
4464
4777
|
listenerValue = null;
|
|
4465
4778
|
updates = 0;
|
|
4779
|
+
backdropValue = null;
|
|
4780
|
+
stills = new Map;
|
|
4781
|
+
stillChanged = false;
|
|
4466
4782
|
constructor(capacity) {
|
|
4467
4783
|
this.capacity = capacity;
|
|
4468
4784
|
if (!NativeNayanEngine_web_default) {
|
|
@@ -4491,6 +4807,8 @@ class World {
|
|
|
4491
4807
|
return this.disposed ? 0 : this.native.count(this.id);
|
|
4492
4808
|
}
|
|
4493
4809
|
spawn(options = {}) {
|
|
4810
|
+
if (options.still)
|
|
4811
|
+
return this.spawnStill(options);
|
|
4494
4812
|
if (options.parent != null && options.physics != null) {
|
|
4495
4813
|
throw new Error("World.spawn: attached entities can't have physics (put it on the parent)");
|
|
4496
4814
|
}
|
|
@@ -4523,9 +4841,35 @@ class World {
|
|
|
4523
4841
|
}
|
|
4524
4842
|
return e;
|
|
4525
4843
|
}
|
|
4844
|
+
get backdrop() {
|
|
4845
|
+
return this.backdropValue;
|
|
4846
|
+
}
|
|
4847
|
+
backdropLayer(capacity = 64) {
|
|
4848
|
+
if (this.disposed)
|
|
4849
|
+
throw new Error("World: used after dispose()");
|
|
4850
|
+
return this.backdropValue ??= new World(capacity);
|
|
4851
|
+
}
|
|
4852
|
+
spawnStill({ still: _, ...options }) {
|
|
4853
|
+
if (options.parent != null || options.physics != null || options.text !== undefined) {
|
|
4854
|
+
throw new Error("World.spawn: a still entity can't be attached or have physics or text");
|
|
4855
|
+
}
|
|
4856
|
+
const layer = this.backdropLayer();
|
|
4857
|
+
const entity = layer.spawn({ pickable: false, ...options });
|
|
4858
|
+
const standIn = this.spawn({ mesh: "none", pickable: false });
|
|
4859
|
+
this.stills.set(standIn, entity);
|
|
4860
|
+
this.stillChanged = true;
|
|
4861
|
+
return standIn;
|
|
4862
|
+
}
|
|
4526
4863
|
set(e, options) {
|
|
4527
4864
|
if (this.disposed)
|
|
4528
4865
|
return false;
|
|
4866
|
+
const still = this.stills.get(e);
|
|
4867
|
+
if (still !== undefined) {
|
|
4868
|
+
if (options.parent != null || options.physics != null)
|
|
4869
|
+
throw new Error("World.set: a still entity can't be attached or have physics");
|
|
4870
|
+
this.stillChanged = true;
|
|
4871
|
+
return this.backdropValue.set(still, options);
|
|
4872
|
+
}
|
|
4529
4873
|
const text = this.texts.get(e);
|
|
4530
4874
|
encode(this.desc, options, text ? undefined : this.resolveMesh(options, "set"));
|
|
4531
4875
|
const ok = this.native.setDesc(this.id, e, this.desc.buffer);
|
|
@@ -4573,6 +4917,12 @@ class World {
|
|
|
4573
4917
|
despawn(e) {
|
|
4574
4918
|
if (this.disposed)
|
|
4575
4919
|
return false;
|
|
4920
|
+
const still = this.stills.get(e);
|
|
4921
|
+
if (still !== undefined) {
|
|
4922
|
+
this.stills.delete(e);
|
|
4923
|
+
this.backdropValue.despawn(still);
|
|
4924
|
+
this.stillChanged = true;
|
|
4925
|
+
}
|
|
4576
4926
|
const existed = this.native.despawn(this.id, e);
|
|
4577
4927
|
this.texts.delete(e);
|
|
4578
4928
|
this.resolveFinished();
|
|
@@ -4949,6 +5299,10 @@ class World {
|
|
|
4949
5299
|
this.runFallbackTimers(dt);
|
|
4950
5300
|
if (!this.disposed)
|
|
4951
5301
|
this.scoreboardValue?.dispatch();
|
|
5302
|
+
if (this.stillChanged && this.backdropValue && !this.disposed) {
|
|
5303
|
+
this.stillChanged = false;
|
|
5304
|
+
this.backdropValue.update(0);
|
|
5305
|
+
}
|
|
4952
5306
|
}
|
|
4953
5307
|
forEachCollision(fn) {
|
|
4954
5308
|
if (this.disposed)
|
|
@@ -4973,6 +5327,8 @@ class World {
|
|
|
4973
5327
|
this.pending.clear();
|
|
4974
5328
|
this.timers.clear();
|
|
4975
5329
|
this.fallbackTimers = [];
|
|
5330
|
+
this.stills.clear();
|
|
5331
|
+
this.backdropValue?.dispose();
|
|
4976
5332
|
NativeNayanEngine_web_default.destroyWorld(this.id);
|
|
4977
5333
|
}
|
|
4978
5334
|
}
|
|
@@ -5915,14 +6271,27 @@ function Surface({ surfaceId, style, onSize, onError, touch, onPrimaryAction })
|
|
|
5915
6271
|
}
|
|
5916
6272
|
|
|
5917
6273
|
// src/render/quality.ts
|
|
5918
|
-
var QUALITIES = ["high", "medium", "low", "lowest"];
|
|
5919
6274
|
var QUALITY_LEVELS = {
|
|
5920
|
-
high: { maxPixelRatio: 3, samples: 4, shadowSize: 2048, softShadows: true },
|
|
5921
|
-
medium: { maxPixelRatio: 3, samples: 4, shadowSize:
|
|
5922
|
-
low: { maxPixelRatio: 3, samples: 1, shadowSize:
|
|
5923
|
-
lowest: { maxPixelRatio: 2, samples: 1, shadowSize:
|
|
6275
|
+
high: { maxPixelRatio: 3, samples: 4, shadows: true, shadowSize: 2048, softShadows: true },
|
|
6276
|
+
medium: { maxPixelRatio: 3, samples: 4, shadows: true, shadowSize: 2048, softShadows: false },
|
|
6277
|
+
low: { maxPixelRatio: 3, samples: 1, shadows: false, shadowSize: 2048, softShadows: true },
|
|
6278
|
+
lowest: { maxPixelRatio: 2, samples: 1, fxaa: true, shadows: false, shadowSize: 2048, softShadows: true, maxPixels: 800000 }
|
|
5924
6279
|
};
|
|
5925
|
-
var
|
|
6280
|
+
var AUTO_STEPS = [
|
|
6281
|
+
{ quality: "high" },
|
|
6282
|
+
{ quality: "high", maxPixels: 1500000 },
|
|
6283
|
+
{ quality: "high", maxPixels: 1100000 },
|
|
6284
|
+
{ quality: "medium", maxPixels: 1100000 },
|
|
6285
|
+
{ quality: "low", maxPixels: 1100000 },
|
|
6286
|
+
{ quality: "lowest" }
|
|
6287
|
+
];
|
|
6288
|
+
function stepLevel(step) {
|
|
6289
|
+
const level = QUALITY_LEVELS[step.quality];
|
|
6290
|
+
if (!step.maxPixels || level.maxPixels && level.maxPixels <= step.maxPixels)
|
|
6291
|
+
return level;
|
|
6292
|
+
return { ...level, maxPixels: step.maxPixels };
|
|
6293
|
+
}
|
|
6294
|
+
var SLOW_FRAME_MS = 18.5;
|
|
5926
6295
|
var VERY_SLOW_FRAME_MS = 30;
|
|
5927
6296
|
var FAST_FRAME_MS = 17.4;
|
|
5928
6297
|
var RENDER_SHARE = 0.6;
|
|
@@ -5931,7 +6300,42 @@ var SETTLE_MS = 1500;
|
|
|
5931
6300
|
var SLOW_SECONDS = 3;
|
|
5932
6301
|
var VERY_SLOW_SECONDS = 1;
|
|
5933
6302
|
var FAST_SECONDS = 10;
|
|
6303
|
+
var HEADROOM_RENDER_MS = 10;
|
|
6304
|
+
var HEADROOM_SECONDS = 2;
|
|
5934
6305
|
var RELAPSE_MS = 20000;
|
|
6306
|
+
function levelPixelRatio(level, screen, width, height) {
|
|
6307
|
+
const ratio = Math.min(screen, level.maxPixelRatio);
|
|
6308
|
+
const area = width * height;
|
|
6309
|
+
if (!level.maxPixels || area <= 0)
|
|
6310
|
+
return ratio;
|
|
6311
|
+
return Math.min(ratio, Math.sqrt(level.maxPixels / area));
|
|
6312
|
+
}
|
|
6313
|
+
var storeKey = (key) => `quality-step:${key}`;
|
|
6314
|
+
var settled = new Map;
|
|
6315
|
+
function settledQuality(key, store) {
|
|
6316
|
+
if (!key)
|
|
6317
|
+
return;
|
|
6318
|
+
const known = settled.get(key);
|
|
6319
|
+
if (known !== undefined || typeof store?.cacheRead !== "function")
|
|
6320
|
+
return known;
|
|
6321
|
+
try {
|
|
6322
|
+
const bytes = new Uint8Array(store.cacheRead(storeKey(key)));
|
|
6323
|
+
const step = bytes.length === 1 && bytes[0] < AUTO_STEPS.length ? bytes[0] : undefined;
|
|
6324
|
+
if (step !== undefined)
|
|
6325
|
+
settled.set(key, step);
|
|
6326
|
+
return step;
|
|
6327
|
+
} catch {
|
|
6328
|
+
return;
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
function rememberQuality(key, step, store) {
|
|
6332
|
+
if (!key || settledQuality(key, store) === step)
|
|
6333
|
+
return;
|
|
6334
|
+
settled.set(key, step);
|
|
6335
|
+
try {
|
|
6336
|
+
store?.cacheWrite?.(storeKey(key), new Uint8Array([step]).buffer);
|
|
6337
|
+
} catch {}
|
|
6338
|
+
}
|
|
5935
6339
|
|
|
5936
6340
|
class AutoQuality {
|
|
5937
6341
|
index = 0;
|
|
@@ -5942,8 +6346,19 @@ class AutoQuality {
|
|
|
5942
6346
|
slow = 0;
|
|
5943
6347
|
verySlow = 0;
|
|
5944
6348
|
fast = 0;
|
|
6349
|
+
headroom = 0;
|
|
6350
|
+
constructor(start = 0) {
|
|
6351
|
+
const index = typeof start === "number" ? Math.floor(start) : AUTO_STEPS.findIndex((s) => s.quality === start);
|
|
6352
|
+
this.index = Math.min(Math.max(0, index), AUTO_STEPS.length - 1);
|
|
6353
|
+
}
|
|
6354
|
+
get step() {
|
|
6355
|
+
return this.index;
|
|
6356
|
+
}
|
|
5945
6357
|
get quality() {
|
|
5946
|
-
return
|
|
6358
|
+
return AUTO_STEPS[this.index].quality;
|
|
6359
|
+
}
|
|
6360
|
+
get level() {
|
|
6361
|
+
return stepLevel(AUTO_STEPS[this.index]);
|
|
5947
6362
|
}
|
|
5948
6363
|
report(now, frames) {
|
|
5949
6364
|
if (!this.started)
|
|
@@ -5955,24 +6370,35 @@ class AutoQuality {
|
|
|
5955
6370
|
this.slow = gpuBound ? this.slow + 1 : 0;
|
|
5956
6371
|
this.verySlow = gpuBound && frames.frameMs > VERY_SLOW_FRAME_MS ? this.verySlow + 1 : 0;
|
|
5957
6372
|
this.fast = smooth ? this.fast + 1 : 0;
|
|
5958
|
-
|
|
6373
|
+
this.headroom = !gpuBound && frames.renderMs <= HEADROOM_RENDER_MS ? this.headroom + 1 : 0;
|
|
6374
|
+
if ((this.slow >= SLOW_SECONDS || this.verySlow >= VERY_SLOW_SECONDS) && this.index < AUTO_STEPS.length - 1) {
|
|
5959
6375
|
if (now - this.raisedAt < RELAPSE_MS)
|
|
5960
6376
|
this.ceiling = Math.max(this.ceiling, this.index + 1);
|
|
5961
6377
|
this.index++;
|
|
5962
6378
|
return this.moved(now);
|
|
5963
6379
|
}
|
|
5964
|
-
if (this.fast >= FAST_SECONDS && this.index > this.ceiling) {
|
|
6380
|
+
if ((this.fast >= FAST_SECONDS || this.headroom >= HEADROOM_SECONDS) && this.index > this.ceiling) {
|
|
5965
6381
|
this.index--;
|
|
5966
6382
|
this.raisedAt = now;
|
|
5967
6383
|
return this.moved(now);
|
|
5968
6384
|
}
|
|
5969
6385
|
return false;
|
|
5970
6386
|
}
|
|
6387
|
+
hold(now) {
|
|
6388
|
+
if (!this.started)
|
|
6389
|
+
this.started = now;
|
|
6390
|
+
this.changed = now;
|
|
6391
|
+
this.slow = 0;
|
|
6392
|
+
this.verySlow = 0;
|
|
6393
|
+
this.fast = 0;
|
|
6394
|
+
this.headroom = 0;
|
|
6395
|
+
}
|
|
5971
6396
|
moved(now) {
|
|
5972
6397
|
this.changed = now;
|
|
5973
6398
|
this.slow = 0;
|
|
5974
6399
|
this.verySlow = 0;
|
|
5975
6400
|
this.fast = 0;
|
|
6401
|
+
this.headroom = 0;
|
|
5976
6402
|
return true;
|
|
5977
6403
|
}
|
|
5978
6404
|
}
|
|
@@ -5987,7 +6413,7 @@ function median(values) {
|
|
|
5987
6413
|
// src/render/GameView.tsx
|
|
5988
6414
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
5989
6415
|
var DEFAULT_BACKGROUND = [0.04, 0.05, 0.09];
|
|
5990
|
-
var FRAME_LEN =
|
|
6416
|
+
var FRAME_LEN = 29;
|
|
5991
6417
|
var WHITE3 = [1, 1, 1];
|
|
5992
6418
|
var nextSurface = 1;
|
|
5993
6419
|
var defaultCamera = () => ({
|
|
@@ -6078,11 +6504,11 @@ function GameView(props) {
|
|
|
6078
6504
|
const threaded = native2.hasFrameClock?.() === true && typeof native2.publishFrame === "function" && typeof native2.startFrames === "function";
|
|
6079
6505
|
let presentedAt = 0;
|
|
6080
6506
|
if (autoQuality.current?.source !== source)
|
|
6081
|
-
autoQuality.current = { source, auto: new AutoQuality };
|
|
6507
|
+
autoQuality.current = { source, auto: new AutoQuality(settledQuality(live.current.props.qualityKey, native)) };
|
|
6082
6508
|
const auto = autoQuality.current.auto;
|
|
6083
6509
|
const chosen = () => {
|
|
6084
6510
|
const setting = live.current.props.quality ?? "auto";
|
|
6085
|
-
return setting === "auto" ? auto.quality : setting;
|
|
6511
|
+
return setting === "auto" ? [auto.quality, auto.level] : [setting, QUALITY_LEVELS[setting]];
|
|
6086
6512
|
};
|
|
6087
6513
|
const followed = [0, 0, 0];
|
|
6088
6514
|
const shaken = { eye: [0, 0, 0], target: [0, 0, 0], fov: 1 };
|
|
@@ -6111,10 +6537,12 @@ function GameView(props) {
|
|
|
6111
6537
|
return Math.min(s.count, end);
|
|
6112
6538
|
};
|
|
6113
6539
|
let overlay = null;
|
|
6540
|
+
let backdrop = null;
|
|
6114
6541
|
let last = 0;
|
|
6115
6542
|
let frames = 0;
|
|
6116
6543
|
let fpsStart = 0;
|
|
6117
6544
|
let updateTime = 0;
|
|
6545
|
+
let publishTime = 0;
|
|
6118
6546
|
let renderTime = 0;
|
|
6119
6547
|
const intervals = [];
|
|
6120
6548
|
const draws = [];
|
|
@@ -6143,10 +6571,10 @@ function GameView(props) {
|
|
|
6143
6571
|
updateTime += performance.now() - t0;
|
|
6144
6572
|
follow(camera, source, followed, dt);
|
|
6145
6573
|
const view = shake(camera, shaken, dt);
|
|
6146
|
-
const quality = chosen();
|
|
6147
|
-
const level = QUALITY_LEVELS[quality];
|
|
6574
|
+
const [quality, level] = chosen();
|
|
6148
6575
|
const { width, height } = size.current;
|
|
6149
|
-
const
|
|
6576
|
+
const screenRatio = Math.min(pixelRatio(), level.maxPixelRatio);
|
|
6577
|
+
const ratio = levelPixelRatio(level, pixelRatio(), width, height);
|
|
6150
6578
|
const f = frameData;
|
|
6151
6579
|
f.set(view.eye, 0);
|
|
6152
6580
|
f.set(view.target, 3);
|
|
@@ -6154,7 +6582,7 @@ function GameView(props) {
|
|
|
6154
6582
|
f[7] = view.ortho ?? 0;
|
|
6155
6583
|
f.set(light.direction, 8);
|
|
6156
6584
|
f[11] = light.ambient;
|
|
6157
|
-
f[12] = light.shadows ?? true ? 1 : 0;
|
|
6585
|
+
f[12] = (light.shadows ?? true) !== false && level.shadows ? 1 : 0;
|
|
6158
6586
|
f[13] = light.shadowExtent ?? 30;
|
|
6159
6587
|
const lightColor = light.color === undefined ? WHITE3 : resolveColor(light.color);
|
|
6160
6588
|
f[14] = lightColor[0];
|
|
@@ -6165,11 +6593,14 @@ function GameView(props) {
|
|
|
6165
6593
|
f[18] = sky[1];
|
|
6166
6594
|
f[19] = sky[2];
|
|
6167
6595
|
f[20] = environment.fog;
|
|
6168
|
-
f[21] = Math.round(width *
|
|
6169
|
-
f[22] = Math.round(height *
|
|
6596
|
+
f[21] = Math.round(width * screenRatio);
|
|
6597
|
+
f[22] = Math.round(height * screenRatio);
|
|
6170
6598
|
f[23] = level.samples;
|
|
6171
6599
|
f[24] = level.shadowSize;
|
|
6172
6600
|
f[25] = level.softShadows ? 1 : 0;
|
|
6601
|
+
f[26] = screenRatio > 0 ? ratio / screenRatio : 1;
|
|
6602
|
+
f[27] = level.fxaa ? 1 : 0;
|
|
6603
|
+
f[28] = light.shadows === "backdrop" ? 0 : 1;
|
|
6173
6604
|
const t1 = performance.now();
|
|
6174
6605
|
if (layer) {
|
|
6175
6606
|
if (overlay?.source !== layer)
|
|
@@ -6179,9 +6610,23 @@ function GameView(props) {
|
|
|
6179
6610
|
overlay = null;
|
|
6180
6611
|
native.renderOverlay(surfaceId, regions.buffer, regions.buffer, regions.buffer, regions.buffer, 0, 0, 0);
|
|
6181
6612
|
}
|
|
6613
|
+
const backSource = current.backdrop ?? source.backdrop;
|
|
6614
|
+
const back = backSource && !backSource.isDisposed ? backSource : undefined;
|
|
6615
|
+
if (back && typeof native.renderBackdrop === "function") {
|
|
6616
|
+
if (backdrop?.source !== back || backdrop.updates !== (back.updateCount ?? 0)) {
|
|
6617
|
+
if (!back.updateCount && back.update)
|
|
6618
|
+
back.update(0);
|
|
6619
|
+
backdrop = { source: back, updates: back.updateCount ?? 0, regions: wholeRegions(back) };
|
|
6620
|
+
native.renderBackdrop(surfaceId, back.matrices.buffer, back.colors.buffer, backdrop.regions.buffer, back.ranges.buffer, drawn(back));
|
|
6621
|
+
}
|
|
6622
|
+
} else if (backdrop) {
|
|
6623
|
+
backdrop = null;
|
|
6624
|
+
native.renderBackdrop?.(surfaceId, regions.buffer, regions.buffer, regions.buffer, regions.buffer, 0);
|
|
6625
|
+
}
|
|
6182
6626
|
const render = threaded ? native2.publishFrame : native.renderFrame;
|
|
6183
6627
|
const rendered = render(surfaceId, f.buffer, source.matrices.buffer, source.colors.buffer, regions.buffer, source.ranges.buffer, drawn(source), viewProj.buffer, source.nativeWorld ?? -1);
|
|
6184
6628
|
const drawMs = performance.now() - t1;
|
|
6629
|
+
publishTime += drawMs;
|
|
6185
6630
|
if (!threaded) {
|
|
6186
6631
|
renderTime += drawMs;
|
|
6187
6632
|
draws.push(drawMs);
|
|
@@ -6207,18 +6652,26 @@ function GameView(props) {
|
|
|
6207
6652
|
frameMs = shownFrames > 0 ? Math.max(frameMs, elapsed / shownFrames) : elapsed;
|
|
6208
6653
|
renderMs = meanRenderMs = nativeMs;
|
|
6209
6654
|
}
|
|
6210
|
-
|
|
6655
|
+
if (current.adaptQuality ?? true)
|
|
6656
|
+
auto.report(now, { frameMs, renderMs });
|
|
6657
|
+
else
|
|
6658
|
+
auto.hold(now);
|
|
6659
|
+
if ((current.quality ?? "auto") === "auto")
|
|
6660
|
+
rememberQuality(current.qualityKey, auto.step, native);
|
|
6211
6661
|
intervals.length = 0;
|
|
6212
6662
|
draws.length = 0;
|
|
6213
6663
|
current.onStats?.({
|
|
6214
6664
|
fps,
|
|
6215
6665
|
updateMs: updateTime / frames,
|
|
6666
|
+
publishMs: publishTime / frames,
|
|
6216
6667
|
renderMs: meanRenderMs,
|
|
6217
6668
|
quality,
|
|
6669
|
+
sceneScale: frameData[26],
|
|
6218
6670
|
backend: native.renderBackend()
|
|
6219
6671
|
});
|
|
6220
6672
|
frames = 0;
|
|
6221
6673
|
updateTime = 0;
|
|
6674
|
+
publishTime = 0;
|
|
6222
6675
|
renderTime = 0;
|
|
6223
6676
|
fpsStart = now;
|
|
6224
6677
|
}
|
|
@@ -6346,6 +6799,9 @@ class ProceduralCache {
|
|
|
6346
6799
|
this.revision = revision;
|
|
6347
6800
|
this.storage = storage;
|
|
6348
6801
|
}
|
|
6802
|
+
storageKey(key) {
|
|
6803
|
+
return `procedural:${this.revision}:${key}`;
|
|
6804
|
+
}
|
|
6349
6805
|
get stats() {
|
|
6350
6806
|
return {
|
|
6351
6807
|
hits: this.hits,
|
|
@@ -6556,6 +7012,322 @@ class ProceduralCache {
|
|
|
6556
7012
|
return mapValue(header.value, restored);
|
|
6557
7013
|
}
|
|
6558
7014
|
}
|
|
7015
|
+
// src/assets/procedural.ts
|
|
7016
|
+
class FieldRef {
|
|
7017
|
+
id;
|
|
7018
|
+
constructor(id) {
|
|
7019
|
+
this.id = id;
|
|
7020
|
+
}
|
|
7021
|
+
}
|
|
7022
|
+
|
|
7023
|
+
class FieldGraph {
|
|
7024
|
+
nodes = [];
|
|
7025
|
+
outputs = {};
|
|
7026
|
+
constants = new Map;
|
|
7027
|
+
inputs = new Map;
|
|
7028
|
+
node(node) {
|
|
7029
|
+
this.nodes.push(node);
|
|
7030
|
+
return new FieldRef(this.nodes.length - 1);
|
|
7031
|
+
}
|
|
7032
|
+
ref(value) {
|
|
7033
|
+
return (value instanceof FieldRef ? value : this.constant(value)).id;
|
|
7034
|
+
}
|
|
7035
|
+
refs(values) {
|
|
7036
|
+
return values.map((v) => this.ref(v));
|
|
7037
|
+
}
|
|
7038
|
+
constant(value) {
|
|
7039
|
+
if (!Number.isFinite(value))
|
|
7040
|
+
throw new Error("FieldGraph: constants must be finite");
|
|
7041
|
+
let ref = this.constants.get(value);
|
|
7042
|
+
if (!ref || Object.is(value, -0) !== Object.is(this.nodes[ref.id]?.value, -0)) {
|
|
7043
|
+
ref = this.node({ op: "const", value });
|
|
7044
|
+
this.constants.set(value, ref);
|
|
7045
|
+
}
|
|
7046
|
+
return ref;
|
|
7047
|
+
}
|
|
7048
|
+
input(name) {
|
|
7049
|
+
let ref = this.inputs.get(name);
|
|
7050
|
+
if (!ref) {
|
|
7051
|
+
ref = this.node({ op: "var", name });
|
|
7052
|
+
this.inputs.set(name, ref);
|
|
7053
|
+
}
|
|
7054
|
+
return ref;
|
|
7055
|
+
}
|
|
7056
|
+
get x() {
|
|
7057
|
+
return this.input("x");
|
|
7058
|
+
}
|
|
7059
|
+
get z() {
|
|
7060
|
+
return this.input("z");
|
|
7061
|
+
}
|
|
7062
|
+
add(a, b) {
|
|
7063
|
+
return this.node({ op: "add", a: this.ref(a), b: this.ref(b) });
|
|
7064
|
+
}
|
|
7065
|
+
sub(a, b) {
|
|
7066
|
+
return this.node({ op: "sub", a: this.ref(a), b: this.ref(b) });
|
|
7067
|
+
}
|
|
7068
|
+
mul(a, b) {
|
|
7069
|
+
return this.node({ op: "mul", a: this.ref(a), b: this.ref(b) });
|
|
7070
|
+
}
|
|
7071
|
+
div(a, b) {
|
|
7072
|
+
return this.node({ op: "div", a: this.ref(a), b: this.ref(b) });
|
|
7073
|
+
}
|
|
7074
|
+
sum(...values) {
|
|
7075
|
+
if (!values.length)
|
|
7076
|
+
return this.constant(0);
|
|
7077
|
+
let total = values[0] instanceof FieldRef ? values[0] : this.constant(values[0]);
|
|
7078
|
+
for (const value of values.slice(1))
|
|
7079
|
+
total = this.add(total, value);
|
|
7080
|
+
return total;
|
|
7081
|
+
}
|
|
7082
|
+
product(...values) {
|
|
7083
|
+
if (!values.length)
|
|
7084
|
+
return this.constant(1);
|
|
7085
|
+
let total = values[0] instanceof FieldRef ? values[0] : this.constant(values[0]);
|
|
7086
|
+
for (const value of values.slice(1))
|
|
7087
|
+
total = this.mul(total, value);
|
|
7088
|
+
return total;
|
|
7089
|
+
}
|
|
7090
|
+
min(...args) {
|
|
7091
|
+
return this.node({ op: "min", args: this.refs(args) });
|
|
7092
|
+
}
|
|
7093
|
+
max(...args) {
|
|
7094
|
+
return this.node({ op: "max", args: this.refs(args) });
|
|
7095
|
+
}
|
|
7096
|
+
neg(a) {
|
|
7097
|
+
return this.node({ op: "neg", a: this.ref(a) });
|
|
7098
|
+
}
|
|
7099
|
+
abs(a) {
|
|
7100
|
+
return this.node({ op: "abs", a: this.ref(a) });
|
|
7101
|
+
}
|
|
7102
|
+
sqrt(a) {
|
|
7103
|
+
return this.node({ op: "sqrt", a: this.ref(a) });
|
|
7104
|
+
}
|
|
7105
|
+
floor(a) {
|
|
7106
|
+
return this.node({ op: "floor", a: this.ref(a) });
|
|
7107
|
+
}
|
|
7108
|
+
square(a) {
|
|
7109
|
+
return this.node({ op: "square", a: this.ref(a) });
|
|
7110
|
+
}
|
|
7111
|
+
sin(a) {
|
|
7112
|
+
return this.node({ op: "sin", a: this.ref(a) });
|
|
7113
|
+
}
|
|
7114
|
+
cos(a) {
|
|
7115
|
+
return this.node({ op: "cos", a: this.ref(a) });
|
|
7116
|
+
}
|
|
7117
|
+
exp(a) {
|
|
7118
|
+
return this.node({ op: "exp", a: this.ref(a) });
|
|
7119
|
+
}
|
|
7120
|
+
pow(a, b) {
|
|
7121
|
+
return this.node({ op: "pow", a: this.ref(a), b: this.ref(b) });
|
|
7122
|
+
}
|
|
7123
|
+
fract(a) {
|
|
7124
|
+
return this.node({ op: "fract", a: this.ref(a) });
|
|
7125
|
+
}
|
|
7126
|
+
noise(x, z, period = 0) {
|
|
7127
|
+
return this.node({ op: "noise", x: this.ref(x), z: this.ref(z), period });
|
|
7128
|
+
}
|
|
7129
|
+
mix(a, b, t) {
|
|
7130
|
+
return this.add(a, this.mul(this.sub(b, a), t));
|
|
7131
|
+
}
|
|
7132
|
+
hypot(...args) {
|
|
7133
|
+
return this.node({ op: "hypot", args: this.refs(args) });
|
|
7134
|
+
}
|
|
7135
|
+
smooth(a) {
|
|
7136
|
+
return this.node({ op: "smooth", a: this.ref(a) });
|
|
7137
|
+
}
|
|
7138
|
+
clamp(a, lo, hi) {
|
|
7139
|
+
return this.node({ op: "clamp", a: this.ref(a), lo: this.ref(lo), hi: this.ref(hi) });
|
|
7140
|
+
}
|
|
7141
|
+
select(test, le, gt) {
|
|
7142
|
+
return this.node({ op: "select", test: this.ref(test), le: this.ref(le), gt: this.ref(gt) });
|
|
7143
|
+
}
|
|
7144
|
+
sines(x, z, base, terms) {
|
|
7145
|
+
return this.node({ op: "sines", x: this.ref(x), z: this.ref(z), base, terms });
|
|
7146
|
+
}
|
|
7147
|
+
bumps(x, z, items, power = 2) {
|
|
7148
|
+
return this.node({ op: "bumps", x: this.ref(x), z: this.ref(z), items, power });
|
|
7149
|
+
}
|
|
7150
|
+
distance(x, z, shapes) {
|
|
7151
|
+
return this.node({ op: "distance", x: this.ref(x), z: this.ref(z), shapes });
|
|
7152
|
+
}
|
|
7153
|
+
falloff(x, z, shapes) {
|
|
7154
|
+
return this.node({ op: "falloff", x: this.ref(x), z: this.ref(z), shapes });
|
|
7155
|
+
}
|
|
7156
|
+
depth(x, z, shapes) {
|
|
7157
|
+
return this.node({ op: "depth", x: this.ref(x), z: this.ref(z), shapes });
|
|
7158
|
+
}
|
|
7159
|
+
output(name, value) {
|
|
7160
|
+
this.outputs[name] = this.ref(value);
|
|
7161
|
+
return name;
|
|
7162
|
+
}
|
|
7163
|
+
toJSON() {
|
|
7164
|
+
return { nodes: this.nodes, outputs: this.outputs };
|
|
7165
|
+
}
|
|
7166
|
+
}
|
|
7167
|
+
|
|
7168
|
+
class FieldFunction {
|
|
7169
|
+
fields;
|
|
7170
|
+
outputs;
|
|
7171
|
+
constructor(fields, outputs) {
|
|
7172
|
+
this.fields = fields;
|
|
7173
|
+
this.outputs = outputs;
|
|
7174
|
+
}
|
|
7175
|
+
toJSON() {
|
|
7176
|
+
return { fields: this.fields, out: Array.from({ length: this.outputs }, (_, i) => `out${i}`) };
|
|
7177
|
+
}
|
|
7178
|
+
}
|
|
7179
|
+
function fieldFunction(names, build) {
|
|
7180
|
+
const f = new FieldGraph;
|
|
7181
|
+
const inputs = Object.fromEntries(names.map((name) => [name, f.input(name)]));
|
|
7182
|
+
const result = build(f, inputs);
|
|
7183
|
+
const out = Array.isArray(result) ? result : [result];
|
|
7184
|
+
out.forEach((value, i) => f.output(`out${i}`, value));
|
|
7185
|
+
return new FieldFunction(f, out.length);
|
|
7186
|
+
}
|
|
7187
|
+
var surfaceColor = (build) => fieldFunction(["u", "v", "x", "y", "z", "nx", "ny", "nz"], build);
|
|
7188
|
+
var faceColor = (build) => fieldFunction(["r", "angle"], build);
|
|
7189
|
+
var sectionColor = (build) => fieldFunction(["r", "y"], build);
|
|
7190
|
+
var surfaceDisplacement = (build) => fieldFunction(["u", "v"], build);
|
|
7191
|
+
var engine = () => {
|
|
7192
|
+
const native = NativeNayanEngine_web_default;
|
|
7193
|
+
if (!native)
|
|
7194
|
+
throw new Error("procedural worlds: the native core is not linked into this build");
|
|
7195
|
+
if (typeof native.worldgenBuild !== "function")
|
|
7196
|
+
throw new Error("procedural worlds: this app's native core predates them: rebuild it");
|
|
7197
|
+
return native;
|
|
7198
|
+
};
|
|
7199
|
+
var recipeText = (recipe) => JSON.stringify(recipe, (_key, value) => value instanceof FieldGraph ? value.toJSON() : value);
|
|
7200
|
+
var geometry = (buffers) => ({
|
|
7201
|
+
vertices: new Float32Array(buffers.vertices),
|
|
7202
|
+
indices: new Uint32Array(buffers.indices)
|
|
7203
|
+
});
|
|
7204
|
+
var spots = (points) => points.map(([x, z]) => ({ x, z }));
|
|
7205
|
+
var bodyBuffers = new Map;
|
|
7206
|
+
|
|
7207
|
+
class ProceduralWorld {
|
|
7208
|
+
handle;
|
|
7209
|
+
spawn;
|
|
7210
|
+
restored;
|
|
7211
|
+
layers;
|
|
7212
|
+
picks;
|
|
7213
|
+
fields = new Map;
|
|
7214
|
+
disposed = false;
|
|
7215
|
+
constructor(handle) {
|
|
7216
|
+
this.handle = handle;
|
|
7217
|
+
const info = JSON.parse(engine().worldgenInfo(handle));
|
|
7218
|
+
this.spawn = { x: info.spawn[0], z: info.spawn[1] };
|
|
7219
|
+
this.restored = info.restored;
|
|
7220
|
+
this.layers = info.layers;
|
|
7221
|
+
this.picks = Object.fromEntries(Object.entries(info.picks).map(([name, points]) => [name, spots(points)]));
|
|
7222
|
+
}
|
|
7223
|
+
get id() {
|
|
7224
|
+
if (this.disposed)
|
|
7225
|
+
throw new Error("ProceduralWorld: used after dispose");
|
|
7226
|
+
return this.handle;
|
|
7227
|
+
}
|
|
7228
|
+
layer(name) {
|
|
7229
|
+
return new Float64Array(engine().worldgenLayer(this.id, name));
|
|
7230
|
+
}
|
|
7231
|
+
reachable() {
|
|
7232
|
+
return new Float64Array(engine().worldgenReachable(this.id));
|
|
7233
|
+
}
|
|
7234
|
+
overview() {
|
|
7235
|
+
return new Uint8Array(engine().worldgenOverview(this.id));
|
|
7236
|
+
}
|
|
7237
|
+
pick(run) {
|
|
7238
|
+
const native = engine();
|
|
7239
|
+
if (!native.worldgenPick(this.id, run))
|
|
7240
|
+
return false;
|
|
7241
|
+
const info = JSON.parse(native.worldgenInfo(this.id));
|
|
7242
|
+
this.picks = Object.fromEntries(Object.entries(info.picks).map(([name, points]) => [name, spots(points)]));
|
|
7243
|
+
return true;
|
|
7244
|
+
}
|
|
7245
|
+
terrain(material) {
|
|
7246
|
+
return geometry(engine().worldgenTerrain(this.id, material));
|
|
7247
|
+
}
|
|
7248
|
+
ground(x, z) {
|
|
7249
|
+
return engine().worldgenGround(this.id, x, z);
|
|
7250
|
+
}
|
|
7251
|
+
surface(x, z) {
|
|
7252
|
+
return engine().worldgenSurface(this.id, x, z);
|
|
7253
|
+
}
|
|
7254
|
+
platformAt(x, z) {
|
|
7255
|
+
return engine().worldgenPlatform(this.id, x, z);
|
|
7256
|
+
}
|
|
7257
|
+
walkable(x, z, radius) {
|
|
7258
|
+
return engine().worldgenWalkable(this.id, x, z, radius);
|
|
7259
|
+
}
|
|
7260
|
+
clearance(x, z, radius) {
|
|
7261
|
+
return engine().worldgenClearance(this.id, x, z, radius);
|
|
7262
|
+
}
|
|
7263
|
+
solidClearance(x, z, radius, bottom, top) {
|
|
7264
|
+
return engine().worldgenSolidClearance(this.id, x, z, radius, bottom, top);
|
|
7265
|
+
}
|
|
7266
|
+
field(name, x, z) {
|
|
7267
|
+
let index = this.fields.get(name);
|
|
7268
|
+
if (index === undefined) {
|
|
7269
|
+
index = engine().worldgenFieldIndex(this.id, name);
|
|
7270
|
+
if (index < 0)
|
|
7271
|
+
throw new Error(`ProceduralWorld: no field named ${name}`);
|
|
7272
|
+
this.fields.set(name, index);
|
|
7273
|
+
}
|
|
7274
|
+
return engine().worldgenField(this.id, index, x, z);
|
|
7275
|
+
}
|
|
7276
|
+
tilt(x, z, yaw = 0) {
|
|
7277
|
+
return engine().worldgenTilt(this.id, x, z, yaw);
|
|
7278
|
+
}
|
|
7279
|
+
canSee(a, b, { radius = 0.25, step = 0.4, rise = Infinity } = {}) {
|
|
7280
|
+
return engine().worldgenSight(this.id, a.x, a.z, b.x, b.z, radius, step, rise === Infinity ? Number.MAX_VALUE : rise);
|
|
7281
|
+
}
|
|
7282
|
+
move(point, dx, dz, radius, bodies = []) {
|
|
7283
|
+
let buffer = bodyBuffers.get(bodies.length);
|
|
7284
|
+
if (!buffer)
|
|
7285
|
+
bodyBuffers.set(bodies.length, buffer = new Float64Array(bodies.length * 3));
|
|
7286
|
+
for (let i = 0;i < bodies.length; i++) {
|
|
7287
|
+
const b = bodies[i];
|
|
7288
|
+
buffer[i * 3] = b.x;
|
|
7289
|
+
buffer[i * 3 + 1] = b.z;
|
|
7290
|
+
buffer[i * 3 + 2] = b.radius;
|
|
7291
|
+
}
|
|
7292
|
+
const [x, z] = engine().worldgenMove(this.id, point.x, point.z, dx, dz, radius, buffer.buffer);
|
|
7293
|
+
point.x = x;
|
|
7294
|
+
point.z = z;
|
|
7295
|
+
}
|
|
7296
|
+
dispose() {
|
|
7297
|
+
if (this.disposed)
|
|
7298
|
+
return;
|
|
7299
|
+
this.disposed = true;
|
|
7300
|
+
engine().worldgenFree(this.handle);
|
|
7301
|
+
}
|
|
7302
|
+
}
|
|
7303
|
+
var opened = (handle) => {
|
|
7304
|
+
if (!handle)
|
|
7305
|
+
throw new Error(`procedural world: ${engine().worldgenError() || "generation failed"}`);
|
|
7306
|
+
return new ProceduralWorld(handle);
|
|
7307
|
+
};
|
|
7308
|
+
function generateWorld(recipe, options = {}) {
|
|
7309
|
+
return opened(engine().worldgenBuild(recipeText(recipe), options.key ?? "", options.prepareTerrain ?? false));
|
|
7310
|
+
}
|
|
7311
|
+
async function generateWorldAsync(recipe, options = {}) {
|
|
7312
|
+
return opened(await engine().worldgenBuildAsync(recipeText(recipe), options.key ?? "", options.prepareTerrain ?? false));
|
|
7313
|
+
}
|
|
7314
|
+
function isWorldKept(key) {
|
|
7315
|
+
return engine().worldgenKept(key);
|
|
7316
|
+
}
|
|
7317
|
+
function generateMesh(recipe) {
|
|
7318
|
+
return geometry(engine().worldgenMesh(recipeText(recipe)));
|
|
7319
|
+
}
|
|
7320
|
+
function paintGeometry(geometry, color) {
|
|
7321
|
+
const v = geometry.vertices;
|
|
7322
|
+
const whole = v.byteOffset === 0 && v.byteLength === v.buffer.byteLength;
|
|
7323
|
+
const buffer = whole ? v.buffer : v.slice().buffer;
|
|
7324
|
+
if (!engine().worldgenPaint(buffer, JSON.stringify(color)))
|
|
7325
|
+
throw new Error(`recolor: ${engine().worldgenError()}`);
|
|
7326
|
+
if (!whole)
|
|
7327
|
+
v.set(new Float32Array(buffer));
|
|
7328
|
+
return geometry;
|
|
7329
|
+
}
|
|
7330
|
+
|
|
6559
7331
|
// src/assets/shape.ts
|
|
6560
7332
|
var TAU2 = Math.PI * 2;
|
|
6561
7333
|
var CURVE_STEPS = 12;
|
|
@@ -6874,10 +7646,6 @@ function paint(g, color) {
|
|
|
6874
7646
|
}
|
|
6875
7647
|
return g;
|
|
6876
7648
|
}
|
|
6877
|
-
var fromBuilder = (b) => ({
|
|
6878
|
-
vertices: new Float32Array(b.vertices),
|
|
6879
|
-
indices: new Uint32Array(b.indices)
|
|
6880
|
-
});
|
|
6881
7649
|
function shapeGeometry(shape, options = {}) {
|
|
6882
7650
|
const info = meshInfo(SHAPE_MESH[shape]);
|
|
6883
7651
|
if (!info)
|
|
@@ -6907,7 +7675,11 @@ function extrude(path, options = {}) {
|
|
|
6907
7675
|
indices[i] = i;
|
|
6908
7676
|
return paint({ vertices, indices }, options.color);
|
|
6909
7677
|
}
|
|
7678
|
+
var perPoint = (x) => typeof x === "function" || x instanceof FieldFunction;
|
|
7679
|
+
var asField = (x) => x instanceof FieldFunction ? x : undefined;
|
|
6910
7680
|
function paintBy(g, color) {
|
|
7681
|
+
if (color instanceof FieldFunction)
|
|
7682
|
+
return paintGeometry(g, color);
|
|
6911
7683
|
if (typeof color !== "function")
|
|
6912
7684
|
return paint(g, color);
|
|
6913
7685
|
const v = g.vertices;
|
|
@@ -6927,29 +7699,40 @@ function paintBy(g, color) {
|
|
|
6927
7699
|
function recolor(geometry, color) {
|
|
6928
7700
|
return paintBy(geometry, color);
|
|
6929
7701
|
}
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
7702
|
+
var flat = (color) => color ? [color[0], color[1], color[2]] : undefined;
|
|
7703
|
+
function nativeSweep(part) {
|
|
7704
|
+
const core = native();
|
|
7705
|
+
if (typeof core.worldgenMesh !== "function")
|
|
7706
|
+
throw new Error("shapes: this app's native core predates native lathes and tubes: rebuild it");
|
|
7707
|
+
const built = core.worldgenMesh(JSON.stringify({ parts: [part] }));
|
|
7708
|
+
return { vertices: new Float32Array(built.vertices), indices: new Uint32Array(built.indices) };
|
|
7709
|
+
}
|
|
7710
|
+
function paintRange(g, from, to, color) {
|
|
7711
|
+
const v = g.vertices;
|
|
7712
|
+
for (let i = from * VERTEX_FLOATS;i < to * VERTEX_FLOATS; i += VERTEX_FLOATS) {
|
|
7713
|
+
const c = color({
|
|
7714
|
+
u: v[i + 9],
|
|
7715
|
+
v: v[i + 10],
|
|
7716
|
+
position: [v[i], v[i + 1], v[i + 2]],
|
|
7717
|
+
normal: [v[i + 3], v[i + 4], v[i + 5]]
|
|
7718
|
+
});
|
|
7719
|
+
v[i + 6] = c[0];
|
|
7720
|
+
v[i + 7] = c[1];
|
|
7721
|
+
v[i + 8] = c[2];
|
|
7722
|
+
}
|
|
7723
|
+
}
|
|
7724
|
+
function paintFace(g, from, to, sweep, color) {
|
|
6939
7725
|
const vs = g.vertices;
|
|
6940
|
-
for (let i =
|
|
7726
|
+
for (let i = from * VERTEX_FLOATS;i < to * VERTEX_FLOATS; i += VERTEX_FLOATS) {
|
|
6941
7727
|
const a = vs[i + 9] * sweep;
|
|
6942
7728
|
const r = vs[i + 10];
|
|
6943
7729
|
vs[i + 9] = 0.5 + Math.cos(a) * r / 2;
|
|
6944
7730
|
vs[i + 10] = 0.5 + Math.sin(a) * r / 2;
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
vs[i + 8] = c[2];
|
|
6950
|
-
}
|
|
7731
|
+
const c = color(r, a);
|
|
7732
|
+
vs[i + 6] = c[0];
|
|
7733
|
+
vs[i + 7] = c[1];
|
|
7734
|
+
vs[i + 8] = c[2];
|
|
6951
7735
|
}
|
|
6952
|
-
return typeof color === "function" ? g : paint(g, color);
|
|
6953
7736
|
}
|
|
6954
7737
|
var whole = (a) => a.byteOffset === 0 && a.byteLength === a.buffer.byteLength;
|
|
6955
7738
|
var nativeGeometry3 = (g) => NativeNayanEngine_web_default && typeof NativeNayanEngine_web_default.geometryPlace === "function" && whole(g.vertices) && whole(g.indices) ? NativeNayanEngine_web_default : null;
|
|
@@ -7013,70 +7796,52 @@ function lathe(profile, options = {}) {
|
|
|
7013
7796
|
const sweep = Math.min(TAU2, Math.max(0.001, options.sweep ?? TAU2));
|
|
7014
7797
|
const full = sweep >= TAU2 - 0.000001;
|
|
7015
7798
|
const last = points.length - 1;
|
|
7016
|
-
const edge = (i) => {
|
|
7017
|
-
const a = points[Math.max(0, i)];
|
|
7018
|
-
const b = points[Math.min(last, i + 1)];
|
|
7019
|
-
const len = Math.hypot(b[0] - a[0], b[1] - a[1]) || 1;
|
|
7020
|
-
return [(a[1] - b[1]) / len, (b[0] - a[0]) / len];
|
|
7021
|
-
};
|
|
7022
|
-
const normals = points.map(([r], i) => {
|
|
7023
|
-
if (r < 0.000001 && (i === 0 || i === last))
|
|
7024
|
-
return [0, i === 0 ? 1 : -1];
|
|
7025
|
-
const e1 = edge(i - 1);
|
|
7026
|
-
const e2 = edge(i);
|
|
7027
|
-
const n = i === 0 ? e2 : i === last ? e1 : [e1[0] + e2[0], e1[1] + e2[1]];
|
|
7028
|
-
const len = Math.hypot(n[0], n[1]) || 1;
|
|
7029
|
-
return [n[0] / len, n[1] / len];
|
|
7030
|
-
});
|
|
7031
|
-
const b = new Builder;
|
|
7032
7799
|
const displace = options.displace;
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
const parts = [
|
|
7043
|
-
{
|
|
7044
|
-
geometry: paintBy(displace ? smoothNormals(fromBuilder(b)) : fromBuilder(b), options.color)
|
|
7800
|
+
let offsets;
|
|
7801
|
+
if (typeof displace === "function") {
|
|
7802
|
+
offsets = new Array((last + 1) * (segments + 1));
|
|
7803
|
+
for (let i = 0;i <= last; i++) {
|
|
7804
|
+
const pole = points[i][0] < 0.000001;
|
|
7805
|
+
for (let j = 0;j <= segments; j++) {
|
|
7806
|
+
const u = j / segments;
|
|
7807
|
+
offsets[i * (segments + 1) + j] = displace(pole || full && u === 1 ? 0 : u, i / last);
|
|
7808
|
+
}
|
|
7045
7809
|
}
|
|
7046
|
-
];
|
|
7047
|
-
const capColor = options.capColor ?? (typeof options.color === "function" ? undefined : options.color);
|
|
7048
|
-
const rings = Math.max(1, Math.round(options.capRings ?? (typeof capColor === "function" ? 12 : 1)));
|
|
7049
|
-
for (const [i, facing] of [
|
|
7050
|
-
[0, 1],
|
|
7051
|
-
[last, -1]
|
|
7052
|
-
]) {
|
|
7053
|
-
const [r, y] = points[i];
|
|
7054
|
-
if (r < 0.000001)
|
|
7055
|
-
continue;
|
|
7056
|
-
parts.push({
|
|
7057
|
-
geometry: roundFace([0, y, 0], [1, 0, 0], [0, 0, -1], [0, facing, 0], () => r, sweep, segments, rings, capColor)
|
|
7058
|
-
});
|
|
7059
7810
|
}
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
const
|
|
7063
|
-
const
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7811
|
+
const color = options.color;
|
|
7812
|
+
const capColor = options.capColor ?? (perPoint(color) ? undefined : color);
|
|
7813
|
+
const capRings = Math.max(1, Math.round(options.capRings ?? (perPoint(capColor) ? 12 : 1)));
|
|
7814
|
+
const cutColor = options.cutColor ?? (perPoint(color) ? undefined : color);
|
|
7815
|
+
const cutSteps = Math.max(1, Math.round(options.cutSteps ?? (perPoint(cutColor) ? 12 : 1)));
|
|
7816
|
+
const g = nativeSweep({
|
|
7817
|
+
kind: "lathe",
|
|
7818
|
+
points,
|
|
7819
|
+
segments,
|
|
7820
|
+
sweep,
|
|
7821
|
+
displace: offsets,
|
|
7822
|
+
displaceField: asField(displace),
|
|
7823
|
+
color: perPoint(color) ? undefined : flat(color),
|
|
7824
|
+
colorField: asField(color),
|
|
7825
|
+
capColor: perPoint(capColor) ? undefined : flat(capColor),
|
|
7826
|
+
capColorField: asField(capColor),
|
|
7827
|
+
rawCaps: typeof capColor === "function",
|
|
7828
|
+
capRings,
|
|
7829
|
+
cutColor: perPoint(cutColor) ? undefined : flat(cutColor),
|
|
7830
|
+
cutColorField: asField(cutColor),
|
|
7831
|
+
cutSteps
|
|
7832
|
+
});
|
|
7833
|
+
let at = (last + 1) * (segments + 1);
|
|
7834
|
+
if (typeof color === "function")
|
|
7835
|
+
paintRange(g, 0, at, color);
|
|
7836
|
+
for (const i of [0, last]) {
|
|
7837
|
+
if (points[i][0] < 0.000001)
|
|
7838
|
+
continue;
|
|
7839
|
+
const end = at + (capRings + 1) * (segments + 1);
|
|
7840
|
+
if (typeof capColor === "function")
|
|
7841
|
+
paintFace(g, at, end, sweep, capColor);
|
|
7842
|
+
at = end;
|
|
7078
7843
|
}
|
|
7079
|
-
if (typeof cutColor === "function") {
|
|
7844
|
+
if (!full && typeof cutColor === "function") {
|
|
7080
7845
|
const widest = Math.max(...points.map((p) => p[0]), 0.000001);
|
|
7081
7846
|
const skinAt = (y) => {
|
|
7082
7847
|
let best = 0;
|
|
@@ -7088,33 +7853,19 @@ function lathe(profile, options = {}) {
|
|
|
7088
7853
|
}
|
|
7089
7854
|
return best || widest;
|
|
7090
7855
|
};
|
|
7091
|
-
const
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7856
|
+
const v = g.vertices;
|
|
7857
|
+
const half = (v.length / VERTEX_FLOATS - at) / 2;
|
|
7858
|
+
for (let k = 0;k < half; k++) {
|
|
7859
|
+
const i = (at + k) * VERTEX_FLOATS;
|
|
7860
|
+
const c = cutColor(Math.min(1, v[i] / skinAt(v[i + 1])), v[i + 1]);
|
|
7861
|
+
for (const o of [i, i + half * VERTEX_FLOATS]) {
|
|
7862
|
+
v[o + 6] = c[0];
|
|
7863
|
+
v[o + 7] = c[1];
|
|
7864
|
+
v[o + 8] = c[2];
|
|
7865
|
+
}
|
|
7095
7866
|
}
|
|
7096
|
-
} else {
|
|
7097
|
-
paint(face, cutColor);
|
|
7098
7867
|
}
|
|
7099
|
-
|
|
7100
|
-
const g = {
|
|
7101
|
-
vertices: face.vertices.slice(),
|
|
7102
|
-
indices: face.indices.slice()
|
|
7103
|
-
};
|
|
7104
|
-
const [c, s] = [Math.cos(angle), Math.sin(angle)];
|
|
7105
|
-
const n = angle === 0 ? [0, 0, 1] : [-s, 0, -c];
|
|
7106
|
-
for (let v = 0;v < g.vertices.length; v += VERTEX_FLOATS) {
|
|
7107
|
-
const r = g.vertices[v];
|
|
7108
|
-
g.vertices[v] = r * c;
|
|
7109
|
-
g.vertices[v + 2] = -r * s;
|
|
7110
|
-
g.vertices.set(n, v + 3);
|
|
7111
|
-
}
|
|
7112
|
-
if (flip)
|
|
7113
|
-
for (let t = 0;t < g.indices.length; t += 3)
|
|
7114
|
-
[g.indices[t + 1], g.indices[t + 2]] = [g.indices[t + 2], g.indices[t + 1]];
|
|
7115
|
-
return g;
|
|
7116
|
-
};
|
|
7117
|
-
return merge([...parts, { geometry: cut(0, false) }, { geometry: cut(sweep, true) }]);
|
|
7868
|
+
return g;
|
|
7118
7869
|
}
|
|
7119
7870
|
function tube(points, options = {}) {
|
|
7120
7871
|
if (points.some((p) => p.some((v) => !Number.isFinite(v))))
|
|
@@ -7127,133 +7878,43 @@ function tube(points, options = {}) {
|
|
|
7127
7878
|
if (points.length < (closed ? 3 : 2))
|
|
7128
7879
|
throw new Error(`tube: needs at least ${closed ? "three" : "two"} distinct points`);
|
|
7129
7880
|
const radius = typeof options.radius === "function" ? options.radius : () => options.radius ?? 0.1;
|
|
7130
|
-
const shape = options.shape
|
|
7881
|
+
const shape = options.shape;
|
|
7131
7882
|
const sides = Math.max(3, Math.round(options.sides ?? 12));
|
|
7132
7883
|
const steps = Math.max(1, Math.round(options.smoothness ?? 8));
|
|
7133
|
-
const
|
|
7134
|
-
const
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
if (Math.hypot(...delta) < 0.000000001)
|
|
7157
|
-
delta = i > 0 ? sub(curve[i], curve[i - 1]) : sub(curve[1], curve[0]);
|
|
7158
|
-
return norm(delta);
|
|
7159
|
-
});
|
|
7160
|
-
if (closed)
|
|
7161
|
-
tangents[last] = tangents[0];
|
|
7162
|
-
const t0 = tangents[0];
|
|
7163
|
-
let normal = norm(cross(t0, Math.abs(t0[1]) < 0.9 ? [0, 1, 0] : [1, 0, 0]));
|
|
7164
|
-
let previous = t0;
|
|
7165
|
-
const frames = [];
|
|
7166
|
-
for (const t of tangents) {
|
|
7167
|
-
const axis = cross(previous, t);
|
|
7168
|
-
const cosine = Math.max(-1, Math.min(1, dot(previous, t)));
|
|
7169
|
-
if (cosine > -1 + 0.00000001) {
|
|
7170
|
-
const turn = cross(axis, normal);
|
|
7171
|
-
const second = cross(axis, turn);
|
|
7172
|
-
normal = [
|
|
7173
|
-
normal[0] + turn[0] + second[0] / (1 + cosine),
|
|
7174
|
-
normal[1] + turn[1] + second[1] / (1 + cosine),
|
|
7175
|
-
normal[2] + turn[2] + second[2] / (1 + cosine)
|
|
7176
|
-
];
|
|
7177
|
-
}
|
|
7178
|
-
const projection = dot(normal, t);
|
|
7179
|
-
normal = norm(sub(normal, [t[0] * projection, t[1] * projection, t[2] * projection]));
|
|
7180
|
-
frames.push([normal, cross(t, normal)]);
|
|
7181
|
-
previous = t;
|
|
7182
|
-
}
|
|
7183
|
-
if (closed) {
|
|
7184
|
-
const end = frames[last][0], start = frames[0][0];
|
|
7185
|
-
const correction = Math.atan2(dot(t0, cross(end, start)), dot(end, start));
|
|
7186
|
-
const lengths = [0];
|
|
7187
|
-
for (let i = 1;i <= last; i++)
|
|
7188
|
-
lengths.push(lengths[i - 1] + distance(curve[i], curve[i - 1]));
|
|
7189
|
-
for (let i = 1;i <= last; i++) {
|
|
7190
|
-
const angle = correction * lengths[i] / lengths[last];
|
|
7191
|
-
const [n, bn] = frames[i];
|
|
7192
|
-
const c = Math.cos(angle), s = Math.sin(angle);
|
|
7193
|
-
const corrected = [n[0] * c + bn[0] * s, n[1] * c + bn[1] * s, n[2] * c + bn[2] * s];
|
|
7194
|
-
frames[i] = [corrected, cross(tangents[i], corrected)];
|
|
7195
|
-
}
|
|
7196
|
-
frames[last] = frames[0];
|
|
7197
|
-
}
|
|
7198
|
-
const b = new Builder;
|
|
7199
|
-
const ring = curve.map((c, i) => {
|
|
7200
|
-
const r = Math.max(0, radius(closed && i === last ? 0 : i / last));
|
|
7201
|
-
const [n, bn] = frames[i];
|
|
7202
|
-
const first = b.vertices.length / VERTEX_FLOATS;
|
|
7203
|
-
for (let j = 0;j <= sides; j++) {
|
|
7204
|
-
const a = (j === sides ? 0 : j / sides) * TAU2;
|
|
7205
|
-
const cosine = Math.cos(a), sine = Math.sin(a);
|
|
7206
|
-
const dir = [cosine * n[0] + sine * bn[0], cosine * n[1] + sine * bn[1], cosine * n[2] + sine * bn[2]];
|
|
7207
|
-
const rj = r * shape(j === sides ? 0 : j / sides);
|
|
7208
|
-
b.vertex([c[0] + dir[0] * rj, c[1] + dir[1] * rj, c[2] + dir[2] * rj], dir, j / sides, i / (curve.length - 1));
|
|
7209
|
-
}
|
|
7210
|
-
return { first, r };
|
|
7884
|
+
const count = (points.length - (closed ? 0 : 1)) * steps + 1;
|
|
7885
|
+
const last = count - 1;
|
|
7886
|
+
const radii = Array.from({ length: count }, (_, i) => Math.max(0, radius(closed && i === last ? 0 : i / last)));
|
|
7887
|
+
const color = options.color;
|
|
7888
|
+
const caps = !closed && (options.caps ?? true);
|
|
7889
|
+
const capColor = options.capColor ?? (perPoint(color) ? undefined : color);
|
|
7890
|
+
const capRings = perPoint(capColor) ? 8 : 1;
|
|
7891
|
+
const g = nativeSweep({
|
|
7892
|
+
kind: "tube",
|
|
7893
|
+
points,
|
|
7894
|
+
closed,
|
|
7895
|
+
sides,
|
|
7896
|
+
steps,
|
|
7897
|
+
radii,
|
|
7898
|
+
shape: shape && Array.from({ length: sides + 1 }, (_, j) => shape(j === sides ? 0 : j / sides)),
|
|
7899
|
+
smooth: !!shape || typeof options.radius === "function",
|
|
7900
|
+
caps,
|
|
7901
|
+
color: perPoint(color) ? undefined : flat(color),
|
|
7902
|
+
colorField: asField(color),
|
|
7903
|
+
capColor: perPoint(capColor) ? undefined : flat(capColor),
|
|
7904
|
+
capColorField: asField(capColor),
|
|
7905
|
+
rawCaps: typeof capColor === "function",
|
|
7906
|
+
capRings
|
|
7211
7907
|
});
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
}
|
|
7219
|
-
let side = facingOutward(fromBuilder(b));
|
|
7220
|
-
if (options.shape || typeof options.radius === "function")
|
|
7221
|
-
side = smoothNormals(side);
|
|
7222
|
-
const parts = [{ geometry: paintBy(side, options.color) }];
|
|
7223
|
-
if (!closed && (options.caps ?? true)) {
|
|
7224
|
-
const capColor = options.capColor ?? (typeof options.color === "function" ? undefined : options.color);
|
|
7225
|
-
const rings = typeof capColor === "function" ? 8 : 1;
|
|
7226
|
-
for (const [i, facing] of [
|
|
7227
|
-
[0, -1],
|
|
7228
|
-
[ring.length - 1, 1]
|
|
7229
|
-
]) {
|
|
7230
|
-
const { r } = ring[i];
|
|
7231
|
-
if (r < 0.000001)
|
|
7908
|
+
let at = count * (sides + 1);
|
|
7909
|
+
if (typeof color === "function")
|
|
7910
|
+
paintRange(g, 0, at, color);
|
|
7911
|
+
if (caps && typeof capColor === "function") {
|
|
7912
|
+
for (const i of [0, last]) {
|
|
7913
|
+
if (radii[i] < 0.000001)
|
|
7232
7914
|
continue;
|
|
7233
|
-
const
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
geometry: roundFace(curve[i], fn, fb, [t[0] * facing, t[1] * facing, t[2] * facing], (u) => r * shape(u === 1 ? 0 : u), TAU2, sides, rings, capColor)
|
|
7237
|
-
});
|
|
7238
|
-
}
|
|
7239
|
-
}
|
|
7240
|
-
return parts.length > 1 ? merge(parts) : parts[0].geometry;
|
|
7241
|
-
}
|
|
7242
|
-
function facingOutward(g) {
|
|
7243
|
-
const native = nativeGeometry3(g);
|
|
7244
|
-
if (native) {
|
|
7245
|
-
native.geometryFaceOutward(g.vertices.buffer, g.indices.buffer);
|
|
7246
|
-
return g;
|
|
7247
|
-
}
|
|
7248
|
-
const v = g.vertices;
|
|
7249
|
-
const at = (i, k) => v[g.indices[i] * VERTEX_FLOATS + k];
|
|
7250
|
-
for (let t = 0;t < g.indices.length; t += 3) {
|
|
7251
|
-
const e1 = [0, 1, 2].map((k) => at(t + 1, k) - at(t, k));
|
|
7252
|
-
const e2 = [0, 1, 2].map((k) => at(t + 2, k) - at(t, k));
|
|
7253
|
-
const face = [e1[1] * e2[2] - e1[2] * e2[1], e1[2] * e2[0] - e1[0] * e2[2], e1[0] * e2[1] - e1[1] * e2[0]];
|
|
7254
|
-
const n = [0, 1, 2].map((k) => at(t, k + 3) + at(t + 1, k + 3) + at(t + 2, k + 3));
|
|
7255
|
-
if (face[0] * n[0] + face[1] * n[1] + face[2] * n[2] < 0) {
|
|
7256
|
-
[g.indices[t + 1], g.indices[t + 2]] = [g.indices[t + 2], g.indices[t + 1]];
|
|
7915
|
+
const end = at + (capRings + 1) * (sides + 1);
|
|
7916
|
+
paintFace(g, at, end, TAU2, capColor);
|
|
7917
|
+
at = end;
|
|
7257
7918
|
}
|
|
7258
7919
|
}
|
|
7259
7920
|
return g;
|
|
@@ -7513,42 +8174,6 @@ function deformGeometry(geometry, deform) {
|
|
|
7513
8174
|
}
|
|
7514
8175
|
return smoothNormals({ vertices, indices: geometry.indices.slice() });
|
|
7515
8176
|
}
|
|
7516
|
-
// src/assets/surface.ts
|
|
7517
|
-
function parametricSurface(sample, options = {}) {
|
|
7518
|
-
const nu = options.uSegments ?? 32, nv = options.vSegments ?? 16;
|
|
7519
|
-
if (![nu, nv].every((n) => Number.isInteger(n) && n >= 1 && n <= 1024) || (nu + 1) * (nv + 1) > 1e6)
|
|
7520
|
-
throw new Error("parametricSurface: invalid segments or surface exceeds one million vertices");
|
|
7521
|
-
const vertices = new Float32Array((nu + 1) * (nv + 1) * 11);
|
|
7522
|
-
for (let y = 0;y <= nv; y++)
|
|
7523
|
-
for (let x = 0;x <= nu; x++) {
|
|
7524
|
-
const u = x / nu, v = y / nv;
|
|
7525
|
-
const p = sample(options.wrapU && x === nu ? 0 : u, options.wrapV && y === nv ? 0 : v);
|
|
7526
|
-
if (p.some((c) => !Number.isFinite(c)))
|
|
7527
|
-
throw new Error("parametricSurface: sample returned a non-finite position");
|
|
7528
|
-
vertices.set([p[0], p[1], p[2], 0, 1, 0, 1, 1, 1, u, v], (y * (nu + 1) + x) * 11);
|
|
7529
|
-
}
|
|
7530
|
-
const indices = [];
|
|
7531
|
-
const triangle = (a, b, c) => {
|
|
7532
|
-
const v = vertices;
|
|
7533
|
-
const oa = a * 11, ob = b * 11, oc = c * 11;
|
|
7534
|
-
const x1 = v[ob] - v[oa], y1 = v[ob + 1] - v[oa + 1], z1 = v[ob + 2] - v[oa + 2];
|
|
7535
|
-
const x2 = v[oc] - v[oa], y2 = v[oc + 1] - v[oa + 1], z2 = v[oc + 2] - v[oa + 2];
|
|
7536
|
-
if (Math.hypot(y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2) > 0)
|
|
7537
|
-
indices.push(a, b, c);
|
|
7538
|
-
};
|
|
7539
|
-
for (let y = 0;y < nv; y++)
|
|
7540
|
-
for (let x = 0;x < nu; x++) {
|
|
7541
|
-
const a = y * (nu + 1) + x, b = a + nu + 1;
|
|
7542
|
-
triangle(a, a + 1, b);
|
|
7543
|
-
triangle(a + 1, b + 1, b);
|
|
7544
|
-
}
|
|
7545
|
-
const geometry = smoothNormals({
|
|
7546
|
-
vertices,
|
|
7547
|
-
indices: new Uint32Array(indices)
|
|
7548
|
-
});
|
|
7549
|
-
return options.color ? recolor(geometry, typeof options.color === "function" ? options.color : () => options.color) : geometry;
|
|
7550
|
-
}
|
|
7551
|
-
|
|
7552
8177
|
// src/assets/loft.ts
|
|
7553
8178
|
function loft(sections, options = {}) {
|
|
7554
8179
|
if (sections.length < 2 || sections.some((s) => ![s.z, s.bottom, s.top, s.width, s.topWidth ?? s.width, s.square ?? 4].every(Number.isFinite) || s.width < 0 || (s.topWidth ?? s.width) < 0 || s.top <= s.bottom || (s.square ?? 4) < 1))
|
|
@@ -7560,53 +8185,23 @@ function loft(sections, options = {}) {
|
|
|
7560
8185
|
if (!Number.isInteger(n) || n < 6 || n > 512 || !Number.isInteger(steps) || steps < 1 || steps > 64)
|
|
7561
8186
|
throw new Error("loft: invalid around/smoothness");
|
|
7562
8187
|
const values = ordered.map((s) => [s.z, s.bottom, s.top, s.width, s.topWidth ?? s.width, s.square ?? 4]);
|
|
7563
|
-
const
|
|
7564
|
-
const
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
f[5] = Math.max(1, f[5]);
|
|
7572
|
-
return f;
|
|
7573
|
-
};
|
|
7574
|
-
const rowCount = (sections.length - 1) * steps;
|
|
7575
|
-
const rows = Array.from({ length: rowCount + 1 }, (_, i) => row(i / rowCount));
|
|
7576
|
-
const point = (u, v) => {
|
|
7577
|
-
const [z, bottom, top, width, topWidth, square] = rows[Math.round(v * rowCount)], angle = -Math.PI / 2 + u * Math.PI * 2;
|
|
7578
|
-
const c = Math.cos(angle), s = Math.sin(angle), exponent = 2 / square;
|
|
7579
|
-
const x = Math.sign(c) * Math.abs(c) ** exponent, y = Math.sign(s) * Math.abs(s) ** exponent;
|
|
7580
|
-
return [x * (y > 0 ? width + (topWidth - width) * y : width), (bottom + top) / 2 + y * (top - bottom) / 2, z];
|
|
7581
|
-
};
|
|
7582
|
-
const side = parametricSurface(point, {
|
|
7583
|
-
uSegments: n,
|
|
7584
|
-
vSegments: rowCount,
|
|
7585
|
-
wrapU: true
|
|
8188
|
+
const color = options.color;
|
|
8189
|
+
const g = nativeSweep({
|
|
8190
|
+
kind: "loft",
|
|
8191
|
+
sections: values,
|
|
8192
|
+
around: n,
|
|
8193
|
+
smoothness: steps,
|
|
8194
|
+
color: typeof color === "function" || color instanceof FieldFunction || !color ? undefined : [color[0], color[1], color[2]],
|
|
8195
|
+
colorField: color instanceof FieldFunction ? color : undefined
|
|
7586
8196
|
});
|
|
7587
|
-
|
|
7588
|
-
for (const [v, facing] of [
|
|
7589
|
-
[0, -1],
|
|
7590
|
-
[1, 1]
|
|
7591
|
-
]) {
|
|
7592
|
-
const section = rows[v * rowCount], cy = (section[1] + section[2]) / 2;
|
|
7593
|
-
const vertices = new Float32Array((n + 1) * 11), indices = [];
|
|
7594
|
-
vertices.set([0, cy, section[0], 0, 0, facing, 1, 1, 1, 0.5, 0.5]);
|
|
7595
|
-
for (let j = 0;j < n; j++) {
|
|
7596
|
-
const p = point(j / n, v), width = Math.max(section[3], section[4], 0.000001);
|
|
7597
|
-
vertices.set([p[0], p[1], p[2], 0, 0, facing, 1, 1, 1, 0.5 + p[0] / (2 * width), (p[1] - section[1]) / (section[2] - section[1])], (j + 1) * 11);
|
|
7598
|
-
const a = j + 1, b = (j + 1) % n + 1;
|
|
7599
|
-
if (facing === 1)
|
|
7600
|
-
indices.push(0, a, b);
|
|
7601
|
-
else
|
|
7602
|
-
indices.push(0, b, a);
|
|
7603
|
-
}
|
|
7604
|
-
parts.push({ geometry: { vertices, indices: new Uint32Array(indices) } });
|
|
7605
|
-
}
|
|
7606
|
-
return paint2(merge(parts), options.color);
|
|
8197
|
+
return typeof color === "function" ? paint2(g, color) : g;
|
|
7607
8198
|
}
|
|
7608
8199
|
function paint2(geometry, color) {
|
|
7609
|
-
|
|
8200
|
+
if (!color)
|
|
8201
|
+
return geometry;
|
|
8202
|
+
if (color instanceof FieldFunction)
|
|
8203
|
+
return recolor(geometry, color);
|
|
8204
|
+
return recolor(geometry, typeof color === "function" ? ({ position, normal }) => color(position, normal) : () => color);
|
|
7610
8205
|
}
|
|
7611
8206
|
function block(w, h, d, square = 6, color) {
|
|
7612
8207
|
return loft([
|
|
@@ -7643,6 +8238,41 @@ function smoothCurve(points) {
|
|
|
7643
8238
|
return (2 * t * t * t - 3 * t * t + 1) * y0 + (t * t * t - 2 * t * t + t) * h * slope(i) + (-2 * t * t * t + 3 * t * t) * y1 + (t * t * t - t * t) * h * slope(i + 1);
|
|
7644
8239
|
};
|
|
7645
8240
|
}
|
|
8241
|
+
// src/assets/surface.ts
|
|
8242
|
+
function parametricSurface(sample, options = {}) {
|
|
8243
|
+
const nu = options.uSegments ?? 32, nv = options.vSegments ?? 16;
|
|
8244
|
+
if (![nu, nv].every((n) => Number.isInteger(n) && n >= 1 && n <= 1024) || (nu + 1) * (nv + 1) > 1e6)
|
|
8245
|
+
throw new Error("parametricSurface: invalid segments or surface exceeds one million vertices");
|
|
8246
|
+
const vertices = new Float32Array((nu + 1) * (nv + 1) * 11);
|
|
8247
|
+
for (let y = 0;y <= nv; y++)
|
|
8248
|
+
for (let x = 0;x <= nu; x++) {
|
|
8249
|
+
const u = x / nu, v = y / nv;
|
|
8250
|
+
const p = sample(options.wrapU && x === nu ? 0 : u, options.wrapV && y === nv ? 0 : v);
|
|
8251
|
+
if (p.some((c) => !Number.isFinite(c)))
|
|
8252
|
+
throw new Error("parametricSurface: sample returned a non-finite position");
|
|
8253
|
+
vertices.set([p[0], p[1], p[2], 0, 1, 0, 1, 1, 1, u, v], (y * (nu + 1) + x) * 11);
|
|
8254
|
+
}
|
|
8255
|
+
const indices = [];
|
|
8256
|
+
const triangle = (a, b, c) => {
|
|
8257
|
+
const v = vertices;
|
|
8258
|
+
const oa = a * 11, ob = b * 11, oc = c * 11;
|
|
8259
|
+
const x1 = v[ob] - v[oa], y1 = v[ob + 1] - v[oa + 1], z1 = v[ob + 2] - v[oa + 2];
|
|
8260
|
+
const x2 = v[oc] - v[oa], y2 = v[oc + 1] - v[oa + 1], z2 = v[oc + 2] - v[oa + 2];
|
|
8261
|
+
if (Math.hypot(y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2) > 0)
|
|
8262
|
+
indices.push(a, b, c);
|
|
8263
|
+
};
|
|
8264
|
+
for (let y = 0;y < nv; y++)
|
|
8265
|
+
for (let x = 0;x < nu; x++) {
|
|
8266
|
+
const a = y * (nu + 1) + x, b = a + nu + 1;
|
|
8267
|
+
triangle(a, a + 1, b);
|
|
8268
|
+
triangle(a + 1, b + 1, b);
|
|
8269
|
+
}
|
|
8270
|
+
const geometry = smoothNormals({
|
|
8271
|
+
vertices,
|
|
8272
|
+
indices: new Uint32Array(indices)
|
|
8273
|
+
});
|
|
8274
|
+
return options.color ? recolor(geometry, typeof options.color === "function" ? options.color : () => options.color) : geometry;
|
|
8275
|
+
}
|
|
7646
8276
|
// src/media/audio.ts
|
|
7647
8277
|
var loader4 = new AssetLoader("audio");
|
|
7648
8278
|
function loadSound(source) {
|
|
@@ -7693,6 +8323,17 @@ var audio = {
|
|
|
7693
8323
|
if (voice)
|
|
7694
8324
|
NativeNayanEngine_web_default?.audioStop(voice);
|
|
7695
8325
|
},
|
|
8326
|
+
release(sound) {
|
|
8327
|
+
if (sound != null)
|
|
8328
|
+
NativeNayanEngine_web_default?.audioRelease?.(sound);
|
|
8329
|
+
},
|
|
8330
|
+
duration(sound) {
|
|
8331
|
+
return NativeNayanEngine_web_default?.audioDuration?.(sound) ?? 0;
|
|
8332
|
+
},
|
|
8333
|
+
levels(sound, perSecond = 30) {
|
|
8334
|
+
const buffer = NativeNayanEngine_web_default?.audioLevels?.(sound, perSecond);
|
|
8335
|
+
return buffer ? new Float32Array(buffer) : new Float32Array(0);
|
|
8336
|
+
},
|
|
7696
8337
|
get muted() {
|
|
7697
8338
|
return muted;
|
|
7698
8339
|
},
|
|
@@ -7717,6 +8358,108 @@ var audio = {
|
|
|
7717
8358
|
return NativeNayanEngine_web_default?.audioIsRunning() ?? false;
|
|
7718
8359
|
}
|
|
7719
8360
|
};
|
|
8361
|
+
// src/media/speechPlatform.web.ts
|
|
8362
|
+
var speechPlatform = {
|
|
8363
|
+
get supported() {
|
|
8364
|
+
return typeof window !== "undefined" && "speechSynthesis" in window && "SpeechSynthesisUtterance" in window;
|
|
8365
|
+
},
|
|
8366
|
+
async request(command) {
|
|
8367
|
+
await prepareEngine();
|
|
8368
|
+
return speech_request(command);
|
|
8369
|
+
}
|
|
8370
|
+
};
|
|
8371
|
+
|
|
8372
|
+
// src/media/speech.ts
|
|
8373
|
+
async function request(command) {
|
|
8374
|
+
if (!speechPlatform.supported)
|
|
8375
|
+
throw new Error("Speech is unavailable on this platform or engine build");
|
|
8376
|
+
const result = JSON.parse(await speechPlatform.request(JSON.stringify(command)));
|
|
8377
|
+
if (result.error)
|
|
8378
|
+
throw new Error(result.error);
|
|
8379
|
+
return result.value;
|
|
8380
|
+
}
|
|
8381
|
+
var speech = {
|
|
8382
|
+
get supported() {
|
|
8383
|
+
return speechPlatform.supported;
|
|
8384
|
+
},
|
|
8385
|
+
async speak(text, options = {}) {
|
|
8386
|
+
if (typeof text !== "string")
|
|
8387
|
+
throw new TypeError("Speech text must be a string");
|
|
8388
|
+
for (const [key, min, max] of [
|
|
8389
|
+
["rate", 0.1, 2],
|
|
8390
|
+
["pitch", 0.5, 2],
|
|
8391
|
+
["volume", 0, 1]
|
|
8392
|
+
]) {
|
|
8393
|
+
const value = options[key];
|
|
8394
|
+
if (value !== undefined && (!Number.isFinite(value) || value < min || value > max)) {
|
|
8395
|
+
throw new RangeError(`Speech ${key} must be between ${min} and ${max}`);
|
|
8396
|
+
}
|
|
8397
|
+
}
|
|
8398
|
+
for (const key of ["language", "voice"]) {
|
|
8399
|
+
if (options[key] !== undefined && typeof options[key] !== "string")
|
|
8400
|
+
throw new TypeError(`Speech ${key} must be a string`);
|
|
8401
|
+
}
|
|
8402
|
+
if (!text.trim())
|
|
8403
|
+
return;
|
|
8404
|
+
const { language, voice, rate, pitch, volume } = options;
|
|
8405
|
+
await request({ action: "speak", text, language, voice, rate, pitch, volume });
|
|
8406
|
+
},
|
|
8407
|
+
async stop() {
|
|
8408
|
+
await request({ action: "stop" });
|
|
8409
|
+
},
|
|
8410
|
+
async pause() {
|
|
8411
|
+
await request({ action: "pause" });
|
|
8412
|
+
},
|
|
8413
|
+
async resume() {
|
|
8414
|
+
await request({ action: "resume" });
|
|
8415
|
+
},
|
|
8416
|
+
isSpeakingAsync() {
|
|
8417
|
+
return request({ action: "isSpeaking" });
|
|
8418
|
+
},
|
|
8419
|
+
getAvailableVoicesAsync() {
|
|
8420
|
+
return request({ action: "voices" });
|
|
8421
|
+
}
|
|
8422
|
+
};
|
|
8423
|
+
// src/media/microphone.ts
|
|
8424
|
+
var STATES = { 0: "off", 1: "starting", 2: "listening", [-1]: "failed" };
|
|
8425
|
+
var microphone = {
|
|
8426
|
+
get supported() {
|
|
8427
|
+
return typeof NativeNayanEngine_web_default?.micStart === "function";
|
|
8428
|
+
},
|
|
8429
|
+
get permission() {
|
|
8430
|
+
const value = microphone.supported ? NativeNayanEngine_web_default.micPermission() : -1;
|
|
8431
|
+
return value > 0 ? "granted" : value < 0 ? "denied" : "undetermined";
|
|
8432
|
+
},
|
|
8433
|
+
requestPermission() {
|
|
8434
|
+
return microphone.supported ? NativeNayanEngine_web_default.micRequestPermission() : Promise.resolve(false);
|
|
8435
|
+
},
|
|
8436
|
+
start({ maxSeconds = 10 } = {}) {
|
|
8437
|
+
return microphone.supported && NativeNayanEngine_web_default.micStart(maxSeconds);
|
|
8438
|
+
},
|
|
8439
|
+
stop() {
|
|
8440
|
+
if (microphone.supported)
|
|
8441
|
+
NativeNayanEngine_web_default.micStop();
|
|
8442
|
+
},
|
|
8443
|
+
get state() {
|
|
8444
|
+
return microphone.supported ? STATES[NativeNayanEngine_web_default.micState()] ?? "off" : "off";
|
|
8445
|
+
},
|
|
8446
|
+
get level() {
|
|
8447
|
+
return microphone.supported ? NativeNayanEngine_web_default.micLevel() : 0;
|
|
8448
|
+
},
|
|
8449
|
+
get held() {
|
|
8450
|
+
return microphone.supported ? NativeNayanEngine_web_default.micHeld() : 0;
|
|
8451
|
+
},
|
|
8452
|
+
take(seconds = Infinity, { skipEnd = 0, levelsPerSecond = 30 } = {}) {
|
|
8453
|
+
if (!microphone.supported)
|
|
8454
|
+
return null;
|
|
8455
|
+
const id = NativeNayanEngine_web_default.micTake(Number.isFinite(seconds) ? seconds : 3600, skipEnd);
|
|
8456
|
+
if (id < 0)
|
|
8457
|
+
return null;
|
|
8458
|
+
const sound = id;
|
|
8459
|
+
const buffer = NativeNayanEngine_web_default.audioLevels(sound, levelsPerSecond);
|
|
8460
|
+
return { sound, duration: NativeNayanEngine_web_default.audioDuration(sound), levels: new Float32Array(buffer), levelsPerSecond };
|
|
8461
|
+
}
|
|
8462
|
+
};
|
|
7720
8463
|
// src/media/haptics.ts
|
|
7721
8464
|
var PATTERNS = {
|
|
7722
8465
|
success: [
|
|
@@ -7862,7 +8605,7 @@ class DrawingDocument {
|
|
|
7862
8605
|
boundTexture = null;
|
|
7863
8606
|
constructor(width, height, pixelRatio = 2) {
|
|
7864
8607
|
if (!NativeNayanEngine_web_default || typeof NativeNayanEngine_web_default.drawingCreate !== "function") {
|
|
7865
|
-
throw new Error("Drawing requires a native app rebuild with the updated Nayan
|
|
8608
|
+
throw new Error("Drawing requires a native app rebuild with the updated Nayan Game Engine.");
|
|
7866
8609
|
}
|
|
7867
8610
|
NativeNayanEngine_web_default.renderWarmUp?.();
|
|
7868
8611
|
const id = NativeNayanEngine_web_default.drawingCreate(width, height, pixelRatio);
|
|
@@ -8190,16 +8933,21 @@ var DrawingCanvas = memo(function DrawingCanvas({
|
|
|
8190
8933
|
export {
|
|
8191
8934
|
DrawingCanvas,
|
|
8192
8935
|
DrawingDocument,
|
|
8936
|
+
FieldFunction,
|
|
8937
|
+
FieldGraph,
|
|
8938
|
+
FieldRef,
|
|
8193
8939
|
GameView,
|
|
8194
8940
|
Joystick,
|
|
8195
8941
|
MAX_MESHES,
|
|
8196
8942
|
Path,
|
|
8197
8943
|
ProceduralCache,
|
|
8944
|
+
ProceduralWorld,
|
|
8198
8945
|
Scoreboard,
|
|
8199
8946
|
Solid,
|
|
8200
8947
|
World,
|
|
8201
8948
|
afterNextFrame,
|
|
8202
8949
|
audio,
|
|
8950
|
+
bakeModel,
|
|
8203
8951
|
block,
|
|
8204
8952
|
clearAssetCache,
|
|
8205
8953
|
createGeometryLods,
|
|
@@ -8210,11 +8958,17 @@ export {
|
|
|
8210
8958
|
effects,
|
|
8211
8959
|
ellipsoid,
|
|
8212
8960
|
extrude,
|
|
8961
|
+
faceColor,
|
|
8213
8962
|
frontLight,
|
|
8963
|
+
generateMesh,
|
|
8964
|
+
generateWorld,
|
|
8965
|
+
generateWorldAsync,
|
|
8214
8966
|
getGeometryStats,
|
|
8215
8967
|
getMeshIdLimit,
|
|
8216
8968
|
haptics,
|
|
8969
|
+
isBakeKept,
|
|
8217
8970
|
isEngineAvailable,
|
|
8971
|
+
isWorldKept,
|
|
8218
8972
|
lathe,
|
|
8219
8973
|
loadFont,
|
|
8220
8974
|
loadModel,
|
|
@@ -8222,14 +8976,19 @@ export {
|
|
|
8222
8976
|
loft,
|
|
8223
8977
|
measureText,
|
|
8224
8978
|
merge,
|
|
8979
|
+
microphone,
|
|
8225
8980
|
optimizeGeometry,
|
|
8226
8981
|
parametricSurface,
|
|
8227
8982
|
quat,
|
|
8228
8983
|
recolor,
|
|
8984
|
+
sectionColor,
|
|
8229
8985
|
shapeGeometry,
|
|
8230
8986
|
smoothCurve,
|
|
8231
8987
|
smoothNormals,
|
|
8232
8988
|
solidGeometry,
|
|
8989
|
+
speech,
|
|
8990
|
+
surfaceColor,
|
|
8991
|
+
surfaceDisplacement,
|
|
8233
8992
|
toColor,
|
|
8234
8993
|
tube,
|
|
8235
8994
|
useJoystick,
|
|
@@ -8237,4 +8996,4 @@ export {
|
|
|
8237
8996
|
warmUpEngine
|
|
8238
8997
|
};
|
|
8239
8998
|
|
|
8240
|
-
//# debugId=
|
|
8999
|
+
//# debugId=089DF8C707AEEB2364756E2164756E21
|