@doki-land/live2d-renderer 0.0.17 → 0.0.19
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/dist/index.d.ts +145 -135
- package/dist/index.js +601 -227
- package/package.json +2 -2
- package/src/cpu/evaluate.ts +63 -4
- package/src/index.ts +37 -37
- package/src/moc/moc2-to-program.ts +89 -3
- package/src/moc/moc2.ts +151 -75
- package/src/moc/moc3-to-program.ts +193 -3
- package/src/moc/moc3.ts +160 -81
- package/src/runtime/model-runtime.ts +6 -0
- package/src/types.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -2551,10 +2551,21 @@ function createModelInstance(program) {
|
|
|
2551
2551
|
timeSeconds: 0
|
|
2552
2552
|
};
|
|
2553
2553
|
}
|
|
2554
|
+
var paramIndexCache = /* @__PURE__ */ new WeakMap();
|
|
2555
|
+
function parameterIndex(instance, parameterId) {
|
|
2556
|
+
let map = paramIndexCache.get(instance.program);
|
|
2557
|
+
if (!map) {
|
|
2558
|
+
map = /* @__PURE__ */ new Map();
|
|
2559
|
+
for (let i = 0; i < instance.program.parameters.length; i++) {
|
|
2560
|
+
map.set(instance.program.parameters[i].id, i);
|
|
2561
|
+
}
|
|
2562
|
+
paramIndexCache.set(instance.program, map);
|
|
2563
|
+
}
|
|
2564
|
+
const index = map.get(parameterId);
|
|
2565
|
+
return index ?? -1;
|
|
2566
|
+
}
|
|
2554
2567
|
function setParameterValue(instance, parameterId, value) {
|
|
2555
|
-
const index = instance
|
|
2556
|
-
(p2) => p2.id === parameterId
|
|
2557
|
-
);
|
|
2568
|
+
const index = parameterIndex(instance, parameterId);
|
|
2558
2569
|
if (index < 0) {
|
|
2559
2570
|
throw new Error(
|
|
2560
2571
|
`@doki-land/live2d-renderer: unknown parameter "${parameterId}"`
|
|
@@ -2604,6 +2615,32 @@ function evaluateFrame(instance) {
|
|
|
2604
2615
|
drawables
|
|
2605
2616
|
};
|
|
2606
2617
|
}
|
|
2618
|
+
function evaluateFrameInto(instance, meshes, poseOpacity) {
|
|
2619
|
+
const byIndex = /* @__PURE__ */ new Map();
|
|
2620
|
+
for (const m of meshes) byIndex.set(m.index, m);
|
|
2621
|
+
for (const d of instance.program.drawables) {
|
|
2622
|
+
const sink = byIndex.get(d.index);
|
|
2623
|
+
if (!sink) continue;
|
|
2624
|
+
let positions = sink.vertexPositions;
|
|
2625
|
+
if (positions.length !== d.positions.length) {
|
|
2626
|
+
positions = new Float32Array(d.positions.length);
|
|
2627
|
+
sink.vertexPositions = positions;
|
|
2628
|
+
}
|
|
2629
|
+
positions.set(d.positions);
|
|
2630
|
+
if (d.deformParamIndex >= 0 && d.deformDeltas) {
|
|
2631
|
+
const w = paramWeight(instance, d.deformParamIndex);
|
|
2632
|
+
for (let i = 0; i < positions.length; i++) {
|
|
2633
|
+
positions[i] = positions[i] + w * d.deformDeltas[i];
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
sink.opacity = d.opacity;
|
|
2637
|
+
sink.renderOrder = d.renderOrder;
|
|
2638
|
+
sink.visible = d.visible;
|
|
2639
|
+
if (d.index >= 0 && d.index < poseOpacity.length) {
|
|
2640
|
+
poseOpacity[d.index] = d.opacity;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2607
2644
|
function fingerprintSnapshot(snapshot) {
|
|
2608
2645
|
const parts = [`t=${snapshot.timeSeconds.toFixed(4)}`];
|
|
2609
2646
|
for (const d of snapshot.drawables) {
|
|
@@ -2620,97 +2657,6 @@ function fingerprintSnapshot(snapshot) {
|
|
|
2620
2657
|
return parts.join("|");
|
|
2621
2658
|
}
|
|
2622
2659
|
|
|
2623
|
-
// src/runtime/create-renderer.ts
|
|
2624
|
-
var DEFAULT_PREFER = ["webgpu", "webgl2", "canvas2d"];
|
|
2625
|
-
var INIT_TIMEOUT_MS = {
|
|
2626
|
-
webgpu: 2500,
|
|
2627
|
-
webgl2: 1500,
|
|
2628
|
-
canvas2d: 1e3
|
|
2629
|
-
};
|
|
2630
|
-
function instantiate(kind, options) {
|
|
2631
|
-
if (kind === "webgpu") return createWebGpuRenderer(options.webgpu);
|
|
2632
|
-
if (kind === "webgl2") return createWebGl2Renderer(options.webgl2);
|
|
2633
|
-
return createCanvas2DRenderer(options.canvas2d);
|
|
2634
|
-
}
|
|
2635
|
-
async function initializeWithTimeout(kind, candidate, canvas) {
|
|
2636
|
-
const ms = INIT_TIMEOUT_MS[kind];
|
|
2637
|
-
let timer;
|
|
2638
|
-
try {
|
|
2639
|
-
await Promise.race([
|
|
2640
|
-
candidate.initialize(canvas),
|
|
2641
|
-
new Promise((_, reject) => {
|
|
2642
|
-
timer = setTimeout(() => {
|
|
2643
|
-
reject(
|
|
2644
|
-
new Error(
|
|
2645
|
-
`@doki-land/live2d-renderer: ${kind} initialize timed out after ${ms}ms`
|
|
2646
|
-
)
|
|
2647
|
-
);
|
|
2648
|
-
}, ms);
|
|
2649
|
-
})
|
|
2650
|
-
]);
|
|
2651
|
-
} finally {
|
|
2652
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
var FallbackRenderer = class {
|
|
2656
|
-
#inner = null;
|
|
2657
|
-
#kind = "webgpu";
|
|
2658
|
-
#prefer;
|
|
2659
|
-
#options;
|
|
2660
|
-
constructor(prefer, options) {
|
|
2661
|
-
this.#prefer = prefer;
|
|
2662
|
-
this.#options = options;
|
|
2663
|
-
}
|
|
2664
|
-
get kind() {
|
|
2665
|
-
return this.#inner?.kind ?? this.#kind;
|
|
2666
|
-
}
|
|
2667
|
-
async initialize(canvas) {
|
|
2668
|
-
const errors = [];
|
|
2669
|
-
for (const kind of this.#prefer) {
|
|
2670
|
-
const candidate = instantiate(kind, this.#options);
|
|
2671
|
-
try {
|
|
2672
|
-
await initializeWithTimeout(kind, candidate, canvas);
|
|
2673
|
-
this.#inner = candidate;
|
|
2674
|
-
this.#kind = candidate.kind;
|
|
2675
|
-
return;
|
|
2676
|
-
} catch (err) {
|
|
2677
|
-
candidate.destroy();
|
|
2678
|
-
errors.push(
|
|
2679
|
-
`${kind}: ${err instanceof Error ? err.message : String(err)}`
|
|
2680
|
-
);
|
|
2681
|
-
}
|
|
2682
|
-
}
|
|
2683
|
-
throw new Error(
|
|
2684
|
-
`@doki-land/live2d-renderer: no renderer initialized (${errors.join("; ")})`
|
|
2685
|
-
);
|
|
2686
|
-
}
|
|
2687
|
-
createModelDrawPass() {
|
|
2688
|
-
if (!this.#inner) {
|
|
2689
|
-
throw new Error(
|
|
2690
|
-
"@doki-land/live2d-renderer: renderer not initialized"
|
|
2691
|
-
);
|
|
2692
|
-
}
|
|
2693
|
-
return this.#inner.createModelDrawPass();
|
|
2694
|
-
}
|
|
2695
|
-
beginFrame() {
|
|
2696
|
-
this.#inner?.beginFrame();
|
|
2697
|
-
}
|
|
2698
|
-
endFrame() {
|
|
2699
|
-
this.#inner?.endFrame();
|
|
2700
|
-
}
|
|
2701
|
-
resize(width, height) {
|
|
2702
|
-
this.#inner?.resize(width, height);
|
|
2703
|
-
}
|
|
2704
|
-
destroy() {
|
|
2705
|
-
this.#inner?.destroy();
|
|
2706
|
-
this.#inner = null;
|
|
2707
|
-
}
|
|
2708
|
-
};
|
|
2709
|
-
function createRenderer(options = {}) {
|
|
2710
|
-
const prefer = options.prefer?.length ? options.prefer : DEFAULT_PREFER;
|
|
2711
|
-
return new FallbackRenderer(prefer, options);
|
|
2712
|
-
}
|
|
2713
|
-
|
|
2714
2660
|
// src/format/detect-format.ts
|
|
2715
2661
|
import { detectModelSettingsFormat } from "@doki-land/live2d-core";
|
|
2716
2662
|
function detectMocBinaryFormat(bytes) {
|
|
@@ -3702,16 +3648,81 @@ function moc2ParamGetterFromValues(params, values) {
|
|
|
3702
3648
|
}
|
|
3703
3649
|
return (id) => byId.get(id) ?? 0;
|
|
3704
3650
|
}
|
|
3705
|
-
function
|
|
3651
|
+
function normalizePositionsInto(positions, canvasWidth, canvasHeight, out) {
|
|
3706
3652
|
const w = canvasWidth > 0 ? canvasWidth : 1;
|
|
3707
3653
|
const h = canvasHeight > 0 ? canvasHeight : 1;
|
|
3708
|
-
const out = new Float32Array(positions.length);
|
|
3709
3654
|
for (let i = 0; i + 1 < positions.length; i += 2) {
|
|
3710
3655
|
out[i] = positions[i] / w * 2 - 1;
|
|
3711
3656
|
out[i + 1] = 1 - positions[i + 1] / h * 2;
|
|
3712
3657
|
}
|
|
3658
|
+
}
|
|
3659
|
+
function normalizePositions(positions, canvasWidth, canvasHeight) {
|
|
3660
|
+
const out = new Float32Array(positions.length);
|
|
3661
|
+
normalizePositionsInto(positions, canvasWidth, canvasHeight, out);
|
|
3713
3662
|
return out;
|
|
3714
3663
|
}
|
|
3664
|
+
function evaluateMoc2PoseInto(model, getParam, byId) {
|
|
3665
|
+
const ops = bakeDeformerOps(model, getParam);
|
|
3666
|
+
const w = model.canvasWidth;
|
|
3667
|
+
const h = model.canvasHeight;
|
|
3668
|
+
for (const part of model.parts) {
|
|
3669
|
+
for (const mesh of part.drawData) {
|
|
3670
|
+
const sink = byId.get(mesh.id);
|
|
3671
|
+
if (!sink) continue;
|
|
3672
|
+
const floatCount = mesh.numPoints * 2;
|
|
3673
|
+
const local = interpolateKeyforms(
|
|
3674
|
+
mesh.keyforms,
|
|
3675
|
+
mesh.pivotManager,
|
|
3676
|
+
getParam,
|
|
3677
|
+
floatCount
|
|
3678
|
+
);
|
|
3679
|
+
const world = transformDrawablePositions(mesh, local, ops);
|
|
3680
|
+
let pos = sink.vertexPositions;
|
|
3681
|
+
if (pos.length !== world.length) {
|
|
3682
|
+
pos = new Float32Array(world.length);
|
|
3683
|
+
sink.vertexPositions = pos;
|
|
3684
|
+
}
|
|
3685
|
+
normalizePositionsInto(world, w, h, pos);
|
|
3686
|
+
sink.opacity = interpolateScalarTable(
|
|
3687
|
+
mesh.opacities,
|
|
3688
|
+
mesh.pivotManager,
|
|
3689
|
+
getParam,
|
|
3690
|
+
1
|
|
3691
|
+
);
|
|
3692
|
+
sink.renderOrder = Math.round(
|
|
3693
|
+
interpolateScalarTable(
|
|
3694
|
+
mesh.drawOrders,
|
|
3695
|
+
mesh.pivotManager,
|
|
3696
|
+
getParam,
|
|
3697
|
+
mesh.averageDrawOrder
|
|
3698
|
+
)
|
|
3699
|
+
);
|
|
3700
|
+
sink.visible = part.visible;
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
function moc2DrawableIdsInProgramOrder(model, getParam) {
|
|
3705
|
+
const paramDefs = model.paramDefSet?.params ?? [];
|
|
3706
|
+
const gp = getParam ?? buildParamGetter(paramDefs);
|
|
3707
|
+
const drafts = [];
|
|
3708
|
+
for (const part of model.parts) {
|
|
3709
|
+
for (const mesh of part.drawData) {
|
|
3710
|
+
drafts.push({
|
|
3711
|
+
id: mesh.id,
|
|
3712
|
+
renderOrder: Math.round(
|
|
3713
|
+
interpolateScalarTable(
|
|
3714
|
+
mesh.drawOrders,
|
|
3715
|
+
mesh.pivotManager,
|
|
3716
|
+
gp,
|
|
3717
|
+
mesh.averageDrawOrder
|
|
3718
|
+
)
|
|
3719
|
+
)
|
|
3720
|
+
});
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
drafts.sort((a, b) => a.renderOrder - b.renderOrder);
|
|
3724
|
+
return drafts.map((d) => d.id);
|
|
3725
|
+
}
|
|
3715
3726
|
function lowerDrawable(mesh, getParam, ops, canvasWidth, canvasHeight, partVisible) {
|
|
3716
3727
|
const floatCount = mesh.numPoints * 2;
|
|
3717
3728
|
const local = interpolateKeyforms(
|
|
@@ -4942,15 +4953,24 @@ function meanGlueSeamDistance(positionsByMesh, glue) {
|
|
|
4942
4953
|
}
|
|
4943
4954
|
|
|
4944
4955
|
// src/moc/moc3-to-program.ts
|
|
4945
|
-
function
|
|
4956
|
+
function normalizePositionsInto2(positions, canvasWidth, canvasHeight, pixelsPerUnit, out) {
|
|
4946
4957
|
const ppu = pixelsPerUnit > 0 ? pixelsPerUnit : 1;
|
|
4947
4958
|
const hw = canvasWidth > 0 ? canvasWidth / ppu * 0.5 : 0.5;
|
|
4948
4959
|
const hh = canvasHeight > 0 ? canvasHeight / ppu * 0.5 : 0.5;
|
|
4949
|
-
const out = new Float32Array(positions.length);
|
|
4950
4960
|
for (let i = 0; i + 1 < positions.length; i += 2) {
|
|
4951
4961
|
out[i] = positions[i] / hw;
|
|
4952
4962
|
out[i + 1] = -positions[i + 1] / hh;
|
|
4953
4963
|
}
|
|
4964
|
+
}
|
|
4965
|
+
function normalizePositions2(positions, canvasWidth, canvasHeight, pixelsPerUnit) {
|
|
4966
|
+
const out = new Float32Array(positions.length);
|
|
4967
|
+
normalizePositionsInto2(
|
|
4968
|
+
positions,
|
|
4969
|
+
canvasWidth,
|
|
4970
|
+
canvasHeight,
|
|
4971
|
+
pixelsPerUnit,
|
|
4972
|
+
out
|
|
4973
|
+
);
|
|
4954
4974
|
return out;
|
|
4955
4975
|
}
|
|
4956
4976
|
function moc3DocumentToProgram(doc, options = {}) {
|
|
@@ -5136,6 +5156,155 @@ function moc3DocumentToProgram(doc, options = {}) {
|
|
|
5136
5156
|
drawables
|
|
5137
5157
|
};
|
|
5138
5158
|
}
|
|
5159
|
+
function moc3ArtMeshIndicesInProgramOrder(doc, getParamByIndex) {
|
|
5160
|
+
const meshCount = doc.counts[CountIdx.ART_MESHES] ?? 0;
|
|
5161
|
+
const defaultValues = moc3SectionF32(doc, "parameter.default_values");
|
|
5162
|
+
const gp = getParamByIndex ?? ((index) => defaultValues[index] ?? 0);
|
|
5163
|
+
const keyTables = loadMoc3KeyTables(doc);
|
|
5164
|
+
const enables = moc3SectionI32(doc, "art_mesh.enables");
|
|
5165
|
+
const vertexCounts = moc3SectionI32(doc, "art_mesh.vertex_counts");
|
|
5166
|
+
const indexCounts = moc3SectionI32(doc, "art_mesh.position_index_counts");
|
|
5167
|
+
const keyformBegins = moc3SectionI32(doc, "art_mesh.keyform_begin_indices");
|
|
5168
|
+
const keyformCounts = moc3SectionI32(doc, "art_mesh.keyform_counts");
|
|
5169
|
+
const bandIndices = moc3SectionI32(
|
|
5170
|
+
doc,
|
|
5171
|
+
"art_mesh.keyform_binding_band_indices"
|
|
5172
|
+
);
|
|
5173
|
+
const keyformDrawOrders = moc3SectionF32(
|
|
5174
|
+
doc,
|
|
5175
|
+
"art_mesh_keyform.draw_orders"
|
|
5176
|
+
);
|
|
5177
|
+
const drafts = [];
|
|
5178
|
+
for (let i = 0; i < meshCount; i++) {
|
|
5179
|
+
if ((enables[i] ?? 1) === 0) continue;
|
|
5180
|
+
const vertexCount = vertexCounts[i] ?? 0;
|
|
5181
|
+
const indexCount = indexCounts[i] ?? 0;
|
|
5182
|
+
if (vertexCount <= 0 || indexCount < 3) continue;
|
|
5183
|
+
const kfBegin = keyformBegins[i] ?? 0;
|
|
5184
|
+
const kfCount = keyformCounts[i] ?? 0;
|
|
5185
|
+
if (kfCount <= 0) continue;
|
|
5186
|
+
const band = bandIndices[i] ?? -1;
|
|
5187
|
+
const blend = resolveMoc3KeyformBlend(keyTables, band, gp);
|
|
5188
|
+
drafts.push({
|
|
5189
|
+
artMeshIndex: i,
|
|
5190
|
+
renderOrder: Math.round(
|
|
5191
|
+
blendKeyformScalar(
|
|
5192
|
+
keyformDrawOrders,
|
|
5193
|
+
kfBegin,
|
|
5194
|
+
kfCount,
|
|
5195
|
+
blend,
|
|
5196
|
+
i
|
|
5197
|
+
)
|
|
5198
|
+
)
|
|
5199
|
+
});
|
|
5200
|
+
}
|
|
5201
|
+
drafts.sort((a, b) => a.renderOrder - b.renderOrder);
|
|
5202
|
+
return drafts.map((d) => d.artMeshIndex);
|
|
5203
|
+
}
|
|
5204
|
+
function evaluateMoc3PoseInto(doc, getParamByIndex, byArtMesh, poseOpacity) {
|
|
5205
|
+
const meshCount = doc.counts[CountIdx.ART_MESHES] ?? 0;
|
|
5206
|
+
const keyTables = loadMoc3KeyTables(doc);
|
|
5207
|
+
const deformers = bakeMoc3Deformers(doc, keyTables, getParamByIndex);
|
|
5208
|
+
const glues = loadMoc3Glues(doc);
|
|
5209
|
+
const glueIntensities = moc3SectionF32(doc, "glue_keyform.intensities");
|
|
5210
|
+
const visibles = moc3SectionI32(doc, "art_mesh.visibles");
|
|
5211
|
+
const enables = moc3SectionI32(doc, "art_mesh.enables");
|
|
5212
|
+
const vertexCounts = moc3SectionI32(doc, "art_mesh.vertex_counts");
|
|
5213
|
+
const indexCounts = moc3SectionI32(doc, "art_mesh.position_index_counts");
|
|
5214
|
+
const keyformBegins = moc3SectionI32(doc, "art_mesh.keyform_begin_indices");
|
|
5215
|
+
const keyformCounts = moc3SectionI32(doc, "art_mesh.keyform_counts");
|
|
5216
|
+
const bandIndices = moc3SectionI32(
|
|
5217
|
+
doc,
|
|
5218
|
+
"art_mesh.keyform_binding_band_indices"
|
|
5219
|
+
);
|
|
5220
|
+
const parentDeformers = moc3SectionI32(
|
|
5221
|
+
doc,
|
|
5222
|
+
"art_mesh.parent_deformer_indices"
|
|
5223
|
+
);
|
|
5224
|
+
const keyformOpacities = moc3SectionF32(doc, "art_mesh_keyform.opacities");
|
|
5225
|
+
const keyformDrawOrders = moc3SectionF32(
|
|
5226
|
+
doc,
|
|
5227
|
+
"art_mesh_keyform.draw_orders"
|
|
5228
|
+
);
|
|
5229
|
+
const keyformPosBegins = moc3SectionI32(
|
|
5230
|
+
doc,
|
|
5231
|
+
"art_mesh_keyform.keyform_position_begin_indices"
|
|
5232
|
+
);
|
|
5233
|
+
const keyformPositions = moc3SectionF32(doc, "keyform_position.xys");
|
|
5234
|
+
const cw = doc.canvas.canvasWidth;
|
|
5235
|
+
const ch = doc.canvas.canvasHeight;
|
|
5236
|
+
const ppu = doc.canvas.pixelsPerUnit;
|
|
5237
|
+
const worldByMesh = /* @__PURE__ */ new Map();
|
|
5238
|
+
const opacityByMesh = /* @__PURE__ */ new Map();
|
|
5239
|
+
const orderByMesh = /* @__PURE__ */ new Map();
|
|
5240
|
+
const visibleByMesh = /* @__PURE__ */ new Map();
|
|
5241
|
+
for (let i = 0; i < meshCount; i++) {
|
|
5242
|
+
if (!byArtMesh.has(i)) continue;
|
|
5243
|
+
if ((enables[i] ?? 1) === 0) continue;
|
|
5244
|
+
const vertexCount = vertexCounts[i] ?? 0;
|
|
5245
|
+
const indexCount = indexCounts[i] ?? 0;
|
|
5246
|
+
if (vertexCount <= 0 || indexCount < 3) continue;
|
|
5247
|
+
const kfBegin = keyformBegins[i] ?? 0;
|
|
5248
|
+
const kfCount = keyformCounts[i] ?? 0;
|
|
5249
|
+
if (kfCount <= 0) continue;
|
|
5250
|
+
const band = bandIndices[i] ?? -1;
|
|
5251
|
+
const blend = resolveMoc3KeyformBlend(keyTables, band, getParamByIndex);
|
|
5252
|
+
const local = blendKeyformFloats(
|
|
5253
|
+
keyformPositions,
|
|
5254
|
+
keyformPosBegins,
|
|
5255
|
+
kfBegin,
|
|
5256
|
+
kfCount,
|
|
5257
|
+
vertexCount * 2,
|
|
5258
|
+
blend
|
|
5259
|
+
);
|
|
5260
|
+
const parentIndex = parentDeformers[i] ?? -1;
|
|
5261
|
+
const parent = parentIndex >= 0 ? deformers[parentIndex] ?? null : null;
|
|
5262
|
+
const world = parent ? applyParentToPoints(local, parent) : local;
|
|
5263
|
+
worldByMesh.set(i, world);
|
|
5264
|
+
opacityByMesh.set(
|
|
5265
|
+
i,
|
|
5266
|
+
blendKeyformScalar(keyformOpacities, kfBegin, kfCount, blend, 1)
|
|
5267
|
+
);
|
|
5268
|
+
orderByMesh.set(
|
|
5269
|
+
i,
|
|
5270
|
+
Math.round(
|
|
5271
|
+
blendKeyformScalar(
|
|
5272
|
+
keyformDrawOrders,
|
|
5273
|
+
kfBegin,
|
|
5274
|
+
kfCount,
|
|
5275
|
+
blend,
|
|
5276
|
+
i
|
|
5277
|
+
)
|
|
5278
|
+
)
|
|
5279
|
+
);
|
|
5280
|
+
visibleByMesh.set(i, (visibles[i] ?? 1) !== 0);
|
|
5281
|
+
}
|
|
5282
|
+
applyMoc3Glues(
|
|
5283
|
+
worldByMesh,
|
|
5284
|
+
glues,
|
|
5285
|
+
keyTables,
|
|
5286
|
+
getParamByIndex,
|
|
5287
|
+
glueIntensities
|
|
5288
|
+
);
|
|
5289
|
+
for (const [artMeshIndex, world] of worldByMesh) {
|
|
5290
|
+
const sink = byArtMesh.get(artMeshIndex);
|
|
5291
|
+
if (!sink) continue;
|
|
5292
|
+
let pos = sink.vertexPositions;
|
|
5293
|
+
if (pos.length !== world.length) {
|
|
5294
|
+
pos = new Float32Array(world.length);
|
|
5295
|
+
sink.vertexPositions = pos;
|
|
5296
|
+
}
|
|
5297
|
+
normalizePositionsInto2(world, cw, ch, ppu, pos);
|
|
5298
|
+
const opacity = opacityByMesh.get(artMeshIndex) ?? 1;
|
|
5299
|
+
sink.renderOrder = orderByMesh.get(artMeshIndex) ?? sink.renderOrder;
|
|
5300
|
+
sink.visible = visibleByMesh.get(artMeshIndex) ?? true;
|
|
5301
|
+
const slot = sink.index;
|
|
5302
|
+
if (slot >= 0 && slot < poseOpacity.length) {
|
|
5303
|
+
poseOpacity[slot] = opacity;
|
|
5304
|
+
}
|
|
5305
|
+
sink.opacity = opacity;
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5139
5308
|
|
|
5140
5309
|
// src/moc/decode.ts
|
|
5141
5310
|
function readMagic2(bytes) {
|
|
@@ -5186,49 +5355,90 @@ async function decodeMoc3(bytes) {
|
|
|
5186
5355
|
|
|
5187
5356
|
// src/moc/moc2.ts
|
|
5188
5357
|
import { detectModelSettingsFormat as detectModelSettingsFormat2 } from "@doki-land/live2d-core";
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5358
|
+
var stateByModel = /* @__PURE__ */ new WeakMap();
|
|
5359
|
+
function allocateMeshesFromProgram(program, drawableIds) {
|
|
5360
|
+
const meshes = [];
|
|
5361
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5362
|
+
for (let i = 0; i < program.drawables.length; i++) {
|
|
5363
|
+
const d = program.drawables[i];
|
|
5364
|
+
const mesh = {
|
|
5365
|
+
index: d.index,
|
|
5366
|
+
textureIndex: d.textureIndex,
|
|
5367
|
+
vertexPositions: new Float32Array(d.positions),
|
|
5368
|
+
uvs: d.uvs,
|
|
5369
|
+
indices: d.indices,
|
|
5370
|
+
opacity: d.opacity,
|
|
5371
|
+
blendMode: d.blendMode,
|
|
5372
|
+
invertedMask: d.invertedMask,
|
|
5373
|
+
renderOrder: d.renderOrder,
|
|
5374
|
+
dynamicFlag: true,
|
|
5375
|
+
maskIndices: [...d.maskIndices],
|
|
5376
|
+
visible: d.visible
|
|
5377
|
+
};
|
|
5378
|
+
meshes.push(mesh);
|
|
5379
|
+
const id = drawableIds[i];
|
|
5380
|
+
if (id) byId.set(id, mesh);
|
|
5381
|
+
}
|
|
5382
|
+
return { meshes, byId };
|
|
5383
|
+
}
|
|
5384
|
+
function buildBindings(instance) {
|
|
5385
|
+
const bindings = [];
|
|
5386
|
+
const paramIndexById = /* @__PURE__ */ new Map();
|
|
5387
|
+
for (let i = 0; i < instance.program.parameters.length; i++) {
|
|
5388
|
+
const p = instance.program.parameters[i];
|
|
5389
|
+
const binding = {
|
|
5390
|
+
id: p.id,
|
|
5391
|
+
min: p.min,
|
|
5392
|
+
max: p.max,
|
|
5393
|
+
defaultValue: p.defaultValue,
|
|
5394
|
+
value: instance.parameterValues[i] ?? p.defaultValue
|
|
5395
|
+
};
|
|
5396
|
+
bindings.push(binding);
|
|
5397
|
+
paramIndexById.set(p.id, i);
|
|
5398
|
+
}
|
|
5399
|
+
return { bindings, paramIndexById };
|
|
5204
5400
|
}
|
|
5205
|
-
function
|
|
5206
|
-
let
|
|
5207
|
-
|
|
5208
|
-
|
|
5401
|
+
function syncBindingValues(state) {
|
|
5402
|
+
for (let i = 0; i < state.bindings.length; i++) {
|
|
5403
|
+
const b = state.bindings[i];
|
|
5404
|
+
b.value = state.instance.parameterValues[i] ?? b.defaultValue;
|
|
5209
5405
|
}
|
|
5210
|
-
return s;
|
|
5211
5406
|
}
|
|
5212
|
-
|
|
5407
|
+
function refreshDrawView(state) {
|
|
5408
|
+
const view = state.drawView;
|
|
5409
|
+
view.length = 0;
|
|
5410
|
+
for (const m of state.meshes) view.push(m);
|
|
5411
|
+
view.sort((a, b) => a.renderOrder - b.renderOrder || a.index - b.index);
|
|
5412
|
+
}
|
|
5213
5413
|
function bakePose(state) {
|
|
5214
|
-
|
|
5215
|
-
const
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5414
|
+
if (!state.poseDirty) return;
|
|
5415
|
+
const getParam = moc2ParamGetterFromValues(
|
|
5416
|
+
state.instance.program.parameters,
|
|
5417
|
+
state.instance.parameterValues
|
|
5418
|
+
);
|
|
5419
|
+
evaluateMoc2PoseInto(state.moc, getParam, state.byId);
|
|
5420
|
+
refreshDrawView(state);
|
|
5421
|
+
syncBindingValues(state);
|
|
5422
|
+
state.poseDirty = false;
|
|
5423
|
+
}
|
|
5424
|
+
function frameFromMeshes(meshes, timeSeconds) {
|
|
5425
|
+
const drawables = [];
|
|
5426
|
+
for (const m of meshes) {
|
|
5427
|
+
drawables.push({
|
|
5428
|
+
index: m.index,
|
|
5429
|
+
textureIndex: m.textureIndex,
|
|
5430
|
+
positions: m.vertexPositions,
|
|
5431
|
+
uvs: m.uvs,
|
|
5432
|
+
indices: m.indices,
|
|
5433
|
+
opacity: m.opacity,
|
|
5434
|
+
blendMode: m.blendMode,
|
|
5435
|
+
renderOrder: m.renderOrder,
|
|
5436
|
+
visible: m.visible,
|
|
5437
|
+
invertedMask: m.invertedMask,
|
|
5438
|
+
maskIndices: m.maskIndices
|
|
5439
|
+
});
|
|
5219
5440
|
}
|
|
5220
|
-
|
|
5221
|
-
getParam: moc2ParamGetterFromValues(
|
|
5222
|
-
state.moc.paramDefSet.params,
|
|
5223
|
-
values
|
|
5224
|
-
)
|
|
5225
|
-
});
|
|
5226
|
-
const next = createModelInstance(program);
|
|
5227
|
-
next.parameterValues.set(values);
|
|
5228
|
-
next.timeSeconds = timeSeconds;
|
|
5229
|
-
state.instance = next;
|
|
5230
|
-
state.bakedFingerprint = fp;
|
|
5231
|
-
state.lastFrame = evaluateFrame(next);
|
|
5441
|
+
return { timeSeconds, drawables };
|
|
5232
5442
|
}
|
|
5233
5443
|
var Moc2Backend = class {
|
|
5234
5444
|
format = "moc2";
|
|
@@ -5249,17 +5459,30 @@ var Moc2Backend = class {
|
|
|
5249
5459
|
const moc = shared?.moc2Model ?? new Moc2Parser(bytes).parseModel();
|
|
5250
5460
|
const program = moc2ModelToProgram(moc);
|
|
5251
5461
|
const instance = createModelInstance(program);
|
|
5462
|
+
const drawableIds = moc2DrawableIdsInProgramOrder(moc);
|
|
5463
|
+
const { meshes, byId } = allocateMeshesFromProgram(
|
|
5464
|
+
program,
|
|
5465
|
+
drawableIds
|
|
5466
|
+
);
|
|
5467
|
+
const { bindings, paramIndexById } = buildBindings(instance);
|
|
5468
|
+
const drawView = [];
|
|
5252
5469
|
const model = {
|
|
5253
5470
|
id: settings.name ?? settings.url,
|
|
5254
5471
|
settings,
|
|
5255
5472
|
format: "moc2"
|
|
5256
5473
|
};
|
|
5257
|
-
|
|
5474
|
+
const state = {
|
|
5258
5475
|
moc,
|
|
5259
5476
|
instance,
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5477
|
+
meshes,
|
|
5478
|
+
drawView,
|
|
5479
|
+
byId,
|
|
5480
|
+
poseDirty: true,
|
|
5481
|
+
bindings,
|
|
5482
|
+
paramIndexById
|
|
5483
|
+
};
|
|
5484
|
+
bakePose(state);
|
|
5485
|
+
stateByModel.set(model, state);
|
|
5263
5486
|
return model;
|
|
5264
5487
|
}
|
|
5265
5488
|
updateModel(model, deltaTimeSeconds) {
|
|
@@ -5267,46 +5490,43 @@ var Moc2Backend = class {
|
|
|
5267
5490
|
if (!state) return;
|
|
5268
5491
|
state.instance.timeSeconds += deltaTimeSeconds;
|
|
5269
5492
|
bakePose(state);
|
|
5270
|
-
if (state.lastFrame) {
|
|
5271
|
-
state.lastFrame = {
|
|
5272
|
-
...state.lastFrame,
|
|
5273
|
-
timeSeconds: state.instance.timeSeconds
|
|
5274
|
-
};
|
|
5275
|
-
}
|
|
5276
5493
|
}
|
|
5277
5494
|
getDrawables(model) {
|
|
5278
5495
|
const state = stateByModel.get(model);
|
|
5279
5496
|
if (!state) return [];
|
|
5280
5497
|
bakePose(state);
|
|
5281
|
-
|
|
5282
|
-
state.lastFrame = frame;
|
|
5283
|
-
return frame.drawables.map(toDrawableMesh);
|
|
5498
|
+
return state.drawView;
|
|
5284
5499
|
}
|
|
5285
5500
|
captureFrame(model) {
|
|
5286
5501
|
const state = stateByModel.get(model);
|
|
5287
5502
|
if (!state) return null;
|
|
5288
5503
|
bakePose(state);
|
|
5289
|
-
|
|
5290
|
-
state.lastFrame = frame;
|
|
5291
|
-
return frame;
|
|
5504
|
+
return frameFromMeshes(state.drawView, state.instance.timeSeconds);
|
|
5292
5505
|
}
|
|
5293
5506
|
setParameter(model, id, value) {
|
|
5294
5507
|
const state = stateByModel.get(model);
|
|
5295
5508
|
if (!state) return;
|
|
5296
5509
|
setParameterValue(state.instance, id, value);
|
|
5297
|
-
|
|
5298
|
-
|
|
5510
|
+
const index = state.paramIndexById.get(id);
|
|
5511
|
+
if (index !== void 0) {
|
|
5512
|
+
const binding = state.bindings[index];
|
|
5513
|
+
if (binding) {
|
|
5514
|
+
binding.value = state.instance.parameterValues[index] ?? binding.defaultValue;
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
state.poseDirty = true;
|
|
5518
|
+
}
|
|
5519
|
+
resolveParameter(model, id) {
|
|
5520
|
+
const state = stateByModel.get(model);
|
|
5521
|
+
if (!state) return void 0;
|
|
5522
|
+
return state.paramIndexById.get(id);
|
|
5299
5523
|
}
|
|
5300
5524
|
listParameters(model) {
|
|
5301
5525
|
const state = stateByModel.get(model);
|
|
5302
5526
|
if (!state) return [];
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
max: p.max,
|
|
5307
|
-
defaultValue: p.defaultValue,
|
|
5308
|
-
value: state.instance.parameterValues[i] ?? p.defaultValue
|
|
5309
|
-
}));
|
|
5527
|
+
bakePose(state);
|
|
5528
|
+
syncBindingValues(state);
|
|
5529
|
+
return state.bindings;
|
|
5310
5530
|
}
|
|
5311
5531
|
hitTest(_model, _x, _y) {
|
|
5312
5532
|
return null;
|
|
@@ -5314,6 +5534,10 @@ var Moc2Backend = class {
|
|
|
5314
5534
|
destroyModel(model) {
|
|
5315
5535
|
stateByModel.delete(model);
|
|
5316
5536
|
}
|
|
5537
|
+
/** Test/harness: stable program + instance refs. */
|
|
5538
|
+
getResidentInstance(model) {
|
|
5539
|
+
return stateByModel.get(model)?.instance ?? null;
|
|
5540
|
+
}
|
|
5317
5541
|
};
|
|
5318
5542
|
function createMoc2Backend() {
|
|
5319
5543
|
return new Moc2Backend();
|
|
@@ -5352,11 +5576,12 @@ function cascadedPartOpacity(tables, artMeshIndex, overrides) {
|
|
|
5352
5576
|
}
|
|
5353
5577
|
|
|
5354
5578
|
// src/moc/moc3.ts
|
|
5355
|
-
|
|
5356
|
-
|
|
5579
|
+
var stateByModel2 = /* @__PURE__ */ new WeakMap();
|
|
5580
|
+
function allocateMeshesFromProgram2(program) {
|
|
5581
|
+
return program.drawables.map((d) => ({
|
|
5357
5582
|
index: d.index,
|
|
5358
5583
|
textureIndex: d.textureIndex,
|
|
5359
|
-
vertexPositions: d.positions,
|
|
5584
|
+
vertexPositions: new Float32Array(d.positions),
|
|
5360
5585
|
uvs: d.uvs,
|
|
5361
5586
|
indices: d.indices,
|
|
5362
5587
|
opacity: d.opacity,
|
|
@@ -5366,34 +5591,82 @@ function toDrawableMesh2(d) {
|
|
|
5366
5591
|
dynamicFlag: true,
|
|
5367
5592
|
maskIndices: [...d.maskIndices],
|
|
5368
5593
|
visible: d.visible
|
|
5369
|
-
};
|
|
5594
|
+
}));
|
|
5595
|
+
}
|
|
5596
|
+
function buildBindings2(instance) {
|
|
5597
|
+
const bindings = [];
|
|
5598
|
+
const paramIndexById = /* @__PURE__ */ new Map();
|
|
5599
|
+
for (let i = 0; i < instance.program.parameters.length; i++) {
|
|
5600
|
+
const p = instance.program.parameters[i];
|
|
5601
|
+
bindings.push({
|
|
5602
|
+
id: p.id,
|
|
5603
|
+
min: p.min,
|
|
5604
|
+
max: p.max,
|
|
5605
|
+
defaultValue: p.defaultValue,
|
|
5606
|
+
value: instance.parameterValues[i] ?? p.defaultValue
|
|
5607
|
+
});
|
|
5608
|
+
paramIndexById.set(p.id, i);
|
|
5609
|
+
}
|
|
5610
|
+
return { bindings, paramIndexById };
|
|
5370
5611
|
}
|
|
5371
|
-
function
|
|
5372
|
-
let
|
|
5373
|
-
|
|
5374
|
-
|
|
5612
|
+
function syncBindingValues2(state) {
|
|
5613
|
+
for (let i = 0; i < state.bindings.length; i++) {
|
|
5614
|
+
const b = state.bindings[i];
|
|
5615
|
+
b.value = state.instance.parameterValues[i] ?? b.defaultValue;
|
|
5616
|
+
}
|
|
5617
|
+
}
|
|
5618
|
+
function refreshDrawView2(state) {
|
|
5619
|
+
const view = state.drawView;
|
|
5620
|
+
view.length = 0;
|
|
5621
|
+
for (const m of state.meshes) view.push(m);
|
|
5622
|
+
view.sort((a, b) => a.renderOrder - b.renderOrder || a.index - b.index);
|
|
5623
|
+
}
|
|
5624
|
+
function applyPartOpacity(state) {
|
|
5625
|
+
const tables = state.doc ? readMoc3PartTables(state.doc) : null;
|
|
5626
|
+
for (const mesh of state.meshes) {
|
|
5627
|
+
const base = state.poseOpacity[mesh.index] ?? mesh.opacity;
|
|
5628
|
+
if (!tables || state.partOpacity.size === 0) {
|
|
5629
|
+
mesh.opacity = base;
|
|
5630
|
+
continue;
|
|
5631
|
+
}
|
|
5632
|
+
mesh.opacity = base * cascadedPartOpacity(tables, mesh.index, state.partOpacity);
|
|
5375
5633
|
}
|
|
5376
|
-
return s;
|
|
5377
5634
|
}
|
|
5378
|
-
var stateByModel2 = /* @__PURE__ */ new WeakMap();
|
|
5379
5635
|
function bakePose2(state) {
|
|
5380
|
-
if (!state.
|
|
5381
|
-
|
|
5382
|
-
|
|
5636
|
+
if (!state.poseDirty) return;
|
|
5637
|
+
if (state.doc) {
|
|
5638
|
+
const values = state.instance.parameterValues;
|
|
5639
|
+
evaluateMoc3PoseInto(
|
|
5640
|
+
state.doc,
|
|
5641
|
+
(i) => values[i] ?? 0,
|
|
5642
|
+
state.byArtMesh,
|
|
5643
|
+
state.poseOpacity
|
|
5644
|
+
);
|
|
5645
|
+
} else {
|
|
5646
|
+
evaluateFrameInto(state.instance, state.meshes, state.poseOpacity);
|
|
5383
5647
|
}
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5648
|
+
refreshDrawView2(state);
|
|
5649
|
+
syncBindingValues2(state);
|
|
5650
|
+
state.poseDirty = false;
|
|
5651
|
+
}
|
|
5652
|
+
function frameFromMeshes2(meshes, timeSeconds) {
|
|
5653
|
+
const drawables = [];
|
|
5654
|
+
for (const m of meshes) {
|
|
5655
|
+
drawables.push({
|
|
5656
|
+
index: m.index,
|
|
5657
|
+
textureIndex: m.textureIndex,
|
|
5658
|
+
positions: m.vertexPositions,
|
|
5659
|
+
uvs: m.uvs,
|
|
5660
|
+
indices: m.indices,
|
|
5661
|
+
opacity: m.opacity,
|
|
5662
|
+
blendMode: m.blendMode,
|
|
5663
|
+
renderOrder: m.renderOrder,
|
|
5664
|
+
visible: m.visible,
|
|
5665
|
+
invertedMask: m.invertedMask,
|
|
5666
|
+
maskIndices: m.maskIndices
|
|
5667
|
+
});
|
|
5668
|
+
}
|
|
5669
|
+
return { timeSeconds, drawables };
|
|
5397
5670
|
}
|
|
5398
5671
|
var Moc3Backend = class {
|
|
5399
5672
|
format = "moc3";
|
|
@@ -5421,18 +5694,39 @@ var Moc3Backend = class {
|
|
|
5421
5694
|
program = moc3DocumentToProgram(doc);
|
|
5422
5695
|
}
|
|
5423
5696
|
const instance = createModelInstance(program);
|
|
5697
|
+
const meshes = allocateMeshesFromProgram2(program);
|
|
5698
|
+
const byArtMesh = /* @__PURE__ */ new Map();
|
|
5699
|
+
if (doc) {
|
|
5700
|
+
const artOrder = moc3ArtMeshIndicesInProgramOrder(doc);
|
|
5701
|
+
for (let i = 0; i < artOrder.length; i++) {
|
|
5702
|
+
const art = artOrder[i];
|
|
5703
|
+
const mesh = meshes[i];
|
|
5704
|
+
if (mesh) byArtMesh.set(art, mesh);
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
const poseOpacity = new Float32Array(meshes.length);
|
|
5708
|
+
for (const m of meshes) poseOpacity[m.index] = m.opacity;
|
|
5709
|
+
const { bindings, paramIndexById } = buildBindings2(instance);
|
|
5424
5710
|
const model = {
|
|
5425
5711
|
id: settings.name ?? settings.url,
|
|
5426
5712
|
settings,
|
|
5427
5713
|
format: "moc3"
|
|
5428
5714
|
};
|
|
5429
|
-
|
|
5715
|
+
const state = {
|
|
5430
5716
|
doc,
|
|
5431
5717
|
instance,
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5718
|
+
meshes,
|
|
5719
|
+
drawView: [],
|
|
5720
|
+
byArtMesh,
|
|
5721
|
+
poseOpacity,
|
|
5722
|
+
poseDirty: true,
|
|
5723
|
+
partOpacity: /* @__PURE__ */ new Map(),
|
|
5724
|
+
bindings,
|
|
5725
|
+
paramIndexById
|
|
5726
|
+
};
|
|
5727
|
+
bakePose2(state);
|
|
5728
|
+
applyPartOpacity(state);
|
|
5729
|
+
stateByModel2.set(model, state);
|
|
5436
5730
|
return model;
|
|
5437
5731
|
}
|
|
5438
5732
|
updateModel(model, deltaTimeSeconds) {
|
|
@@ -5440,49 +5734,34 @@ var Moc3Backend = class {
|
|
|
5440
5734
|
if (!state) return;
|
|
5441
5735
|
state.instance.timeSeconds += deltaTimeSeconds;
|
|
5442
5736
|
bakePose2(state);
|
|
5443
|
-
|
|
5444
|
-
state.lastFrame = {
|
|
5445
|
-
...state.lastFrame,
|
|
5446
|
-
timeSeconds: state.instance.timeSeconds
|
|
5447
|
-
};
|
|
5448
|
-
}
|
|
5737
|
+
applyPartOpacity(state);
|
|
5449
5738
|
}
|
|
5450
5739
|
getDrawables(model) {
|
|
5451
5740
|
const state = stateByModel2.get(model);
|
|
5452
5741
|
if (!state) return [];
|
|
5453
5742
|
bakePose2(state);
|
|
5454
|
-
|
|
5455
|
-
state.
|
|
5456
|
-
const tables = state.doc ? readMoc3PartTables(state.doc) : null;
|
|
5457
|
-
return frame.drawables.map((d) => {
|
|
5458
|
-
const mesh = toDrawableMesh2(d);
|
|
5459
|
-
if (!tables || state.partOpacity.size === 0) return mesh;
|
|
5460
|
-
const mul = cascadedPartOpacity(tables, d.index, state.partOpacity);
|
|
5461
|
-
return { ...mesh, opacity: mesh.opacity * mul };
|
|
5462
|
-
});
|
|
5743
|
+
applyPartOpacity(state);
|
|
5744
|
+
return state.drawView;
|
|
5463
5745
|
}
|
|
5464
5746
|
captureFrame(model) {
|
|
5465
5747
|
const state = stateByModel2.get(model);
|
|
5466
5748
|
if (!state) return null;
|
|
5467
5749
|
bakePose2(state);
|
|
5468
|
-
|
|
5469
|
-
state.
|
|
5470
|
-
const tables = state.doc ? readMoc3PartTables(state.doc) : null;
|
|
5471
|
-
if (!tables || state.partOpacity.size === 0) return frame;
|
|
5472
|
-
return {
|
|
5473
|
-
...frame,
|
|
5474
|
-
drawables: frame.drawables.map((d) => ({
|
|
5475
|
-
...d,
|
|
5476
|
-
opacity: d.opacity * cascadedPartOpacity(tables, d.index, state.partOpacity)
|
|
5477
|
-
}))
|
|
5478
|
-
};
|
|
5750
|
+
applyPartOpacity(state);
|
|
5751
|
+
return frameFromMeshes2(state.drawView, state.instance.timeSeconds);
|
|
5479
5752
|
}
|
|
5480
5753
|
setParameter(model, id, value) {
|
|
5481
5754
|
const state = stateByModel2.get(model);
|
|
5482
5755
|
if (!state) return;
|
|
5483
5756
|
setParameterValue(state.instance, id, value);
|
|
5484
|
-
|
|
5485
|
-
|
|
5757
|
+
const index = state.paramIndexById.get(id);
|
|
5758
|
+
if (index !== void 0) {
|
|
5759
|
+
const binding = state.bindings[index];
|
|
5760
|
+
if (binding) {
|
|
5761
|
+
binding.value = state.instance.parameterValues[index] ?? binding.defaultValue;
|
|
5762
|
+
}
|
|
5763
|
+
}
|
|
5764
|
+
state.poseDirty = true;
|
|
5486
5765
|
}
|
|
5487
5766
|
setPartOpacity(model, id, value) {
|
|
5488
5767
|
const state = stateByModel2.get(model);
|
|
@@ -5490,16 +5769,17 @@ var Moc3Backend = class {
|
|
|
5490
5769
|
const v = Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 1;
|
|
5491
5770
|
state.partOpacity.set(id, v);
|
|
5492
5771
|
}
|
|
5772
|
+
resolveParameter(model, id) {
|
|
5773
|
+
const state = stateByModel2.get(model);
|
|
5774
|
+
if (!state) return void 0;
|
|
5775
|
+
return state.paramIndexById.get(id);
|
|
5776
|
+
}
|
|
5493
5777
|
listParameters(model) {
|
|
5494
5778
|
const state = stateByModel2.get(model);
|
|
5495
5779
|
if (!state) return [];
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
max: p.max,
|
|
5500
|
-
defaultValue: p.defaultValue,
|
|
5501
|
-
value: state.instance.parameterValues[i] ?? p.defaultValue
|
|
5502
|
-
}));
|
|
5780
|
+
bakePose2(state);
|
|
5781
|
+
syncBindingValues2(state);
|
|
5782
|
+
return state.bindings;
|
|
5503
5783
|
}
|
|
5504
5784
|
hitTest(_model, _x, _y) {
|
|
5505
5785
|
return null;
|
|
@@ -5507,11 +5787,105 @@ var Moc3Backend = class {
|
|
|
5507
5787
|
destroyModel(model) {
|
|
5508
5788
|
stateByModel2.delete(model);
|
|
5509
5789
|
}
|
|
5790
|
+
getResidentInstance(model) {
|
|
5791
|
+
return stateByModel2.get(model)?.instance ?? null;
|
|
5792
|
+
}
|
|
5510
5793
|
};
|
|
5511
5794
|
function createMoc3Backend() {
|
|
5512
5795
|
return new Moc3Backend();
|
|
5513
5796
|
}
|
|
5514
5797
|
|
|
5798
|
+
// src/runtime/create-renderer.ts
|
|
5799
|
+
var DEFAULT_PREFER = ["webgpu", "webgl2", "canvas2d"];
|
|
5800
|
+
var INIT_TIMEOUT_MS = {
|
|
5801
|
+
webgpu: 2500,
|
|
5802
|
+
webgl2: 1500,
|
|
5803
|
+
canvas2d: 1e3
|
|
5804
|
+
};
|
|
5805
|
+
function instantiate(kind, options) {
|
|
5806
|
+
if (kind === "webgpu") return createWebGpuRenderer(options.webgpu);
|
|
5807
|
+
if (kind === "webgl2") return createWebGl2Renderer(options.webgl2);
|
|
5808
|
+
return createCanvas2DRenderer(options.canvas2d);
|
|
5809
|
+
}
|
|
5810
|
+
async function initializeWithTimeout(kind, candidate, canvas) {
|
|
5811
|
+
const ms = INIT_TIMEOUT_MS[kind];
|
|
5812
|
+
let timer;
|
|
5813
|
+
try {
|
|
5814
|
+
await Promise.race([
|
|
5815
|
+
candidate.initialize(canvas),
|
|
5816
|
+
new Promise((_, reject) => {
|
|
5817
|
+
timer = setTimeout(() => {
|
|
5818
|
+
reject(
|
|
5819
|
+
new Error(
|
|
5820
|
+
`@doki-land/live2d-renderer: ${kind} initialize timed out after ${ms}ms`
|
|
5821
|
+
)
|
|
5822
|
+
);
|
|
5823
|
+
}, ms);
|
|
5824
|
+
})
|
|
5825
|
+
]);
|
|
5826
|
+
} finally {
|
|
5827
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5828
|
+
}
|
|
5829
|
+
}
|
|
5830
|
+
var FallbackRenderer = class {
|
|
5831
|
+
#inner = null;
|
|
5832
|
+
#kind = "webgpu";
|
|
5833
|
+
#prefer;
|
|
5834
|
+
#options;
|
|
5835
|
+
constructor(prefer, options) {
|
|
5836
|
+
this.#prefer = prefer;
|
|
5837
|
+
this.#options = options;
|
|
5838
|
+
}
|
|
5839
|
+
get kind() {
|
|
5840
|
+
return this.#inner?.kind ?? this.#kind;
|
|
5841
|
+
}
|
|
5842
|
+
async initialize(canvas) {
|
|
5843
|
+
const errors = [];
|
|
5844
|
+
for (const kind of this.#prefer) {
|
|
5845
|
+
const candidate = instantiate(kind, this.#options);
|
|
5846
|
+
try {
|
|
5847
|
+
await initializeWithTimeout(kind, candidate, canvas);
|
|
5848
|
+
this.#inner = candidate;
|
|
5849
|
+
this.#kind = candidate.kind;
|
|
5850
|
+
return;
|
|
5851
|
+
} catch (err) {
|
|
5852
|
+
candidate.destroy();
|
|
5853
|
+
errors.push(
|
|
5854
|
+
`${kind}: ${err instanceof Error ? err.message : String(err)}`
|
|
5855
|
+
);
|
|
5856
|
+
}
|
|
5857
|
+
}
|
|
5858
|
+
throw new Error(
|
|
5859
|
+
`@doki-land/live2d-renderer: no renderer initialized (${errors.join("; ")})`
|
|
5860
|
+
);
|
|
5861
|
+
}
|
|
5862
|
+
createModelDrawPass() {
|
|
5863
|
+
if (!this.#inner) {
|
|
5864
|
+
throw new Error(
|
|
5865
|
+
"@doki-land/live2d-renderer: renderer not initialized"
|
|
5866
|
+
);
|
|
5867
|
+
}
|
|
5868
|
+
return this.#inner.createModelDrawPass();
|
|
5869
|
+
}
|
|
5870
|
+
beginFrame() {
|
|
5871
|
+
this.#inner?.beginFrame();
|
|
5872
|
+
}
|
|
5873
|
+
endFrame() {
|
|
5874
|
+
this.#inner?.endFrame();
|
|
5875
|
+
}
|
|
5876
|
+
resize(width, height) {
|
|
5877
|
+
this.#inner?.resize(width, height);
|
|
5878
|
+
}
|
|
5879
|
+
destroy() {
|
|
5880
|
+
this.#inner?.destroy();
|
|
5881
|
+
this.#inner = null;
|
|
5882
|
+
}
|
|
5883
|
+
};
|
|
5884
|
+
function createRenderer(options = {}) {
|
|
5885
|
+
const prefer = options.prefer?.length ? options.prefer : DEFAULT_PREFER;
|
|
5886
|
+
return new FallbackRenderer(prefer, options);
|
|
5887
|
+
}
|
|
5888
|
+
|
|
5515
5889
|
// src/runtime/model-runtime.ts
|
|
5516
5890
|
function selectModelBackend(backends, json) {
|
|
5517
5891
|
const hit = backends.find((b) => b.canHandle(json));
|