@nayan-ui/engine 1.0.0-beta.3 → 1.0.0-beta.5
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 +229 -113
- package/lib/module/assets/AssetLoader.js +1 -1
- package/lib/module/assets/ProceduralCache.js +31 -4
- package/lib/module/assets/font.js +10 -7
- package/lib/module/assets/model.js +41 -19
- package/lib/module/assets/storage.shared.js +2 -0
- package/lib/module/assets/storage.web.js +1 -0
- package/lib/module/assets/texture.js +14 -11
- package/lib/module/index.js +4 -1
- package/lib/module/media/audio.js +6 -3
- package/lib/module/native/BrowserEngine.js +17 -0
- package/lib/module/render/GameView.js +86 -18
- package/lib/module/render/light.js +24 -0
- package/lib/module/render/quality.js +12 -5
- package/lib/module/render/useWorld.js +72 -0
- package/lib/module/world/Scoreboard.js +21 -3
- package/lib/module/world/TransformBatch.js +5 -3
- package/lib/module/world/World.js +27 -13
- package/lib/module/world/color.js +80 -0
- package/lib/module/world/desc.js +6 -5
- package/lib/module/world/effects.js +20 -8
- package/lib/typescript/src/assets/AssetLoader.d.ts +1 -1
- package/lib/typescript/src/assets/ProceduralCache.d.ts +12 -0
- package/lib/typescript/src/assets/model.d.ts +10 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/native/EngineBridge.d.ts +6 -2
- package/lib/typescript/src/native/spec/NativeNayanEngine.d.ts +29 -0
- package/lib/typescript/src/render/GameView.d.ts +19 -7
- package/lib/typescript/src/render/light.d.ts +12 -0
- package/lib/typescript/src/render/quality.d.ts +4 -2
- package/lib/typescript/src/render/useWorld.d.ts +20 -0
- package/lib/typescript/src/types.d.ts +13 -4
- package/lib/typescript/src/world/Scoreboard.d.ts +12 -2
- package/lib/typescript/src/world/TransformBatch.d.ts +2 -2
- package/lib/typescript/src/world/World.d.ts +10 -2
- package/lib/typescript/src/world/color.d.ts +18 -0
- package/lib/typescript/src/world/effects.d.ts +13 -12
- package/lib/typescript/src/world/types.d.ts +11 -6
- package/lib/web/engine_core_bg.wasm +0 -0
- package/lib/web/index.js +521 -255
- package/lib/web/types/src/assets/AssetLoader.d.ts +1 -1
- package/lib/web/types/src/assets/ProceduralCache.d.ts +12 -0
- package/lib/web/types/src/assets/model.d.ts +10 -0
- package/lib/web/types/src/index.d.ts +4 -1
- package/lib/web/types/src/native/EngineBridge.d.ts +6 -2
- package/lib/web/types/src/native/spec/NativeNayanEngine.d.ts +29 -0
- package/lib/web/types/src/render/GameView.d.ts +19 -7
- package/lib/web/types/src/render/light.d.ts +11 -0
- package/lib/web/types/src/render/quality.d.ts +4 -2
- package/lib/web/types/src/render/useWorld.d.ts +19 -0
- package/lib/web/types/src/types.d.ts +13 -4
- package/lib/web/types/src/world/Scoreboard.d.ts +12 -2
- package/lib/web/types/src/world/TransformBatch.d.ts +2 -2
- package/lib/web/types/src/world/World.d.ts +10 -2
- package/lib/web/types/src/world/color.d.ts +17 -0
- package/lib/web/types/src/world/effects.d.ts +13 -12
- package/lib/web/types/src/world/types.d.ts +11 -6
- package/native/android/src/main/java/com/nayanui/engine/EngineSurfaceView.java +87 -26
- 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 +9 -0
- package/native/cpp/NayanEngineModule.cpp +171 -0
- package/native/cpp/NayanEngineModule.h +30 -0
- package/native/cpp/generated/NayanEngineSpecJSI.h +105 -0
- package/native/ios/NayanEngineSurface.mm +30 -1
- package/package.json +2 -2
- package/src/native/spec/NativeNayanEngine.ts +39 -0
package/lib/web/index.js
CHANGED
|
@@ -1066,7 +1066,7 @@ function __wbg_get_imports() {
|
|
|
1066
1066
|
const a = state0.a;
|
|
1067
1067
|
state0.a = 0;
|
|
1068
1068
|
try {
|
|
1069
|
-
return
|
|
1069
|
+
return __wasm_bindgen_func_elem_9779(a, state0.b, arg0, arg1);
|
|
1070
1070
|
} finally {
|
|
1071
1071
|
state0.a = a;
|
|
1072
1072
|
}
|
|
@@ -2069,23 +2069,23 @@ function __wbg_get_imports() {
|
|
|
2069
2069
|
}, arguments);
|
|
2070
2070
|
},
|
|
2071
2071
|
__wbindgen_generic_0000000000000001: function(arg0, arg1) {
|
|
2072
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2072
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_9777);
|
|
2073
2073
|
return addHeapObject(ret);
|
|
2074
2074
|
},
|
|
2075
2075
|
__wbindgen_generic_0000000000000002: function(arg0, arg1) {
|
|
2076
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2076
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2414);
|
|
2077
2077
|
return addHeapObject(ret);
|
|
2078
2078
|
},
|
|
2079
2079
|
__wbindgen_generic_0000000000000003: function(arg0, arg1) {
|
|
2080
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2080
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2415);
|
|
2081
2081
|
return addHeapObject(ret);
|
|
2082
2082
|
},
|
|
2083
2083
|
__wbindgen_generic_0000000000000004: function(arg0, arg1) {
|
|
2084
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2084
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2414_9);
|
|
2085
2085
|
return addHeapObject(ret);
|
|
2086
2086
|
},
|
|
2087
2087
|
__wbindgen_generic_0000000000000005: function(arg0, arg1) {
|
|
2088
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
2088
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_2414_10);
|
|
2089
2089
|
return addHeapObject(ret);
|
|
2090
2090
|
},
|
|
2091
2091
|
__wbindgen_generic_0000000000000006: function(arg0) {
|
|
@@ -2138,16 +2138,16 @@ function __wbg_get_imports() {
|
|
|
2138
2138
|
"./snippets/engine-core-64626f8edd8232bb/inline0.js": exports_inline0
|
|
2139
2139
|
};
|
|
2140
2140
|
}
|
|
2141
|
-
function
|
|
2142
|
-
wasm.
|
|
2141
|
+
function __wasm_bindgen_func_elem_2415(arg0, arg1, arg2) {
|
|
2142
|
+
wasm.__wasm_bindgen_func_elem_2415(arg0, arg1, addHeapObject(arg2));
|
|
2143
2143
|
}
|
|
2144
|
-
function
|
|
2145
|
-
wasm.
|
|
2144
|
+
function __wasm_bindgen_func_elem_9779(arg0, arg1, arg2, arg3) {
|
|
2145
|
+
wasm.__wasm_bindgen_func_elem_9779(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
2146
2146
|
}
|
|
2147
|
-
function
|
|
2147
|
+
function __wasm_bindgen_func_elem_9777(arg0, arg1, arg2) {
|
|
2148
2148
|
try {
|
|
2149
2149
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2150
|
-
wasm.
|
|
2150
|
+
wasm.__wasm_bindgen_func_elem_9777(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2151
2151
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2152
2152
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2153
2153
|
if (r1) {
|
|
@@ -2157,10 +2157,10 @@ function __wasm_bindgen_func_elem_9774(arg0, arg1, arg2) {
|
|
|
2157
2157
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2158
2158
|
}
|
|
2159
2159
|
}
|
|
2160
|
-
function
|
|
2160
|
+
function __wasm_bindgen_func_elem_2414(arg0, arg1, arg2) {
|
|
2161
2161
|
try {
|
|
2162
2162
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2163
|
-
wasm.
|
|
2163
|
+
wasm.__wasm_bindgen_func_elem_2414(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2164
2164
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2165
2165
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2166
2166
|
if (r1) {
|
|
@@ -2170,10 +2170,10 @@ function __wasm_bindgen_func_elem_2411(arg0, arg1, arg2) {
|
|
|
2170
2170
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2171
2171
|
}
|
|
2172
2172
|
}
|
|
2173
|
-
function
|
|
2173
|
+
function __wasm_bindgen_func_elem_2414_9(arg0, arg1, arg2) {
|
|
2174
2174
|
try {
|
|
2175
2175
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2176
|
-
wasm.
|
|
2176
|
+
wasm.__wasm_bindgen_func_elem_2414_9(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2177
2177
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2178
2178
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2179
2179
|
if (r1) {
|
|
@@ -2183,10 +2183,10 @@ function __wasm_bindgen_func_elem_2411_9(arg0, arg1, arg2) {
|
|
|
2183
2183
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
2184
2184
|
}
|
|
2185
2185
|
}
|
|
2186
|
-
function
|
|
2186
|
+
function __wasm_bindgen_func_elem_2414_10(arg0, arg1, arg2) {
|
|
2187
2187
|
try {
|
|
2188
2188
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
2189
|
-
wasm.
|
|
2189
|
+
wasm.__wasm_bindgen_func_elem_2414_10(retptr, arg0, arg1, addHeapObject(arg2));
|
|
2190
2190
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
2191
2191
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
2192
2192
|
if (r1) {
|
|
@@ -2974,6 +2974,7 @@ function createBrowserEngine(core) {
|
|
|
2974
2974
|
fn(name, id, p);
|
|
2975
2975
|
return Array.from(float ? new Float32Array(memory(), p, count) : new Uint32Array(memory(), p, count));
|
|
2976
2976
|
};
|
|
2977
|
+
const settle = (work) => new Promise((resolve) => resolve(work()));
|
|
2977
2978
|
const engine = {
|
|
2978
2979
|
createWorld(capacity) {
|
|
2979
2980
|
if (!Number.isInteger(capacity) || capacity < 1 || capacity > 1e6)
|
|
@@ -3172,6 +3173,19 @@ function createBrowserEngine(core) {
|
|
|
3172
3173
|
const [x, y, z] = dimensions("model_size", mesh, 3, true);
|
|
3173
3174
|
return [x, y, z];
|
|
3174
3175
|
},
|
|
3176
|
+
modelLoadAsync(value, center, fit) {
|
|
3177
|
+
return settle(() => engine.modelLoad(value, center, fit));
|
|
3178
|
+
},
|
|
3179
|
+
textureLoadAsync(value) {
|
|
3180
|
+
return settle(() => engine.textureLoad(value));
|
|
3181
|
+
},
|
|
3182
|
+
fontLoadAsync(value, depth, chars, weight) {
|
|
3183
|
+
return settle(() => engine.fontLoad(value, depth, chars, weight));
|
|
3184
|
+
},
|
|
3185
|
+
audioLoadAsync(value) {
|
|
3186
|
+
return settle(() => engine.audioLoad(value));
|
|
3187
|
+
},
|
|
3188
|
+
renderModel: (mesh, texture, shine) => typeof core.engine_render_model === "function" && fn("render_model", mesh, texture, shine) !== 0,
|
|
3175
3189
|
modelTexture: (mesh) => fn("model_texture", mesh),
|
|
3176
3190
|
meshAlias: (mesh) => fn("mesh_alias", mesh),
|
|
3177
3191
|
meshCreate(vertices, indices) {
|
|
@@ -3386,137 +3400,6 @@ function prepareEngine2() {
|
|
|
3386
3400
|
return prepareEngine();
|
|
3387
3401
|
}
|
|
3388
3402
|
|
|
3389
|
-
// src/types.ts
|
|
3390
|
-
var MAX_MESHES = 4096;
|
|
3391
|
-
var SHAPE_MESH = {
|
|
3392
|
-
cube: 0,
|
|
3393
|
-
sphere: 1,
|
|
3394
|
-
plane: 2,
|
|
3395
|
-
cylinder: 3,
|
|
3396
|
-
cone: 4,
|
|
3397
|
-
capsule: 5,
|
|
3398
|
-
torus: 6,
|
|
3399
|
-
roundedBox: 7,
|
|
3400
|
-
puff: 8,
|
|
3401
|
-
flame: 9,
|
|
3402
|
-
none: 15
|
|
3403
|
-
};
|
|
3404
|
-
|
|
3405
|
-
// src/render/meshes.ts
|
|
3406
|
-
var VERTEX_FLOATS = 11;
|
|
3407
|
-
|
|
3408
|
-
class Builder {
|
|
3409
|
-
vertices = [];
|
|
3410
|
-
indices = [];
|
|
3411
|
-
vertex(p, n, u, v) {
|
|
3412
|
-
this.vertices.push(p[0], p[1], p[2], n[0], n[1], n[2], 1, 1, 1, u, v);
|
|
3413
|
-
return this.vertices.length / VERTEX_FLOATS - 1;
|
|
3414
|
-
}
|
|
3415
|
-
quad(a, b, c, d) {
|
|
3416
|
-
this.indices.push(a, b, c, a, c, d);
|
|
3417
|
-
}
|
|
3418
|
-
grid(rows, cols, at) {
|
|
3419
|
-
const first = this.vertices.length / VERTEX_FLOATS;
|
|
3420
|
-
for (let i = 0;i <= rows; i++) {
|
|
3421
|
-
for (let j = 0;j <= cols; j++) {
|
|
3422
|
-
const [p, n] = at(j / cols, i / rows);
|
|
3423
|
-
this.vertex(p, n, j / cols, i / rows);
|
|
3424
|
-
}
|
|
3425
|
-
}
|
|
3426
|
-
for (let i = 0;i < rows; i++) {
|
|
3427
|
-
for (let j = 0;j < cols; j++) {
|
|
3428
|
-
const a = first + i * (cols + 1) + j;
|
|
3429
|
-
const b = a + cols + 1;
|
|
3430
|
-
this.indices.push(a, b, a + 1, a + 1, b, b + 1);
|
|
3431
|
-
}
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
disc(y, radius, facing, segments) {
|
|
3435
|
-
const center = this.vertex([0, y, 0], [0, facing, 0], 0.5, 0.5);
|
|
3436
|
-
const first = center + 1;
|
|
3437
|
-
for (let j = 0;j <= segments; j++) {
|
|
3438
|
-
const t = j / segments * TAU;
|
|
3439
|
-
const x = Math.cos(t);
|
|
3440
|
-
const z = Math.sin(t);
|
|
3441
|
-
this.vertex([x * radius, y, z * radius], [0, facing, 0], 0.5 + x / 2, 0.5 + z / 2);
|
|
3442
|
-
}
|
|
3443
|
-
for (let j = 0;j < segments; j++) {
|
|
3444
|
-
if (facing === 1)
|
|
3445
|
-
this.indices.push(center, first + j + 1, first + j);
|
|
3446
|
-
else
|
|
3447
|
-
this.indices.push(center, first + j, first + j + 1);
|
|
3448
|
-
}
|
|
3449
|
-
}
|
|
3450
|
-
}
|
|
3451
|
-
var TAU = Math.PI * 2;
|
|
3452
|
-
var registered = new Map;
|
|
3453
|
-
var idLimit = 16;
|
|
3454
|
-
function registerMesh(mesh, info, uploadGeometry = true) {
|
|
3455
|
-
registered.set(mesh, info);
|
|
3456
|
-
idLimit = Math.max(idLimit, mesh + 1);
|
|
3457
|
-
if (uploadGeometry)
|
|
3458
|
-
upload(mesh, info);
|
|
3459
|
-
}
|
|
3460
|
-
var getMeshIdLimit = () => idLimit;
|
|
3461
|
-
function exact(data) {
|
|
3462
|
-
const { buffer, byteOffset, byteLength } = data;
|
|
3463
|
-
if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength)
|
|
3464
|
-
return buffer;
|
|
3465
|
-
return data.slice().buffer;
|
|
3466
|
-
}
|
|
3467
|
-
function upload(mesh, info) {
|
|
3468
|
-
const { vertices, indices } = info.geometry;
|
|
3469
|
-
NativeNayanEngine_web_default?.renderMesh(mesh, exact(vertices), exact(indices), info.texture ?? -1, info.shine ?? 0);
|
|
3470
|
-
}
|
|
3471
|
-
var builtInsUploaded = false;
|
|
3472
|
-
function uploadBuiltInMeshes() {
|
|
3473
|
-
if (builtInsUploaded)
|
|
3474
|
-
return;
|
|
3475
|
-
NativeNayanEngine_web_default?.generateBuiltinMeshes();
|
|
3476
|
-
builtInsUploaded = true;
|
|
3477
|
-
}
|
|
3478
|
-
function warmUpEngine() {
|
|
3479
|
-
const pending = prepareEngine2();
|
|
3480
|
-
const warm = () => {
|
|
3481
|
-
const native = NativeNayanEngine_web_default;
|
|
3482
|
-
if (!native)
|
|
3483
|
-
return;
|
|
3484
|
-
uploadBuiltInMeshes();
|
|
3485
|
-
if (typeof native.renderWarmUp === "function")
|
|
3486
|
-
native.renderWarmUp();
|
|
3487
|
-
};
|
|
3488
|
-
if (pending)
|
|
3489
|
-
return pending.then(warm);
|
|
3490
|
-
warm();
|
|
3491
|
-
return Promise.resolve();
|
|
3492
|
-
}
|
|
3493
|
-
function meshInfo(mesh) {
|
|
3494
|
-
const info = registered.get(mesh);
|
|
3495
|
-
if (info || mesh === SHAPE_MESH.none)
|
|
3496
|
-
return info;
|
|
3497
|
-
const shape = Object.keys(SHAPE_MESH).find((s) => SHAPE_MESH[s] === mesh);
|
|
3498
|
-
if (!shape || shape === "none")
|
|
3499
|
-
return;
|
|
3500
|
-
const native = NativeNayanEngine_web_default;
|
|
3501
|
-
if (!native)
|
|
3502
|
-
return;
|
|
3503
|
-
let vertices = new Float32Array(native.renderMeshVertices(mesh));
|
|
3504
|
-
if (!vertices.length && !builtInsUploaded && typeof native.generateBuiltinMeshes === "function") {
|
|
3505
|
-
try {
|
|
3506
|
-
uploadBuiltInMeshes();
|
|
3507
|
-
} catch {
|
|
3508
|
-
return;
|
|
3509
|
-
}
|
|
3510
|
-
vertices = new Float32Array(native.renderMeshVertices(mesh));
|
|
3511
|
-
}
|
|
3512
|
-
const indices = new Uint32Array(native.renderMeshIndices(mesh));
|
|
3513
|
-
if (!vertices.length)
|
|
3514
|
-
return;
|
|
3515
|
-
const made = { geometry: { vertices, indices } };
|
|
3516
|
-
registered.set(mesh, made);
|
|
3517
|
-
return made;
|
|
3518
|
-
}
|
|
3519
|
-
|
|
3520
3403
|
// src/assets/CacheGeneration.ts
|
|
3521
3404
|
var generation = 0;
|
|
3522
3405
|
var cacheGeneration = () => generation;
|
|
@@ -3526,6 +3409,7 @@ var advanceCacheGeneration = () => ++generation;
|
|
|
3526
3409
|
function proceduralStorage(revision) {
|
|
3527
3410
|
const native = NativeNayanEngine_web_default;
|
|
3528
3411
|
return {
|
|
3412
|
+
verified: true,
|
|
3529
3413
|
read(key) {
|
|
3530
3414
|
if (typeof native?.cacheRead !== "function")
|
|
3531
3415
|
return null;
|
|
@@ -3562,6 +3446,7 @@ function proceduralStorage2(revision) {
|
|
|
3562
3446
|
if (!storage)
|
|
3563
3447
|
return;
|
|
3564
3448
|
return {
|
|
3449
|
+
verified: storage.verified,
|
|
3565
3450
|
read: storage.read,
|
|
3566
3451
|
write(key, bytes) {
|
|
3567
3452
|
storage.write(key, bytes);
|
|
@@ -3696,7 +3581,7 @@ class AssetLoader {
|
|
|
3696
3581
|
throw new Error("the engine core is not linked into this build");
|
|
3697
3582
|
const { bytes } = await loadAssetBytes(source);
|
|
3698
3583
|
try {
|
|
3699
|
-
return decode(NativeNayanEngine_web_default, bytes);
|
|
3584
|
+
return await decode(NativeNayanEngine_web_default, bytes);
|
|
3700
3585
|
} catch (cause) {
|
|
3701
3586
|
forgetAssetBytes(uri);
|
|
3702
3587
|
throw cause;
|
|
@@ -3716,6 +3601,137 @@ class AssetLoader {
|
|
|
3716
3601
|
}
|
|
3717
3602
|
}
|
|
3718
3603
|
|
|
3604
|
+
// src/types.ts
|
|
3605
|
+
var MAX_MESHES = 4096;
|
|
3606
|
+
var SHAPE_MESH = {
|
|
3607
|
+
cube: 0,
|
|
3608
|
+
sphere: 1,
|
|
3609
|
+
plane: 2,
|
|
3610
|
+
cylinder: 3,
|
|
3611
|
+
cone: 4,
|
|
3612
|
+
capsule: 5,
|
|
3613
|
+
torus: 6,
|
|
3614
|
+
roundedBox: 7,
|
|
3615
|
+
puff: 8,
|
|
3616
|
+
flame: 9,
|
|
3617
|
+
none: 15
|
|
3618
|
+
};
|
|
3619
|
+
|
|
3620
|
+
// src/render/meshes.ts
|
|
3621
|
+
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
|
+
var TAU = Math.PI * 2;
|
|
3667
|
+
var registered = new Map;
|
|
3668
|
+
var idLimit = 16;
|
|
3669
|
+
function registerMesh(mesh, info, uploadGeometry = true) {
|
|
3670
|
+
registered.set(mesh, info);
|
|
3671
|
+
idLimit = Math.max(idLimit, mesh + 1);
|
|
3672
|
+
if (uploadGeometry)
|
|
3673
|
+
upload(mesh, info);
|
|
3674
|
+
}
|
|
3675
|
+
var getMeshIdLimit = () => idLimit;
|
|
3676
|
+
function exact(data) {
|
|
3677
|
+
const { buffer, byteOffset, byteLength } = data;
|
|
3678
|
+
if (buffer instanceof ArrayBuffer && byteOffset === 0 && byteLength === buffer.byteLength)
|
|
3679
|
+
return buffer;
|
|
3680
|
+
return data.slice().buffer;
|
|
3681
|
+
}
|
|
3682
|
+
function upload(mesh, info) {
|
|
3683
|
+
const { vertices, indices } = info.geometry;
|
|
3684
|
+
NativeNayanEngine_web_default?.renderMesh(mesh, exact(vertices), exact(indices), info.texture ?? -1, info.shine ?? 0);
|
|
3685
|
+
}
|
|
3686
|
+
var builtInsUploaded = false;
|
|
3687
|
+
function uploadBuiltInMeshes() {
|
|
3688
|
+
if (builtInsUploaded)
|
|
3689
|
+
return;
|
|
3690
|
+
NativeNayanEngine_web_default?.generateBuiltinMeshes();
|
|
3691
|
+
builtInsUploaded = true;
|
|
3692
|
+
}
|
|
3693
|
+
function warmUpEngine() {
|
|
3694
|
+
const pending = prepareEngine2();
|
|
3695
|
+
const warm = () => {
|
|
3696
|
+
const native = NativeNayanEngine_web_default;
|
|
3697
|
+
if (!native)
|
|
3698
|
+
return;
|
|
3699
|
+
uploadBuiltInMeshes();
|
|
3700
|
+
if (typeof native.renderWarmUp === "function")
|
|
3701
|
+
native.renderWarmUp();
|
|
3702
|
+
};
|
|
3703
|
+
if (pending)
|
|
3704
|
+
return pending.then(warm);
|
|
3705
|
+
warm();
|
|
3706
|
+
return Promise.resolve();
|
|
3707
|
+
}
|
|
3708
|
+
function meshInfo(mesh) {
|
|
3709
|
+
const info = registered.get(mesh);
|
|
3710
|
+
if (info || mesh === SHAPE_MESH.none)
|
|
3711
|
+
return info;
|
|
3712
|
+
const shape = Object.keys(SHAPE_MESH).find((s) => SHAPE_MESH[s] === mesh);
|
|
3713
|
+
if (!shape || shape === "none")
|
|
3714
|
+
return;
|
|
3715
|
+
const native = NativeNayanEngine_web_default;
|
|
3716
|
+
if (!native)
|
|
3717
|
+
return;
|
|
3718
|
+
let vertices = new Float32Array(native.renderMeshVertices(mesh));
|
|
3719
|
+
if (!vertices.length && !builtInsUploaded && typeof native.generateBuiltinMeshes === "function") {
|
|
3720
|
+
try {
|
|
3721
|
+
uploadBuiltInMeshes();
|
|
3722
|
+
} catch {
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
vertices = new Float32Array(native.renderMeshVertices(mesh));
|
|
3726
|
+
}
|
|
3727
|
+
const indices = new Uint32Array(native.renderMeshIndices(mesh));
|
|
3728
|
+
if (!vertices.length)
|
|
3729
|
+
return;
|
|
3730
|
+
const made = { geometry: { vertices, indices } };
|
|
3731
|
+
registered.set(mesh, made);
|
|
3732
|
+
return made;
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3719
3735
|
// src/assets/model.ts
|
|
3720
3736
|
var loader = new AssetLoader("loadModel");
|
|
3721
3737
|
function nativeGeometry(mesh) {
|
|
@@ -3724,6 +3740,18 @@ function nativeGeometry(mesh) {
|
|
|
3724
3740
|
indices: new Uint32Array(NativeNayanEngine_web_default.modelIndices(mesh))
|
|
3725
3741
|
};
|
|
3726
3742
|
}
|
|
3743
|
+
function registerCoreMesh(mesh, info = {}, geometry = () => nativeGeometry(mesh)) {
|
|
3744
|
+
const native = NativeNayanEngine_web_default;
|
|
3745
|
+
let cached;
|
|
3746
|
+
const inRust = typeof native.renderModel === "function" && native.renderModel(mesh, info.texture ?? -1, info.shine ?? 0);
|
|
3747
|
+
registerMesh(mesh, {
|
|
3748
|
+
get geometry() {
|
|
3749
|
+
return cached ??= geometry();
|
|
3750
|
+
},
|
|
3751
|
+
texture: info.texture,
|
|
3752
|
+
shine: info.shine
|
|
3753
|
+
}, !inRust);
|
|
3754
|
+
}
|
|
3727
3755
|
var materials = new Map;
|
|
3728
3756
|
function registerModelMesh(mesh, shine) {
|
|
3729
3757
|
const info = meshInfo(mesh);
|
|
@@ -3736,11 +3764,7 @@ function registerModelMesh(mesh, shine) {
|
|
|
3736
3764
|
const id = info ? NativeNayanEngine_web_default.meshAlias(mesh) : mesh;
|
|
3737
3765
|
if (id < 0)
|
|
3738
3766
|
throw new Error(NativeNayanEngine_web_default.loadError() || "couldn't register a material variant");
|
|
3739
|
-
|
|
3740
|
-
geometry: info?.geometry ?? nativeGeometry(id),
|
|
3741
|
-
texture: info?.texture,
|
|
3742
|
-
shine
|
|
3743
|
-
});
|
|
3767
|
+
registerCoreMesh(id, { texture: info?.texture, shine }, info ? () => info.geometry : undefined);
|
|
3744
3768
|
materials.set(key, id);
|
|
3745
3769
|
return id;
|
|
3746
3770
|
}
|
|
@@ -3749,25 +3773,25 @@ function loadModel(source, options = {}) {
|
|
|
3749
3773
|
const fit = options.fit ?? 0;
|
|
3750
3774
|
const shine = Math.max(0, Math.min(1, options.shine ?? 0));
|
|
3751
3775
|
return loader.load(source, (native, bytes) => {
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
const texture = native.modelTexture(mesh);
|
|
3756
|
-
registerMesh(mesh, {
|
|
3757
|
-
geometry: nativeGeometry(mesh),
|
|
3758
|
-
texture: texture >= 0 ? texture : undefined,
|
|
3759
|
-
shine
|
|
3760
|
-
});
|
|
3761
|
-
const [x, y, z] = native.modelSize(mesh);
|
|
3762
|
-
const rig = JSON.parse(native.modelRig(mesh));
|
|
3763
|
-
return {
|
|
3764
|
-
animations: rig.clips,
|
|
3765
|
-
jointCount: rig.joints,
|
|
3766
|
-
id: mesh,
|
|
3767
|
-
size: [x, y, z]
|
|
3768
|
-
};
|
|
3776
|
+
if (typeof native.modelLoadAsync === "function")
|
|
3777
|
+
return native.modelLoadAsync(bytes, center, fit).then((mesh) => finishModel(native, mesh, shine));
|
|
3778
|
+
return finishModel(native, native.modelLoad(bytes, center, fit), shine);
|
|
3769
3779
|
}, [center, fit, shine]);
|
|
3770
3780
|
}
|
|
3781
|
+
function finishModel(native, mesh, shine) {
|
|
3782
|
+
if (mesh < 0)
|
|
3783
|
+
throw new Error(native.loadError() || "not a glTF model");
|
|
3784
|
+
const texture = native.modelTexture(mesh);
|
|
3785
|
+
registerCoreMesh(mesh, { texture: texture >= 0 ? texture : undefined, shine });
|
|
3786
|
+
const [x, y, z] = native.modelSize(mesh);
|
|
3787
|
+
const rig = JSON.parse(native.modelRig(mesh));
|
|
3788
|
+
return {
|
|
3789
|
+
animations: rig.clips,
|
|
3790
|
+
jointCount: rig.joints,
|
|
3791
|
+
id: mesh,
|
|
3792
|
+
size: [x, y, z]
|
|
3793
|
+
};
|
|
3794
|
+
}
|
|
3771
3795
|
|
|
3772
3796
|
// src/assets/font.ts
|
|
3773
3797
|
var DEFAULT_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~×÷±−°·•–—…‘’“”";
|
|
@@ -3783,7 +3807,11 @@ function loadFont(source, options = {}) {
|
|
|
3783
3807
|
const chars = [...new Set(`${options.chars ?? DEFAULT_CHARS} ?`.normalize("NFC"))].filter((ch) => !isInvisible(ch)).join("");
|
|
3784
3808
|
const weight = options.weight ?? 0;
|
|
3785
3809
|
const pending = loader2.load(source, (native, bytes) => {
|
|
3786
|
-
|
|
3810
|
+
if (typeof native.fontLoadAsync === "function")
|
|
3811
|
+
return native.fontLoadAsync(bytes, depth, chars, weight).then((id) => finish(native, bytes, id));
|
|
3812
|
+
return finish(native, bytes, native.fontLoad(bytes, depth, chars, weight));
|
|
3813
|
+
}, [depth, weight]);
|
|
3814
|
+
function finish(native, bytes, id) {
|
|
3787
3815
|
if (id < 0)
|
|
3788
3816
|
throw new Error(native.loadError() || "not a TrueType / OpenType font");
|
|
3789
3817
|
const glyphs = new Map;
|
|
@@ -3793,7 +3821,7 @@ function loadFont(source, options = {}) {
|
|
|
3793
3821
|
for (let i = 0;i + 3 <= data.length - 1; i += 3) {
|
|
3794
3822
|
const mesh = data[i + 1];
|
|
3795
3823
|
if (mesh >= 0 && !registered.has(mesh)) {
|
|
3796
|
-
|
|
3824
|
+
registerCoreMesh(mesh);
|
|
3797
3825
|
registered.add(mesh);
|
|
3798
3826
|
}
|
|
3799
3827
|
glyphs.set(String.fromCodePoint(data[i]), {
|
|
@@ -3827,7 +3855,7 @@ function loadFont(source, options = {}) {
|
|
|
3827
3855
|
}
|
|
3828
3856
|
});
|
|
3829
3857
|
return font;
|
|
3830
|
-
}
|
|
3858
|
+
}
|
|
3831
3859
|
return pending.then((font) => {
|
|
3832
3860
|
extend.get(font)?.(chars);
|
|
3833
3861
|
return font;
|
|
@@ -3882,11 +3910,13 @@ function layoutText(font, text, align, options = {}) {
|
|
|
3882
3910
|
var loader3 = new AssetLoader("loadTexture");
|
|
3883
3911
|
function loadTexture(source) {
|
|
3884
3912
|
return loader3.load(source, (native, bytes) => {
|
|
3885
|
-
const
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
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));
|
|
3890
3920
|
});
|
|
3891
3921
|
}
|
|
3892
3922
|
var variants = new Map;
|
|
@@ -3900,16 +3930,76 @@ function texturedMesh(mesh, texture) {
|
|
|
3900
3930
|
id = NativeNayanEngine_web_default.meshAlias(mesh);
|
|
3901
3931
|
if (id < 0)
|
|
3902
3932
|
throw new Error(`texture: ${NativeNayanEngine_web_default.loadError()}`);
|
|
3903
|
-
|
|
3904
|
-
geometry: base.geometry,
|
|
3905
|
-
texture: texture.id,
|
|
3906
|
-
shine: base.shine
|
|
3907
|
-
});
|
|
3933
|
+
registerCoreMesh(id, { texture: texture.id, shine: base.shine }, () => base.geometry);
|
|
3908
3934
|
variants.set(key, id);
|
|
3909
3935
|
}
|
|
3910
3936
|
return id;
|
|
3911
3937
|
}
|
|
3912
3938
|
|
|
3939
|
+
// src/world/color.ts
|
|
3940
|
+
var HEX = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
3941
|
+
var RGB = /^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+%?)\s*)?\)$/i;
|
|
3942
|
+
var NAMED = {
|
|
3943
|
+
transparent: [0, 0, 0, 0],
|
|
3944
|
+
black: [0, 0, 0, 1],
|
|
3945
|
+
white: [1, 1, 1, 1],
|
|
3946
|
+
red: [1, 0, 0, 1],
|
|
3947
|
+
green: [0, 128 / 255, 0, 1],
|
|
3948
|
+
blue: [0, 0, 1, 1],
|
|
3949
|
+
yellow: [1, 1, 0, 1],
|
|
3950
|
+
orange: [1, 165 / 255, 0, 1],
|
|
3951
|
+
purple: [128 / 255, 0, 128 / 255, 1],
|
|
3952
|
+
gray: [128 / 255, 128 / 255, 128 / 255, 1],
|
|
3953
|
+
grey: [128 / 255, 128 / 255, 128 / 255, 1]
|
|
3954
|
+
};
|
|
3955
|
+
var parsed = new Map;
|
|
3956
|
+
var PARSED_LIMIT = 1024;
|
|
3957
|
+
function parse(css) {
|
|
3958
|
+
const text = css.trim();
|
|
3959
|
+
const named = NAMED[text.toLowerCase()];
|
|
3960
|
+
if (named)
|
|
3961
|
+
return named;
|
|
3962
|
+
const hex = HEX.exec(text);
|
|
3963
|
+
if (hex) {
|
|
3964
|
+
let digits = hex[1];
|
|
3965
|
+
if (digits.length <= 4)
|
|
3966
|
+
digits = [...digits].map((d) => d + d).join("");
|
|
3967
|
+
const n = (i) => parseInt(digits.slice(i, i + 2), 16) / 255;
|
|
3968
|
+
return [n(0), n(2), n(4), digits.length === 8 ? n(6) : 1];
|
|
3969
|
+
}
|
|
3970
|
+
const rgb = RGB.exec(text);
|
|
3971
|
+
if (rgb) {
|
|
3972
|
+
const alpha = rgb[4] === undefined ? 1 : rgb[4].endsWith("%") ? parseFloat(rgb[4]) / 100 : Number(rgb[4]);
|
|
3973
|
+
return [Number(rgb[1]) / 255, Number(rgb[2]) / 255, Number(rgb[3]) / 255, alpha];
|
|
3974
|
+
}
|
|
3975
|
+
throw new Error(`@nayan-ui/engine: "${css}" is not a color (use '#RRGGBB', '#RGB', '#RRGGBBAA', 'rgb(…)', 'rgba(…)' or a 0..1 tuple)`);
|
|
3976
|
+
}
|
|
3977
|
+
function toColor(color, alpha = 1) {
|
|
3978
|
+
let c;
|
|
3979
|
+
if (typeof color === "string") {
|
|
3980
|
+
let hit = parsed.get(color);
|
|
3981
|
+
if (!hit) {
|
|
3982
|
+
hit = parse(color);
|
|
3983
|
+
if (parsed.size >= PARSED_LIMIT)
|
|
3984
|
+
parsed.clear();
|
|
3985
|
+
parsed.set(color, hit);
|
|
3986
|
+
}
|
|
3987
|
+
c = hit;
|
|
3988
|
+
} else
|
|
3989
|
+
c = color;
|
|
3990
|
+
return [c[0], c[1], c[2], (c[3] ?? 1) * alpha];
|
|
3991
|
+
}
|
|
3992
|
+
function resolveColor(color) {
|
|
3993
|
+
return typeof color === "string" ? toColor(color) : color;
|
|
3994
|
+
}
|
|
3995
|
+
function resolveColors(colors) {
|
|
3996
|
+
if (typeof colors === "string")
|
|
3997
|
+
return [toColor(colors)];
|
|
3998
|
+
if (typeof colors[0] === "number")
|
|
3999
|
+
return [colors];
|
|
4000
|
+
return colors.map(resolveColor);
|
|
4001
|
+
}
|
|
4002
|
+
|
|
3913
4003
|
// src/world/desc.ts
|
|
3914
4004
|
var DESC_LEN = 64;
|
|
3915
4005
|
var FLAG = {
|
|
@@ -3998,10 +4088,11 @@ function encode(d, o, mesh) {
|
|
|
3998
4088
|
}
|
|
3999
4089
|
if (o.color) {
|
|
4000
4090
|
flags |= FLAG.COLOR;
|
|
4001
|
-
|
|
4002
|
-
d[SLOT.COLOR
|
|
4003
|
-
d[SLOT.COLOR +
|
|
4004
|
-
d[SLOT.COLOR +
|
|
4091
|
+
const c = resolveColor(o.color);
|
|
4092
|
+
d[SLOT.COLOR] = c[0];
|
|
4093
|
+
d[SLOT.COLOR + 1] = c[1];
|
|
4094
|
+
d[SLOT.COLOR + 2] = c[2];
|
|
4095
|
+
d[SLOT.COLOR + 3] = c[3] ?? 1;
|
|
4005
4096
|
}
|
|
4006
4097
|
if (o.velocity) {
|
|
4007
4098
|
flags |= FLAG.VELOCITY;
|
|
@@ -4104,6 +4195,7 @@ var FLAG2 = {
|
|
|
4104
4195
|
class Scoreboard {
|
|
4105
4196
|
world;
|
|
4106
4197
|
handlers = {};
|
|
4198
|
+
listeners = new Set;
|
|
4107
4199
|
state;
|
|
4108
4200
|
constructor(world) {
|
|
4109
4201
|
this.world = world;
|
|
@@ -4171,12 +4263,23 @@ class Scoreboard {
|
|
|
4171
4263
|
this.stop();
|
|
4172
4264
|
}
|
|
4173
4265
|
}
|
|
4266
|
+
listen(handlers) {
|
|
4267
|
+
this.listeners.add(handlers);
|
|
4268
|
+
return () => {
|
|
4269
|
+
this.listeners.delete(handlers);
|
|
4270
|
+
};
|
|
4271
|
+
}
|
|
4174
4272
|
dispatch() {
|
|
4175
4273
|
const flags = this.state[S.flags];
|
|
4176
4274
|
if (flags === 0)
|
|
4177
4275
|
return;
|
|
4178
4276
|
this.state[S.flags] = 0;
|
|
4179
|
-
|
|
4277
|
+
this.run(this.handlers, flags);
|
|
4278
|
+
if (this.listeners.size)
|
|
4279
|
+
for (const h of [...this.listeners])
|
|
4280
|
+
this.run(h, flags);
|
|
4281
|
+
}
|
|
4282
|
+
run(h, flags) {
|
|
4180
4283
|
if (flags & FLAG2.score)
|
|
4181
4284
|
h.onScore?.(this.score);
|
|
4182
4285
|
if (flags & FLAG2.lives)
|
|
@@ -4275,7 +4378,8 @@ class TransformBatch {
|
|
|
4275
4378
|
if (color)
|
|
4276
4379
|
this.writeColor(offset, color);
|
|
4277
4380
|
}
|
|
4278
|
-
writeColor(offset,
|
|
4381
|
+
writeColor(offset, input) {
|
|
4382
|
+
const color = resolveColor(input);
|
|
4279
4383
|
this.data[offset + 12] = color[0];
|
|
4280
4384
|
this.data[offset + 13] = color[1];
|
|
4281
4385
|
this.data[offset + 14] = color[2];
|
|
@@ -4358,6 +4462,7 @@ class World {
|
|
|
4358
4462
|
gravityValue = [0, -9.81, 0];
|
|
4359
4463
|
boundsValue = null;
|
|
4360
4464
|
listenerValue = null;
|
|
4465
|
+
updates = 0;
|
|
4361
4466
|
constructor(capacity) {
|
|
4362
4467
|
this.capacity = capacity;
|
|
4363
4468
|
if (!NativeNayanEngine_web_default) {
|
|
@@ -4405,7 +4510,7 @@ class World {
|
|
|
4405
4510
|
letterSpacing: options.letterSpacing,
|
|
4406
4511
|
tabular: options.tabular
|
|
4407
4512
|
},
|
|
4408
|
-
color: options.color ??
|
|
4513
|
+
color: resolveColor(options.color ?? WHITE),
|
|
4409
4514
|
glyphs: []
|
|
4410
4515
|
};
|
|
4411
4516
|
try {
|
|
@@ -4434,7 +4539,7 @@ class World {
|
|
|
4434
4539
|
tabular: options.tabular ?? text.layout.tabular
|
|
4435
4540
|
};
|
|
4436
4541
|
if (options.color)
|
|
4437
|
-
text.color = options.color;
|
|
4542
|
+
text.color = resolveColor(options.color);
|
|
4438
4543
|
if (rebuild)
|
|
4439
4544
|
this.buildText(e, text);
|
|
4440
4545
|
else if (options.color) {
|
|
@@ -4604,10 +4709,11 @@ class World {
|
|
|
4604
4709
|
}
|
|
4605
4710
|
if (k.color) {
|
|
4606
4711
|
flags |= KEY_FLAG.color;
|
|
4607
|
-
|
|
4608
|
-
a[o +
|
|
4609
|
-
a[o +
|
|
4610
|
-
a[o +
|
|
4712
|
+
const c = resolveColor(k.color);
|
|
4713
|
+
a[o + 12] = c[0];
|
|
4714
|
+
a[o + 13] = c[1];
|
|
4715
|
+
a[o + 14] = c[2];
|
|
4716
|
+
a[o + 15] = c[3] ?? 1;
|
|
4611
4717
|
}
|
|
4612
4718
|
if (k.moveBy) {
|
|
4613
4719
|
flags |= KEY_FLAG.moveBy;
|
|
@@ -4631,9 +4737,8 @@ class World {
|
|
|
4631
4737
|
}
|
|
4632
4738
|
burst(options) {
|
|
4633
4739
|
const b = this.burstDesc;
|
|
4634
|
-
const
|
|
4635
|
-
const
|
|
4636
|
-
const colorCount = single ? 1 : Math.max(1, Math.min(4, color.length));
|
|
4740
|
+
const colors = resolveColors(options.color ?? WHITE);
|
|
4741
|
+
const colorCount = Math.max(1, Math.min(4, colors.length));
|
|
4637
4742
|
b.set(options.position, 0);
|
|
4638
4743
|
b.set(options.direction ?? UP, 3);
|
|
4639
4744
|
b[6] = options.spread ?? Math.PI;
|
|
@@ -4645,12 +4750,12 @@ class World {
|
|
|
4645
4750
|
b[12] = options.gravity ?? -9.81;
|
|
4646
4751
|
b[13] = colorCount;
|
|
4647
4752
|
for (let k = 0;k < colorCount; k++)
|
|
4648
|
-
writeRgba(b, 14 + k * 4,
|
|
4753
|
+
writeRgba(b, 14 + k * 4, colors[k]);
|
|
4649
4754
|
b[30] = options.endSize ?? 1;
|
|
4650
4755
|
const end = options.endColor;
|
|
4651
4756
|
b[31] = end ? 1 : 0;
|
|
4652
4757
|
if (end)
|
|
4653
|
-
writeRgba(b, 32, end);
|
|
4758
|
+
writeRgba(b, 32, resolveColor(end));
|
|
4654
4759
|
return this.native.burst(this.id, b.buffer);
|
|
4655
4760
|
}
|
|
4656
4761
|
after(seconds, fn) {
|
|
@@ -4693,6 +4798,9 @@ class World {
|
|
|
4693
4798
|
get scoreboard() {
|
|
4694
4799
|
return this.scoreboardValue ??= new Scoreboard(this.id);
|
|
4695
4800
|
}
|
|
4801
|
+
get updateCount() {
|
|
4802
|
+
return this.updates;
|
|
4803
|
+
}
|
|
4696
4804
|
get timerCount() {
|
|
4697
4805
|
return this.timers.size + this.fallbackTimers.length;
|
|
4698
4806
|
}
|
|
@@ -4834,6 +4942,8 @@ class World {
|
|
|
4834
4942
|
this.native.setListener(this.id, e ?? -1);
|
|
4835
4943
|
}
|
|
4836
4944
|
update(dt) {
|
|
4945
|
+
this.updates++;
|
|
4946
|
+
this.transformsValue?.flush();
|
|
4837
4947
|
this.native.update(this.id, dt);
|
|
4838
4948
|
this.resolveFinished();
|
|
4839
4949
|
this.runFallbackTimers(dt);
|
|
@@ -4932,10 +5042,16 @@ var quat = {
|
|
|
4932
5042
|
}
|
|
4933
5043
|
};
|
|
4934
5044
|
// src/world/effects.ts
|
|
4935
|
-
var rgba = (
|
|
4936
|
-
|
|
5045
|
+
var rgba = (input) => {
|
|
5046
|
+
const c = resolveColor(input);
|
|
5047
|
+
return [c[0], c[1], c[2], c[3] ?? 1];
|
|
5048
|
+
};
|
|
5049
|
+
var list = (colors) => resolveColors(colors).map(rgba);
|
|
4937
5050
|
var part = (count, share) => Math.max(1, Math.round(count * share));
|
|
4938
|
-
var fade = (
|
|
5051
|
+
var fade = (input) => {
|
|
5052
|
+
const c = resolveColor(input);
|
|
5053
|
+
return [c[0], c[1], c[2], 0];
|
|
5054
|
+
};
|
|
4939
5055
|
function mean(colors) {
|
|
4940
5056
|
const sum = [0, 0, 0, 0];
|
|
4941
5057
|
for (const c of colors)
|
|
@@ -4943,11 +5059,15 @@ function mean(colors) {
|
|
|
4943
5059
|
sum[i] += c[i];
|
|
4944
5060
|
return sum.map((v) => v / colors.length);
|
|
4945
5061
|
}
|
|
4946
|
-
function hot(
|
|
5062
|
+
function hot(input, peak = 2.2, alpha) {
|
|
5063
|
+
const c = resolveColor(input);
|
|
5064
|
+
alpha ??= c[3] ?? 1;
|
|
4947
5065
|
const k = peak / Math.max(c[0], c[1], c[2], 0.25);
|
|
4948
5066
|
return [c[0] * k, c[1] * k, c[2] * k, alpha];
|
|
4949
5067
|
}
|
|
4950
|
-
function pale(
|
|
5068
|
+
function pale(input, t, alpha) {
|
|
5069
|
+
const c = resolveColor(input);
|
|
5070
|
+
alpha ??= c[3] ?? 1;
|
|
4951
5071
|
return [c[0] + (1 - c[0]) * t, c[1] + (1 - c[1]) * t, c[2] + (1 - c[2]) * t, alpha];
|
|
4952
5072
|
}
|
|
4953
5073
|
function aim(e) {
|
|
@@ -4971,7 +5091,7 @@ function glowFlash(world, e, colors, size) {
|
|
|
4971
5091
|
flash(world, { position: e.position, color: hot(mean(colors), 2, 0.85), size });
|
|
4972
5092
|
}
|
|
4973
5093
|
function dust(world, o) {
|
|
4974
|
-
const
|
|
5094
|
+
const colors = resolveColors(o.color);
|
|
4975
5095
|
return world.burst({
|
|
4976
5096
|
position: o.position,
|
|
4977
5097
|
count: o.count,
|
|
@@ -4982,9 +5102,9 @@ function dust(world, o) {
|
|
|
4982
5102
|
gravity: o.gravity ?? 0,
|
|
4983
5103
|
direction: o.direction,
|
|
4984
5104
|
spread: o.spread,
|
|
4985
|
-
color:
|
|
5105
|
+
color: colors.length === 1 ? colors[0] : colors,
|
|
4986
5106
|
endSize: o.endSize ?? 2,
|
|
4987
|
-
endColor: o.endColor ?? (
|
|
5107
|
+
endColor: o.endColor ?? (colors.length === 1 ? fade(colors[0]) : undefined)
|
|
4988
5108
|
});
|
|
4989
5109
|
}
|
|
4990
5110
|
function confetti(world, e) {
|
|
@@ -5803,11 +5923,13 @@ var QUALITY_LEVELS = {
|
|
|
5803
5923
|
lowest: { maxPixelRatio: 2, samples: 1, shadowSize: 512, softShadows: false }
|
|
5804
5924
|
};
|
|
5805
5925
|
var SLOW_FRAME_MS = 20;
|
|
5926
|
+
var VERY_SLOW_FRAME_MS = 30;
|
|
5806
5927
|
var FAST_FRAME_MS = 17.4;
|
|
5807
5928
|
var RENDER_SHARE = 0.6;
|
|
5808
5929
|
var STARTUP_MS = 2500;
|
|
5809
|
-
var SETTLE_MS =
|
|
5930
|
+
var SETTLE_MS = 1500;
|
|
5810
5931
|
var SLOW_SECONDS = 3;
|
|
5932
|
+
var VERY_SLOW_SECONDS = 1;
|
|
5811
5933
|
var FAST_SECONDS = 10;
|
|
5812
5934
|
var RELAPSE_MS = 20000;
|
|
5813
5935
|
|
|
@@ -5818,6 +5940,7 @@ class AutoQuality {
|
|
|
5818
5940
|
changed = 0;
|
|
5819
5941
|
raisedAt = -Infinity;
|
|
5820
5942
|
slow = 0;
|
|
5943
|
+
verySlow = 0;
|
|
5821
5944
|
fast = 0;
|
|
5822
5945
|
get quality() {
|
|
5823
5946
|
return QUALITIES[this.index];
|
|
@@ -5830,8 +5953,9 @@ class AutoQuality {
|
|
|
5830
5953
|
const gpuBound = frames.frameMs > SLOW_FRAME_MS && frames.renderMs > frames.frameMs * RENDER_SHARE;
|
|
5831
5954
|
const smooth = frames.frameMs <= FAST_FRAME_MS;
|
|
5832
5955
|
this.slow = gpuBound ? this.slow + 1 : 0;
|
|
5956
|
+
this.verySlow = gpuBound && frames.frameMs > VERY_SLOW_FRAME_MS ? this.verySlow + 1 : 0;
|
|
5833
5957
|
this.fast = smooth ? this.fast + 1 : 0;
|
|
5834
|
-
if (this.slow >= SLOW_SECONDS && this.index < QUALITIES.length - 1) {
|
|
5958
|
+
if ((this.slow >= SLOW_SECONDS || this.verySlow >= VERY_SLOW_SECONDS) && this.index < QUALITIES.length - 1) {
|
|
5835
5959
|
if (now - this.raisedAt < RELAPSE_MS)
|
|
5836
5960
|
this.ceiling = Math.max(this.ceiling, this.index + 1);
|
|
5837
5961
|
this.index++;
|
|
@@ -5847,6 +5971,7 @@ class AutoQuality {
|
|
|
5847
5971
|
moved(now) {
|
|
5848
5972
|
this.changed = now;
|
|
5849
5973
|
this.slow = 0;
|
|
5974
|
+
this.verySlow = 0;
|
|
5850
5975
|
this.fast = 0;
|
|
5851
5976
|
return true;
|
|
5852
5977
|
}
|
|
@@ -5874,6 +5999,35 @@ var defaultLight = () => ({
|
|
|
5874
5999
|
direction: [0.4, 0.8, 0.5],
|
|
5875
6000
|
ambient: 0.35
|
|
5876
6001
|
});
|
|
6002
|
+
var afterFrame = [];
|
|
6003
|
+
var runningLoops = 0;
|
|
6004
|
+
function runAfterFrame() {
|
|
6005
|
+
if (afterFrame.length === 0)
|
|
6006
|
+
return;
|
|
6007
|
+
const due = afterFrame;
|
|
6008
|
+
afterFrame = [];
|
|
6009
|
+
for (const fn of due)
|
|
6010
|
+
fn();
|
|
6011
|
+
}
|
|
6012
|
+
function afterNextFrame(fn) {
|
|
6013
|
+
let cancelled = false;
|
|
6014
|
+
const run = () => {
|
|
6015
|
+
if (!cancelled)
|
|
6016
|
+
fn();
|
|
6017
|
+
};
|
|
6018
|
+
if (runningLoops > 0)
|
|
6019
|
+
afterFrame.push(run);
|
|
6020
|
+
else {
|
|
6021
|
+
const raf = requestAnimationFrame(run);
|
|
6022
|
+
return () => {
|
|
6023
|
+
cancelled = true;
|
|
6024
|
+
cancelAnimationFrame(raf);
|
|
6025
|
+
};
|
|
6026
|
+
}
|
|
6027
|
+
return () => {
|
|
6028
|
+
cancelled = true;
|
|
6029
|
+
};
|
|
6030
|
+
}
|
|
5877
6031
|
function GameView(props) {
|
|
5878
6032
|
const { source, camera, light, background, fog, style } = props;
|
|
5879
6033
|
const active = useActive();
|
|
@@ -5920,6 +6074,9 @@ function GameView(props) {
|
|
|
5920
6074
|
let alive = true;
|
|
5921
6075
|
let raf = 0;
|
|
5922
6076
|
let errors = 0;
|
|
6077
|
+
const native2 = native;
|
|
6078
|
+
const threaded = native2.hasFrameClock?.() === true && typeof native2.publishFrame === "function" && typeof native2.startFrames === "function";
|
|
6079
|
+
let presentedAt = 0;
|
|
5923
6080
|
if (autoQuality.current?.source !== source)
|
|
5924
6081
|
autoQuality.current = { source, auto: new AutoQuality };
|
|
5925
6082
|
const auto = autoQuality.current.auto;
|
|
@@ -5965,7 +6122,8 @@ function GameView(props) {
|
|
|
5965
6122
|
const frame = (now) => {
|
|
5966
6123
|
if (!alive)
|
|
5967
6124
|
return;
|
|
5968
|
-
|
|
6125
|
+
if (!threaded)
|
|
6126
|
+
raf = requestAnimationFrame(frame);
|
|
5969
6127
|
if (!last)
|
|
5970
6128
|
last = fpsStart = now;
|
|
5971
6129
|
if (now > last)
|
|
@@ -5974,7 +6132,14 @@ function GameView(props) {
|
|
|
5974
6132
|
last = now;
|
|
5975
6133
|
const { props: current, camera, light, environment } = live.current;
|
|
5976
6134
|
const t0 = performance.now();
|
|
6135
|
+
const layer = current.overlay;
|
|
6136
|
+
const sourceSteps = source.updateCount;
|
|
6137
|
+
const layerSteps = layer?.updateCount;
|
|
5977
6138
|
current.onUpdate?.(dt);
|
|
6139
|
+
if (source.update && !source.isDisposed && source.updateCount === sourceSteps)
|
|
6140
|
+
source.update(dt);
|
|
6141
|
+
if (layer?.update && !layer.isDisposed && layer.updateCount === layerSteps)
|
|
6142
|
+
layer.update(dt);
|
|
5978
6143
|
updateTime += performance.now() - t0;
|
|
5979
6144
|
follow(camera, source, followed, dt);
|
|
5980
6145
|
const view = shake(camera, shaken, dt);
|
|
@@ -5991,11 +6156,11 @@ function GameView(props) {
|
|
|
5991
6156
|
f[11] = light.ambient;
|
|
5992
6157
|
f[12] = light.shadows ?? true ? 1 : 0;
|
|
5993
6158
|
f[13] = light.shadowExtent ?? 30;
|
|
5994
|
-
const lightColor = light.color
|
|
6159
|
+
const lightColor = light.color === undefined ? WHITE3 : resolveColor(light.color);
|
|
5995
6160
|
f[14] = lightColor[0];
|
|
5996
6161
|
f[15] = lightColor[1];
|
|
5997
6162
|
f[16] = lightColor[2];
|
|
5998
|
-
const sky = environment.background;
|
|
6163
|
+
const sky = resolveColor(environment.background);
|
|
5999
6164
|
f[17] = sky[0];
|
|
6000
6165
|
f[18] = sky[1];
|
|
6001
6166
|
f[19] = sky[2];
|
|
@@ -6006,7 +6171,6 @@ function GameView(props) {
|
|
|
6006
6171
|
f[24] = level.shadowSize;
|
|
6007
6172
|
f[25] = level.softShadows ? 1 : 0;
|
|
6008
6173
|
const t1 = performance.now();
|
|
6009
|
-
const layer = current.overlay;
|
|
6010
6174
|
if (layer) {
|
|
6011
6175
|
if (overlay?.source !== layer)
|
|
6012
6176
|
overlay = { source: layer, regions: wholeRegions(layer) };
|
|
@@ -6015,28 +6179,41 @@ function GameView(props) {
|
|
|
6015
6179
|
overlay = null;
|
|
6016
6180
|
native.renderOverlay(surfaceId, regions.buffer, regions.buffer, regions.buffer, regions.buffer, 0, 0, 0);
|
|
6017
6181
|
}
|
|
6018
|
-
const
|
|
6182
|
+
const render = threaded ? native2.publishFrame : native.renderFrame;
|
|
6183
|
+
const rendered = render(surfaceId, f.buffer, source.matrices.buffer, source.colors.buffer, regions.buffer, source.ranges.buffer, drawn(source), viewProj.buffer, source.nativeWorld ?? -1);
|
|
6019
6184
|
const drawMs = performance.now() - t1;
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6185
|
+
if (!threaded) {
|
|
6186
|
+
renderTime += drawMs;
|
|
6187
|
+
draws.push(drawMs);
|
|
6188
|
+
}
|
|
6189
|
+
if (rendered === 1 || threaded && rendered === 0)
|
|
6024
6190
|
source.setView?.(viewProj, width, height);
|
|
6025
|
-
|
|
6191
|
+
if (rendered === 1)
|
|
6192
|
+
shown = true;
|
|
6193
|
+
else if (rendered < 0 && errors++ < 3)
|
|
6026
6194
|
report(new Error(native.renderError() || "rendering failed"));
|
|
6027
|
-
}
|
|
6028
6195
|
frames++;
|
|
6029
6196
|
if (now - fpsStart >= 1000) {
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6197
|
+
const elapsed = now - fpsStart;
|
|
6198
|
+
let fps = frames * 1000 / elapsed;
|
|
6199
|
+
let frameMs = median(intervals);
|
|
6200
|
+
let renderMs = median(draws);
|
|
6201
|
+
let meanRenderMs = renderTime / frames;
|
|
6202
|
+
if (threaded) {
|
|
6203
|
+
const [presented = 0, nativeMs = 0] = native2.renderStats?.(surfaceId) ?? [];
|
|
6204
|
+
const shownFrames = presented - presentedAt;
|
|
6205
|
+
presentedAt = presented;
|
|
6206
|
+
fps = shownFrames * 1000 / elapsed;
|
|
6207
|
+
frameMs = shownFrames > 0 ? Math.max(frameMs, elapsed / shownFrames) : elapsed;
|
|
6208
|
+
renderMs = meanRenderMs = nativeMs;
|
|
6209
|
+
}
|
|
6210
|
+
auto.report(now, { frameMs, renderMs });
|
|
6034
6211
|
intervals.length = 0;
|
|
6035
6212
|
draws.length = 0;
|
|
6036
6213
|
current.onStats?.({
|
|
6037
|
-
fps
|
|
6214
|
+
fps,
|
|
6038
6215
|
updateMs: updateTime / frames,
|
|
6039
|
-
renderMs:
|
|
6216
|
+
renderMs: meanRenderMs,
|
|
6040
6217
|
quality,
|
|
6041
6218
|
backend: native.renderBackend()
|
|
6042
6219
|
});
|
|
@@ -6045,11 +6222,22 @@ function GameView(props) {
|
|
|
6045
6222
|
renderTime = 0;
|
|
6046
6223
|
fpsStart = now;
|
|
6047
6224
|
}
|
|
6225
|
+
runAfterFrame();
|
|
6048
6226
|
};
|
|
6049
|
-
|
|
6227
|
+
if (threaded)
|
|
6228
|
+
native2.startFrames(surfaceId, frame);
|
|
6229
|
+
else
|
|
6230
|
+
raf = requestAnimationFrame(frame);
|
|
6231
|
+
runningLoops++;
|
|
6050
6232
|
return () => {
|
|
6051
6233
|
alive = false;
|
|
6052
|
-
|
|
6234
|
+
runningLoops--;
|
|
6235
|
+
if (runningLoops === 0 && afterFrame.length)
|
|
6236
|
+
requestAnimationFrame(runAfterFrame);
|
|
6237
|
+
if (threaded)
|
|
6238
|
+
native2.stopFrames(surfaceId);
|
|
6239
|
+
else
|
|
6240
|
+
cancelAnimationFrame(raf);
|
|
6053
6241
|
};
|
|
6054
6242
|
}, [source, props.paused, active]);
|
|
6055
6243
|
const touchable = props.onTap || props.onSwipe || props.onDrag || props.onLongPress || props.onPinch || props.onOverlayTouch;
|
|
@@ -6064,6 +6252,58 @@ function GameView(props) {
|
|
|
6064
6252
|
onPrimaryAction: props.onPrimaryAction ? () => live.current.props.onPrimaryAction?.() : undefined
|
|
6065
6253
|
});
|
|
6066
6254
|
}
|
|
6255
|
+
// src/render/useWorld.ts
|
|
6256
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
|
|
6257
|
+
function useWorld(capacity, setup, deps = [], onError) {
|
|
6258
|
+
const [world, setWorld] = useState2(null);
|
|
6259
|
+
const latest = useRef3({ setup, onError });
|
|
6260
|
+
latest.current = { setup, onError };
|
|
6261
|
+
useEffect3(() => {
|
|
6262
|
+
let active = true;
|
|
6263
|
+
let created = null;
|
|
6264
|
+
let cleanup;
|
|
6265
|
+
const report = (error) => {
|
|
6266
|
+
const e = error instanceof Error ? error : new Error(String(error));
|
|
6267
|
+
(latest.current.onError ?? ((x) => console.error(`useWorld: ${x.message}`)))(e);
|
|
6268
|
+
};
|
|
6269
|
+
if (!isEngineAvailable) {
|
|
6270
|
+
report(new Error("the native engine is not linked into this build (a development build is needed, not Expo Go)"));
|
|
6271
|
+
return;
|
|
6272
|
+
}
|
|
6273
|
+
warmUpEngine().then(() => {
|
|
6274
|
+
if (!active)
|
|
6275
|
+
return;
|
|
6276
|
+
try {
|
|
6277
|
+
created = new World(capacity);
|
|
6278
|
+
cleanup = latest.current.setup?.(created);
|
|
6279
|
+
setWorld(created);
|
|
6280
|
+
} catch (error) {
|
|
6281
|
+
created?.dispose();
|
|
6282
|
+
created = null;
|
|
6283
|
+
report(error);
|
|
6284
|
+
}
|
|
6285
|
+
}, report);
|
|
6286
|
+
return () => {
|
|
6287
|
+
active = false;
|
|
6288
|
+
setWorld(null);
|
|
6289
|
+
if (!created)
|
|
6290
|
+
return;
|
|
6291
|
+
try {
|
|
6292
|
+
cleanup?.();
|
|
6293
|
+
} finally {
|
|
6294
|
+
created.dispose();
|
|
6295
|
+
}
|
|
6296
|
+
};
|
|
6297
|
+
}, [capacity, ...deps]);
|
|
6298
|
+
return world;
|
|
6299
|
+
}
|
|
6300
|
+
// src/render/light.ts
|
|
6301
|
+
function frontLight(direction, ambient) {
|
|
6302
|
+
const [x, y, z] = direction;
|
|
6303
|
+
const facing = z / Math.hypot(x, y, z);
|
|
6304
|
+
const k = 1 / (ambient * 0.8 + (1 - ambient) * facing);
|
|
6305
|
+
return { direction, ambient, shadows: false, color: [k, k, k] };
|
|
6306
|
+
}
|
|
6067
6307
|
// src/assets/AssetCache.ts
|
|
6068
6308
|
async function clearAssetCache() {
|
|
6069
6309
|
advanceCacheGeneration();
|
|
@@ -6118,6 +6358,24 @@ class ProceduralCache {
|
|
|
6118
6358
|
async flush() {
|
|
6119
6359
|
await Promise.all([...this.writes]);
|
|
6120
6360
|
}
|
|
6361
|
+
peek(key) {
|
|
6362
|
+
if (this.memory.has(key))
|
|
6363
|
+
return this.memory.get(key);
|
|
6364
|
+
if (!this.storage)
|
|
6365
|
+
return;
|
|
6366
|
+
try {
|
|
6367
|
+
const bytes = this.storage.read(key);
|
|
6368
|
+
if (!bytes)
|
|
6369
|
+
return;
|
|
6370
|
+
const value = this.restore(bytes, key);
|
|
6371
|
+
this.memory.set(key, value);
|
|
6372
|
+
this.hits++;
|
|
6373
|
+
return value;
|
|
6374
|
+
} catch {
|
|
6375
|
+
this.invalid++;
|
|
6376
|
+
return;
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6121
6379
|
get(key, build) {
|
|
6122
6380
|
if (this.memory.has(key))
|
|
6123
6381
|
return this.memory.get(key);
|
|
@@ -6226,7 +6484,7 @@ class ProceduralCache {
|
|
|
6226
6484
|
bytes.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength), offset);
|
|
6227
6485
|
offset += data.byteLength;
|
|
6228
6486
|
}
|
|
6229
|
-
view.setUint32(12, checksum(bytes.subarray(16)), true);
|
|
6487
|
+
view.setUint32(12, this.storage?.verified ? 0 : checksum(bytes.subarray(16)), true);
|
|
6230
6488
|
return bytes;
|
|
6231
6489
|
}
|
|
6232
6490
|
restore(raw, key) {
|
|
@@ -6235,7 +6493,7 @@ class ProceduralCache {
|
|
|
6235
6493
|
const bytes = raw.byteOffset % 4 ? raw.slice() : raw;
|
|
6236
6494
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
6237
6495
|
const jsonLength = view.getUint32(4, true);
|
|
6238
|
-
if (view.getUint32(0, true) !== MAGIC || view.getUint32(8, true) !== bytes.length || jsonLength > bytes.length - 16 || view.getUint32(12, true) !== checksum(bytes.subarray(16)))
|
|
6496
|
+
if (view.getUint32(0, true) !== MAGIC || view.getUint32(8, true) !== bytes.length || jsonLength > bytes.length - 16 || !this.storage?.verified && view.getUint32(12, true) !== checksum(bytes.subarray(16)))
|
|
6239
6497
|
throw Error("cache integrity");
|
|
6240
6498
|
const header = decodeJson(bytes.subarray(16, 16 + jsonLength));
|
|
6241
6499
|
if (!("value" in header) || header.revision !== this.revision || header.key !== key || !Array.isArray(header.meshes))
|
|
@@ -6250,12 +6508,14 @@ class ProceduralCache {
|
|
|
6250
6508
|
throw Error("cache truncated");
|
|
6251
6509
|
const vertices = new Float32Array(bytes.buffer, bytes.byteOffset + offset, mesh.floats);
|
|
6252
6510
|
const indices = new Uint32Array(bytes.buffer, bytes.byteOffset + offset + mesh.floats * 4, mesh.indices);
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6511
|
+
if (!this.storage?.verified) {
|
|
6512
|
+
for (const value of vertices)
|
|
6513
|
+
if (!Number.isFinite(value))
|
|
6514
|
+
throw Error("cache vertex");
|
|
6515
|
+
for (const index of indices)
|
|
6516
|
+
if (index >= mesh.floats / 11)
|
|
6517
|
+
throw Error("cache index");
|
|
6518
|
+
}
|
|
6259
6519
|
payloads.push({ vertices, indices, shine: mesh.shine });
|
|
6260
6520
|
offset = end;
|
|
6261
6521
|
}
|
|
@@ -7387,10 +7647,12 @@ function smoothCurve(points) {
|
|
|
7387
7647
|
var loader4 = new AssetLoader("audio");
|
|
7388
7648
|
function loadSound(source) {
|
|
7389
7649
|
return loader4.load(source, (native, bytes) => {
|
|
7390
|
-
const
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7650
|
+
const finish = (id) => {
|
|
7651
|
+
if (id < 0)
|
|
7652
|
+
throw new Error(native.loadError() || "not a supported WAV file");
|
|
7653
|
+
return id;
|
|
7654
|
+
};
|
|
7655
|
+
return typeof native.audioLoadAsync === "function" ? native.audioLoadAsync(bytes).then(finish) : finish(native.audioLoad(bytes));
|
|
7394
7656
|
}).catch((error) => {
|
|
7395
7657
|
console.warn(error instanceof Error ? error.message : String(error));
|
|
7396
7658
|
return null;
|
|
@@ -7509,15 +7771,15 @@ var haptics = {
|
|
|
7509
7771
|
}
|
|
7510
7772
|
};
|
|
7511
7773
|
// src/input/Joystick.web.tsx
|
|
7512
|
-
import { useCallback, useEffect as
|
|
7774
|
+
import { useCallback, useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
7513
7775
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
7514
7776
|
function useJoystick() {
|
|
7515
|
-
return
|
|
7777
|
+
return useRef4({ x: 0, y: 0 }).current;
|
|
7516
7778
|
}
|
|
7517
7779
|
function Joystick({ state, size = 150, style }) {
|
|
7518
|
-
const knob =
|
|
7519
|
-
const pointer =
|
|
7520
|
-
const origin =
|
|
7780
|
+
const knob = useRef4(null);
|
|
7781
|
+
const pointer = useRef4(null);
|
|
7782
|
+
const origin = useRef4({ x: 0, y: 0 });
|
|
7521
7783
|
const reach = size * 0.3;
|
|
7522
7784
|
const reset = useCallback(() => {
|
|
7523
7785
|
pointer.current = null;
|
|
@@ -7525,7 +7787,7 @@ function Joystick({ state, size = 150, style }) {
|
|
|
7525
7787
|
if (knob.current)
|
|
7526
7788
|
knob.current.style.transform = "translate(0px, 0px)";
|
|
7527
7789
|
}, [state]);
|
|
7528
|
-
|
|
7790
|
+
useEffect4(() => {
|
|
7529
7791
|
const visibility = () => {
|
|
7530
7792
|
if (document.hidden)
|
|
7531
7793
|
reset();
|
|
@@ -7730,7 +7992,7 @@ class DrawingDocument {
|
|
|
7730
7992
|
}
|
|
7731
7993
|
}
|
|
7732
7994
|
// src/drawing/DrawingCanvas.web.tsx
|
|
7733
|
-
import { memo, useEffect as
|
|
7995
|
+
import { memo, useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
|
|
7734
7996
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
7735
7997
|
var DrawingCanvas = memo(function DrawingCanvas({
|
|
7736
7998
|
document: drawing,
|
|
@@ -7741,11 +8003,11 @@ var DrawingCanvas = memo(function DrawingCanvas({
|
|
|
7741
8003
|
onChange,
|
|
7742
8004
|
style
|
|
7743
8005
|
}) {
|
|
7744
|
-
const ref =
|
|
7745
|
-
const [error, setError] =
|
|
7746
|
-
const live =
|
|
8006
|
+
const ref = useRef5(null);
|
|
8007
|
+
const [error, setError] = useState3("");
|
|
8008
|
+
const live = useRef5({ mode, background, active, onError, onChange });
|
|
7747
8009
|
live.current = { mode, background, active, onError, onChange };
|
|
7748
|
-
|
|
8010
|
+
useEffect5(() => {
|
|
7749
8011
|
const canvas = ref.current;
|
|
7750
8012
|
setError("");
|
|
7751
8013
|
let alive = true, ready = false, raf = 0, drawingPointer = null;
|
|
@@ -7936,6 +8198,7 @@ export {
|
|
|
7936
8198
|
Scoreboard,
|
|
7937
8199
|
Solid,
|
|
7938
8200
|
World,
|
|
8201
|
+
afterNextFrame,
|
|
7939
8202
|
audio,
|
|
7940
8203
|
block,
|
|
7941
8204
|
clearAssetCache,
|
|
@@ -7947,6 +8210,7 @@ export {
|
|
|
7947
8210
|
effects,
|
|
7948
8211
|
ellipsoid,
|
|
7949
8212
|
extrude,
|
|
8213
|
+
frontLight,
|
|
7950
8214
|
getGeometryStats,
|
|
7951
8215
|
getMeshIdLimit,
|
|
7952
8216
|
haptics,
|
|
@@ -7966,9 +8230,11 @@ export {
|
|
|
7966
8230
|
smoothCurve,
|
|
7967
8231
|
smoothNormals,
|
|
7968
8232
|
solidGeometry,
|
|
8233
|
+
toColor,
|
|
7969
8234
|
tube,
|
|
7970
8235
|
useJoystick,
|
|
8236
|
+
useWorld,
|
|
7971
8237
|
warmUpEngine
|
|
7972
8238
|
};
|
|
7973
8239
|
|
|
7974
|
-
//# debugId=
|
|
8240
|
+
//# debugId=1367AF6CC344167A64756E2164756E21
|