@bitefoundry/retrieviewer 0.0.2 → 0.0.4
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/ASSET-PROVENANCE.md +6 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +65 -0
- package/DESKTOP-PLATFORMS.md +75 -0
- package/INSTALLING.md +8 -5
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +110 -0
- package/README.md +119 -58
- package/RELEASING.md +27 -14
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/desktop/platform.mjs +27 -0
- package/integrations/linux-overlay/README.md +83 -0
- package/integrations/linux-overlay/overlay.py +1094 -0
- package/integrations/macos-overlay/README.md +83 -0
- package/integrations/macos-overlay/overlay.jxa +639 -0
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +4 -4
- package/integrations/windows-overlay/desktop.mjs +40 -8
- package/integrations/windows-overlay/protocol.mjs +11 -7
- package/integrations/windows-overlay/worker.mjs +13 -7
- package/package.json +41 -14
- package/puppy-comfort-sprites.mjs +25 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +77 -0
- package/puppy-companion-life.mjs +49 -16
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +65 -14
- package/retrieviewer-cli.mjs +10 -3
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +10 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -1,575 +0,0 @@
|
|
|
1
|
-
// Pig behaviour layer for the quadruped engine (species.motion.hooks, see core/motion/actions.js):
|
|
2
|
-
//
|
|
3
|
-
// update(P, dt, layer) every frame over the action layer: the corkscrew tail (curled and wagging
|
|
4
|
-
// when active or feeding, uncurled and hanging when resting, dead or afraid),
|
|
5
|
-
// the waddle (the heavy trunk rolls from side to side at the walk and trot,
|
|
6
|
-
// the head nods), piglets' springy bounce, grunting (jaw pulses, a vocalize
|
|
7
|
-
// event), rooting while eating (the disc pushed into the soil in forward-up
|
|
8
|
-
// nudges, the jaw working, tail wagging), idle variants (sniffing with the head
|
|
9
|
-
// up, grunts, piglets' frolics)
|
|
10
|
-
// pose(engine, dt) after the engine's solve: the rostral disc wiggles and twitches (sniffing)
|
|
11
|
-
// actions lie (kneels, drops the hindquarters, then flops onto its side), sleep
|
|
12
|
-
// (lateral, eyes shut), wallow (rocking on the side), attack (sow: a shoulder
|
|
13
|
-
// shove with a sideways bite; boar: head low, then an upward tusk slash),
|
|
14
|
-
// hit (a squeal, tail uncurls), grunt, sniff, root (looping eat), frolic
|
|
15
|
-
// (piglet: two stiff-legged bounces in place with a head toss)
|
|
16
|
-
//
|
|
17
|
-
// Distances are pig metres at the reference size (x cfg.s); posture offsets the engine multiplies by
|
|
18
|
-
// cfg.k (fwd, side, headRaise, neckReach) are divided by cfg.unit.
|
|
19
|
-
import * as THREE from 'three';
|
|
20
|
-
import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
|
|
21
|
-
import { mx, ONESHOTS, POSTURES } from '../../core/motion/actions.js';
|
|
22
|
-
import { earSpine, earLeaf } from './ears.js';
|
|
23
|
-
import { HZ, HY, pigJoints } from './rig.js';
|
|
24
|
-
import { composeWarps } from '../../core/build/warp.js';
|
|
25
|
-
|
|
26
|
-
const _q = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1);
|
|
27
|
-
// extra height of the occiput over the ground when the head lies on its side (m at the reference
|
|
28
|
-
// size): the engine's value fits a slim skull, a pig's jowls are ~5 cm wider
|
|
29
|
-
const HEAD_REST = 0.085;
|
|
30
|
-
// lying on the side (lie, sleep, wallow, death): the forelegs only partly laid out on the ground and not
|
|
31
|
-
// far forward (full, the upper foreleg was pulled down across the chest and its armpit skin folded over on
|
|
32
|
-
// itself: a maroon patch, red in the holes view)
|
|
33
|
-
const PIG_FRONT_SPREAD = 0.15, PIG_FRONT_SIDE = 0.3;
|
|
34
|
-
// lying on the side: the spine's lateral bend (a little toward the up side; see flop)
|
|
35
|
-
const PIG_LIE_BEND = 0.08;
|
|
36
|
-
|
|
37
|
-
function B(e) {
|
|
38
|
-
if (!e._pig) {
|
|
39
|
-
e._pig = {
|
|
40
|
-
curl: 1, fear: 0, wagT: 3 + e.rand() * 5, wagAge: 9, wagAmp: 0,
|
|
41
|
-
gruntT: 2 + e.rand() * 5, grunt: null,
|
|
42
|
-
sniff: 0, sniffPh: 0, twitchPh: 0,
|
|
43
|
-
idleT: 6 + e.rand() * 8,
|
|
44
|
-
rootPh: 0, wag: 0, wagPh: 0, tail: null,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return e._pig;
|
|
48
|
-
}
|
|
49
|
-
const busy = (L) => L.oneshots.some((a) => !a.stopping && a.name !== 'grunt');
|
|
50
|
-
const find = (L, n) => L.oneshots.find((a) => a.name === n && a.w > 0);
|
|
51
|
-
// turning on the spot (0 .. 1): a pivot keeps the core's idle layer on (it looks at the speed only), and
|
|
52
|
-
// its look-around target and the sniff variant turned the head 6-12 deg away from the turn
|
|
53
|
-
const turning = (e) => {
|
|
54
|
-
const err = Math.abs(Math.atan2(Math.sin((e.wantHeading ?? e.heading) - e.heading), Math.cos((e.wantHeading ?? e.heading) - e.heading)));
|
|
55
|
-
return Math.max(smooth(0.1, 0.3, Math.abs(e.yawRate || 0)), smooth(0.15, 0.4, err));
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// ------------------------------------------------------------------------------------------------
|
|
59
|
-
function update(P, dt, L) {
|
|
60
|
-
const e = L.engine, cfg = e.cfg, b = B(e), u = 1 / cfg.unit, s = cfg.s;
|
|
61
|
-
const vn = e.speed / cfg.sq, g = e.gait;
|
|
62
|
-
const piglet = e.params.age === 'juvenile';
|
|
63
|
-
const side = e.params.tailSide ?? 1;
|
|
64
|
-
const dead = L.postures.some((p) => p.name === 'death' && p.w > 0);
|
|
65
|
-
const resting = L.postures.find((p) => (p.name === 'lie' || p.name === 'sleep' || p.name === 'wallow') && p.target > 0);
|
|
66
|
-
const eat = find(L, 'eat') || find(L, 'root') || find(L, 'drink');
|
|
67
|
-
|
|
68
|
-
// ---- tail: curled when active, uncurled (hanging) when resting, dead or afraid
|
|
69
|
-
b.fear = Math.max(0, b.fear - dt);
|
|
70
|
-
let want = 1;
|
|
71
|
-
if (resting) want = 0;
|
|
72
|
-
if (b.fear > 0) want = 0;
|
|
73
|
-
if (dead) want = 0.1;
|
|
74
|
-
if (piglet && !dead && b.fear <= 0) want = Math.max(want, 0.7);
|
|
75
|
-
b.curl += (want - b.curl) * (1 - Math.exp(-dt * (want > b.curl ? 1.5 : 3)));
|
|
76
|
-
const c = b.curl;
|
|
77
|
-
void side;
|
|
78
|
-
// wagging: bursts when feeding, excited (moving off), and now and then standing
|
|
79
|
-
b.wagT -= dt;
|
|
80
|
-
if (b.wagT <= 0) {
|
|
81
|
-
b.wagT = (eat ? 1.5 : 4) + e.rand() * (eat ? 3 : 8);
|
|
82
|
-
if (!resting && !dead) { b.wagAge = 0; b.wagAmp = (eat ? 0.8 : 0.5) + 0.3 * e.rand(); }
|
|
83
|
-
}
|
|
84
|
-
b.wagAge += dt;
|
|
85
|
-
const wa = Math.sin(Math.PI * clamp(b.wagAge / 2.4, 0, 1)) * b.wagAmp;
|
|
86
|
-
b.wag = wa * c; // (the curled tail wags in pose(); the hanging one through the engine)
|
|
87
|
-
b.wagPh += dt * TAU * 3.2;
|
|
88
|
-
if (wa > 0.001) P.tailWag = Math.max(P.tailWag, wa * (1 - c));
|
|
89
|
-
|
|
90
|
-
// ---- waddle: the heavy trunk rolls over the stance legs, the head nods at the walk
|
|
91
|
-
const walkW = smooth(0.1, 0.5, vn) * (1 - smooth(3.0, 4.0, vn)) * P.gaitW;
|
|
92
|
-
if (walkW > 0.001 && g) {
|
|
93
|
-
const trotK = smooth(1.3, 1.9, vn);
|
|
94
|
-
const ph = TAU * (e.phase - (g.off ? g.off[2] : 0));
|
|
95
|
-
const amp = lerp(0.045, 0.03, trotK) * (piglet ? 0.7 : 1);
|
|
96
|
-
P.roll += amp * Math.sin(ph) * walkW;
|
|
97
|
-
P.side += 0.006 * u * Math.sin(ph) * walkW;
|
|
98
|
-
const nod = 0.5 + 0.5 * Math.cos(2 * ph);
|
|
99
|
-
P.headRaise -= 0.018 * u * walkW * nod * (1 - trotK);
|
|
100
|
-
// piglets: a springy, bouncing trot
|
|
101
|
-
if (piglet) P.lift += 0.012 * u * Math.pow(Math.sin(2 * ph), 2) * walkW * trotK;
|
|
102
|
-
}
|
|
103
|
-
// ---- a piglet carries its head higher than a finisher (side1, threequarter3, front2: the snout 15-20 deg below
|
|
104
|
-
// level against 35 deg, the ears standing up over the poll), except while it eats, rests or lies dead
|
|
105
|
-
if (piglet) {
|
|
106
|
-
let busyW = dead ? 1 : eat ? eat.w : 0;
|
|
107
|
-
for (const p of L.postures) busyW = Math.max(busyW, p.w);
|
|
108
|
-
const k = 1 - clamp(busyW, 0, 1);
|
|
109
|
-
P.headPitch -= 0.26 * k;
|
|
110
|
-
P.headRaise += 0.025 * u * k;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ---- grunting: short bursts of 1-3 grunts (jaw pulses and a flank pulse)
|
|
114
|
-
const calm = !dead && !L.postures.some((p) => p.name === 'sleep' && p.w > 0.5);
|
|
115
|
-
b.gruntT -= dt * (eat ? 1.6 : 1);
|
|
116
|
-
if (b.gruntT <= 0 && calm && !L.oneshots.some((a) => a.name === 'grunt')) { b.gruntT = 3 + e.rand() * 9; L.play('grunt'); }
|
|
117
|
-
|
|
118
|
-
// ---- rooting: the disc pushed into the soil in forward-up nudges, the head swinging slowly
|
|
119
|
-
const root = find(L, 'eat') || find(L, 'root');
|
|
120
|
-
if (root) {
|
|
121
|
-
const w = root.w * root.w * (3 - 2 * root.w);
|
|
122
|
-
b.rootPh += dt * 1.6;
|
|
123
|
-
const c1 = b.rootPh % 1;
|
|
124
|
-
const push = smooth(0.0, 0.35, c1) * (1 - smooth(0.45, 0.75, c1));
|
|
125
|
-
const flick = smooth(0.4, 0.6, c1) * (1 - smooth(0.7, 0.95, c1));
|
|
126
|
-
const fw = e.forward(e.heading, tv());
|
|
127
|
-
P.headPos.addScaledVector(fw, 0.04 * s * push * w);
|
|
128
|
-
P.headPos.y += (-0.012 * push + 0.035 * flick) * s * w;
|
|
129
|
-
P.headPitch += (0.12 * push - 0.18 * flick) * w;
|
|
130
|
-
P.headYaw += 0.12 * Math.sin(b.rootPh * 0.37 * TAU) * w;
|
|
131
|
-
P.fwd += 0.015 * u * push * w;
|
|
132
|
-
mx(P, 'jaw', 0.03 + 0.05 * flick, w);
|
|
133
|
-
b.sniff = Math.max(b.sniff, w);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ---- a pivot: the head leads the turn (the engine's steer lead) without the idle look pulling it back
|
|
137
|
-
// to a point picked before the turn; a new point is picked after it
|
|
138
|
-
const turnK = e.input.follow ? 0 : turning(e);
|
|
139
|
-
if (turnK > 0.001 && !e.input.look && L.idle.w > 0.001 && P.look && P.look === L.idle.look) {
|
|
140
|
-
P.lookW *= 1 - turnK;
|
|
141
|
-
if (turnK > 0.5) { L.idle.hasLook = false; L.idle.lookT = Math.max(L.idle.lookT, 1.2); }
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ---- idle variants (not while pivoting)
|
|
145
|
-
const idle = L.idle.w > 0.9 && !L.postures.length && !busy(L) && turnK < 0.05;
|
|
146
|
-
if (idle) {
|
|
147
|
-
b.idleT -= dt;
|
|
148
|
-
if (b.idleT <= 0) {
|
|
149
|
-
b.idleT = 6 + e.rand() * 10;
|
|
150
|
-
if (piglet && e.rand() < 0.45) L.play('frolic');
|
|
151
|
-
else L.play('sniff');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// sniffing between: a quick disc twitch now and then, stronger when idle
|
|
155
|
-
b.sniff = Math.max(b.sniff * Math.exp(-dt * 1.5), idle ? 0.35 : 0.15);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ------------------------------------------------------------------------------------------------
|
|
159
|
-
// pose: the rostral disc wiggles (sniffing): small fast up-down and sideways twitches
|
|
160
|
-
function pose(e, dt) {
|
|
161
|
-
const b = B(e), P = e.P, cfg = e.cfg;
|
|
162
|
-
poseTail(e, b);
|
|
163
|
-
if (e.lod >= 2) return;
|
|
164
|
-
poseEars(e, b, dt);
|
|
165
|
-
const sn = e.bone.snout;
|
|
166
|
-
if (!sn) return;
|
|
167
|
-
const awake = 1 - P.eyelid;
|
|
168
|
-
b.twitchPh += dt * TAU * (2.5 + 3.5 * b.sniff);
|
|
169
|
-
const a = b.sniff * awake;
|
|
170
|
-
if (a < 1e-3) return;
|
|
171
|
-
const tw = Math.pow(Math.max(0, Math.sin(b.twitchPh)), 2) * a;
|
|
172
|
-
const lat = Math.sin(b.twitchPh * 0.43 + 1.3) * a;
|
|
173
|
-
const base = tv().setFromMatrixPosition(sn.matrixWorld);
|
|
174
|
-
_q.setFromRotationMatrix(sn.matrixWorld);
|
|
175
|
-
const ax = tv(1, 0, 0).applyQuaternion(_q), up = tv(0, 0, 1).applyQuaternion(_q);
|
|
176
|
-
const along = tv(0, 1, 0).applyQuaternion(_q);
|
|
177
|
-
base.addScaledVector(along, -0.003 * tw * cfg.s);
|
|
178
|
-
sn.matrixWorld.compose(base, tqa(ax, -0.12 * tw).multiply(tqa(up, 0.06 * lat)).multiply(_q), _s);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// the corkscrew tail: the engine has written a hanging spring chain (E); the curled tail is the rest
|
|
182
|
-
// helix carried rigidly by the root bone (C). Per joint, the relative rotation is slerped from the
|
|
183
|
-
// engine's toward the rest helix's by the curl amount, and the chain is rebuilt from the root; the
|
|
184
|
-
// curled tail wags about the root.
|
|
185
|
-
const _qa = new THREE.Quaternion(), _qb = new THREE.Quaternion(), _qc = new THREE.Quaternion(), _qp = new THREE.Quaternion();
|
|
186
|
-
const _p = new THREE.Vector3(), _d = new THREE.Vector3(), _up = new THREE.Vector3();
|
|
187
|
-
function poseTail(e, b) {
|
|
188
|
-
let T = b.tail;
|
|
189
|
-
if (!T) {
|
|
190
|
-
const bones = [];
|
|
191
|
-
for (let i = 0; ; i++) { const bn = e.bone['tail' + i]; if (!bn) break; bones.push(bn); }
|
|
192
|
-
const idx = bones.map((bn) => e.sk.bones.indexOf(bn));
|
|
193
|
-
const rest = idx.map((i) => new THREE.Quaternion().setFromRotationMatrix(e.sk.bind[i]));
|
|
194
|
-
const rel = rest.map((q, i) => (i ? rest[i - 1].clone().invert().multiply(q) : null));
|
|
195
|
-
const len = idx.map((i, k) => (k < idx.length - 1 ? new THREE.Vector3().setFromMatrixPosition(e.sk.bind[idx[k + 1]]).distanceTo(new THREE.Vector3().setFromMatrixPosition(e.sk.bind[i])) : 0));
|
|
196
|
-
// rigid curl (crowd tier, fully curled): bone_i = root * inv(rest_0) * rest_i
|
|
197
|
-
const inv0 = e.sk.bind[idx[0]].clone().invert();
|
|
198
|
-
const R = idx.map((i) => inv0.clone().multiply(e.sk.bind[i]));
|
|
199
|
-
T = b.tail = { bones, rel, len, R, q: bones.map(() => new THREE.Quaternion()), e: bones.map(() => new THREE.Quaternion()) };
|
|
200
|
-
}
|
|
201
|
-
const c = b.curl, n = T.bones.length;
|
|
202
|
-
if (c < 1e-3 && Math.abs(b.wag) < 1e-4) return;
|
|
203
|
-
if (e.lod >= 2 || (c > 0.995 && Math.abs(b.wag) < 1e-4)) {
|
|
204
|
-
if (c < 0.5) return;
|
|
205
|
-
const m0 = T.bones[0].matrixWorld;
|
|
206
|
-
for (let i = 1; i < n; i++) T.bones[i].matrixWorld.multiplyMatrices(m0, T.R[i]);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
for (let i = 0; i < n; i++) T.e[i].setFromRotationMatrix(T.bones[i].matrixWorld);
|
|
210
|
-
// root: the engine's, wagged about the pelvis' up axis
|
|
211
|
-
const q0 = T.q[0].copy(T.e[0]);
|
|
212
|
-
if (Math.abs(b.wag) > 1e-4) {
|
|
213
|
-
_up.set(0, 0, 1).applyQuaternion(T.e[0]); // (the root's dorsal axis)
|
|
214
|
-
q0.premultiply(_qp.setFromAxisAngle(_up.normalize(), 0.45 * b.wag * Math.sin(b.wagPh)));
|
|
215
|
-
_p.setFromMatrixPosition(T.bones[0].matrixWorld);
|
|
216
|
-
T.bones[0].matrixWorld.compose(_p, q0, _s);
|
|
217
|
-
}
|
|
218
|
-
_p.setFromMatrixPosition(T.bones[0].matrixWorld);
|
|
219
|
-
for (let i = 1; i < n; i++) {
|
|
220
|
-
_qa.copy(T.e[i - 1]).invert().multiply(T.e[i]); // engine relative rotation
|
|
221
|
-
_qb.copy(_qa).slerp(T.rel[i], c);
|
|
222
|
-
T.q[i].copy(T.q[i - 1]).multiply(_qb);
|
|
223
|
-
_d.set(0, T.len[i - 1], 0).applyQuaternion(T.q[i - 1]);
|
|
224
|
-
_p.add(_d);
|
|
225
|
-
T.bones[i].matrixWorld.compose(_p, T.q[i], _s);
|
|
226
|
-
}
|
|
227
|
-
void _qc;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// ears, after the engine's solve:
|
|
231
|
-
// - a head lying on its side (lie, sleep, wallow, death) folds the ground-side ear back and up into the jowl
|
|
232
|
-
// and the neck, where it is hidden, as a lying pig's lower ear is squashed under its head (Landrace photos;
|
|
233
|
-
// swung up out of the ground it stuck out along the ground as a rigid blade; laid level beside the
|
|
234
|
-
// neck it still showed as one); the upper ear falls onto the head: an erect or semi-lop leaf back over the
|
|
235
|
-
// neck, its hollow down, a lop leaf forward over the face and the eye (lr1-lr3). The target is a whole frame
|
|
236
|
-
// (the ear's direction and its leaf's hollow side, from the bind leaf, ears.js), so the leaf lies flat rather
|
|
237
|
-
// than edge-on;
|
|
238
|
-
// - then any pinna still reaching into the ground (rooting) is swung up about its base, just enough (a spring
|
|
239
|
-
// on the correction angle keeps it smooth).
|
|
240
|
-
const _eb = new THREE.Vector3(), _ed = new THREE.Vector3(), _el = new THREE.Vector3(), _ep = new THREE.Vector3(), _ea = new THREE.Vector3();
|
|
241
|
-
const _hx = new THREE.Vector3(), _hy = new THREE.Vector3() /* back along the neck, level */, _hz = new THREE.Vector3(), _dT = new THREE.Vector3(), _nT = new THREE.Vector3();
|
|
242
|
-
const _hv = new THREE.Vector3(), _dC = new THREE.Vector3(), _nC = new THREE.Vector3(), _w3 = new THREE.Vector3(), _mA = new THREE.Matrix4(), _mB = new THREE.Matrix4();
|
|
243
|
-
const _qt = new THREE.Quaternion(), _qi = new THREE.Quaternion(), _qr = new THREE.Quaternion();
|
|
244
|
-
// rotation taking the frame (d, n) onto (d2, n2) (n, n2 made orthogonal to d, d2)
|
|
245
|
-
function frameRot(d, n, d2, n2, out) {
|
|
246
|
-
_w3.copy(n).addScaledVector(d, -n.dot(d)).normalize();
|
|
247
|
-
_mA.makeBasis(d, _w3, _ea.crossVectors(d, _w3));
|
|
248
|
-
_w3.copy(n2).addScaledVector(d2, -n2.dot(d2)).normalize();
|
|
249
|
-
_mB.makeBasis(d2, _w3, _ea.crossVectors(d2, _w3));
|
|
250
|
-
return out.setFromRotationMatrix(_mB.multiply(_mA.transpose()));
|
|
251
|
-
}
|
|
252
|
-
function poseEars(e, b, dt) {
|
|
253
|
-
const cfg = e.cfg;
|
|
254
|
-
if (!b.ear) {
|
|
255
|
-
b.ear = [0, 1].map((k) => {
|
|
256
|
-
// (the leaf in the bind pose: the ear bone's direction and the hollow side at mid-length)
|
|
257
|
-
// (and its first third: a tucked ear is aimed by it, since a drooping leaf's chord runs well below its root)
|
|
258
|
-
// (the bind leaf as the mesh has it: the reference leaf through the individual's warps and size, as the pipeline
|
|
259
|
-
// warps the mesh and the joints; the head scale fades out along a long leaf and tilts its chord several degrees)
|
|
260
|
-
const S = k ? 'R' : 'L', P0 = e.params;
|
|
261
|
-
const W = composeWarps([...(P0.warps || []), ...(P0.size && P0.size !== 1 ? [{ type: 'scale', k: P0.size }] : [])]) || ((p) => p);
|
|
262
|
-
// (rig.js gives the left side; the rig mirrors it)
|
|
263
|
-
const bl = pigJoints(P0).earBaseL, rb = S === 'L' ? bl : [-bl[0], bl[1], bl[2]], wb = W(rb);
|
|
264
|
-
const off = (p) => { const q = W(p); return new THREE.Vector3(q[0] - wb[0], q[1] - wb[1], q[2] - wb[2]); };
|
|
265
|
-
const dirAt = (p, v) => { const a = W(p), q = W([p[0] + 0.01 * v[0], p[1] + 0.01 * v[1], p[2] + 0.01 * v[2]]); return new THREE.Vector3(q[0] - a[0], q[1] - a[1], q[2] - a[2]).normalize(); };
|
|
266
|
-
const sp = earSpine(rb, S, P0), q3 = sp.steps / 3 | 0, mid = sp.steps >> 1;
|
|
267
|
-
const leaf = earLeaf(rb, S, P0);
|
|
268
|
-
// (points on the leaf: the ground check; a drooping leaf's belly hangs 4-5 cm off the bone's chord)
|
|
269
|
-
const pts = [];
|
|
270
|
-
for (const u of [0.3, 0.55, 0.8, 1]) for (const a of [-0.85, 0, 0.85]) pts.push(off(leaf.mid(u, a).p));
|
|
271
|
-
return {
|
|
272
|
-
lift: 0, tuck: 0, relax: 0, len: e.J['earBase' + S].distanceTo(e.J['earTip' + S]), pts,
|
|
273
|
-
d: off(sp.tip).normalize(), h: dirAt(sp.pts[mid], sp.fr[mid].h),
|
|
274
|
-
d1: off(sp.pts[q3]).normalize(), h1: dirAt(sp.pts[q3 >> 1], sp.fr[q3 >> 1].h),
|
|
275
|
-
};
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
const qH = e.headPose.quaternion;
|
|
279
|
-
// (the head's lateral axis and its long axis toward the disc, HZ, in the world)
|
|
280
|
-
_hx.set(1, 0, 0).applyQuaternion(qH); _hz.set(HZ[0], HZ[1], HZ[2]).applyQuaternion(qH);
|
|
281
|
-
// back along the neck, level (the neck lies on the ground beside it)
|
|
282
|
-
_hy.set(-_hz.x, 0, -_hz.z);
|
|
283
|
-
if (_hy.lengthSq() < 1e-6) _hy.set(0, 0, -1);
|
|
284
|
-
_hy.normalize();
|
|
285
|
-
// toward the throat, level (the head's ventral side: -HY)
|
|
286
|
-
_hv.set(HY[0], HY[1], HY[2]).applyQuaternion(qH).multiplyScalar(-1); _hv.y = 0;
|
|
287
|
-
if (_hv.lengthSq() < 1e-6) _hv.set(0, 0, 0); else _hv.normalize();
|
|
288
|
-
const lop = e.params.ear === 'lop', relaxK = 0.85;
|
|
289
|
-
const ke = 1 - Math.exp(-dt * 5);
|
|
290
|
-
for (let k = 0; k < 2; k++) {
|
|
291
|
-
const name = k === 0 ? 'earL' : 'earR', bone = e.bone[name], E = b.ear[k], s = k === 0 ? 1 : -1;
|
|
292
|
-
if (!bone) continue;
|
|
293
|
-
// (how far this ear's side of the head faces the ground: the head on its side)
|
|
294
|
-
const side = s * _hx.y;
|
|
295
|
-
E.tuck += (smooth(0.35, 0.75, -side) - E.tuck) * ke;
|
|
296
|
-
E.relax += (relaxK * smooth(0.35, 0.75, side) - E.relax) * ke;
|
|
297
|
-
_eb.setFromMatrixPosition(bone.matrixWorld);
|
|
298
|
-
const w = Math.max(E.tuck, E.relax);
|
|
299
|
-
if (w > 1e-3 && e.bindQ?.[name]) {
|
|
300
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
301
|
-
// current leaf: the bind leaf carried by the bone's rotation from its bind orientation
|
|
302
|
-
_qr.copy(e.bindQ[name]).invert().premultiply(_q);
|
|
303
|
-
const tuck = E.tuck >= E.relax;
|
|
304
|
-
_dC.copy(tuck ? E.d1 : E.d).applyQuaternion(_qr); _nC.copy(tuck ? E.h1 : E.h).applyQuaternion(_qr);
|
|
305
|
-
if (tuck) {
|
|
306
|
-
// folded under: back along the neck, a little up and toward the throat, into the jowl and the neck (which
|
|
307
|
-
// lie on the ground over it), the hollow toward the throat: a lying neck is thickest from its back to the
|
|
308
|
-
// throat, and the drooping leaf curls that way (its hollow up, it curled out of the neck's upper side)
|
|
309
|
-
_dT.copy(_hy).addScaledVector(tv(0, 1, 0), 0.35).addScaledVector(_hv, 0.3).normalize();
|
|
310
|
-
_nT.copy(_hv);
|
|
311
|
-
} else if (lop) {
|
|
312
|
-
// a lop ear keeps lying along the head and falls across it onto the cheek and the eye, its hollow on them
|
|
313
|
-
// (gravity across the head's long axis)
|
|
314
|
-
_w3.set(0, -1, 0).addScaledVector(_hz, _hz.y);
|
|
315
|
-
_dT.copy(_dC).addScaledVector(_w3, 0.45).normalize();
|
|
316
|
-
_nT.set(0, -1, 0);
|
|
317
|
-
} else {
|
|
318
|
-
// fallen back over the neck and draped down its side, the hollow on it
|
|
319
|
-
_dT.copy(_hy).addScaledVector(tv(0, 1, 0), -0.45).normalize();
|
|
320
|
-
_nT.copy(_hv).multiplyScalar(0.5).addScaledVector(tv(0, 1, 0), -1).normalize();
|
|
321
|
-
}
|
|
322
|
-
frameRot(_dC, _nC, _dT, _nT, _qt);
|
|
323
|
-
// (the part w of that rotation, continuous in time: of q and -q the one nearer last frame's, then its
|
|
324
|
-
// axis-angle scaled; a shortest-arc slerp switched sides where the rotation passed 180 deg and the ear
|
|
325
|
-
// flipped through the ground in one frame)
|
|
326
|
-
if (E.qs ? _qt.dot(E.qs) < 0 : _qt.w < 0) _qt.set(-_qt.x, -_qt.y, -_qt.z, -_qt.w);
|
|
327
|
-
(E.qs || (E.qs = new THREE.Quaternion())).copy(_qt);
|
|
328
|
-
const th = 2 * Math.acos(clamp(_qt.w, -1, 1)), sn = Math.sqrt(Math.max(0, 1 - _qt.w * _qt.w));
|
|
329
|
-
if (sn > 1e-6) { _ea.set(_qt.x / sn, _qt.y / sn, _qt.z / sn); _qi.setFromAxisAngle(_ea, th * w); _q.premultiply(_qi); }
|
|
330
|
-
bone.matrixWorld.compose(_eb, _q, _s);
|
|
331
|
-
} else if (E.qs) E.qs = null;
|
|
332
|
-
// the ground: a pinna reaching into it is swung up about its base, just enough: the swing about the horizontal
|
|
333
|
-
// axis across the bone that lifts each point of the leaf above the floor (its height gain per radian is
|
|
334
|
-
// (axis x offset).y), the largest of them; fast to rise (the head falls fast in a collapse: a spring lagged and
|
|
335
|
-
// the leaf's belly went 29 mm into the ground), slow to let go
|
|
336
|
-
const near = _eb.y - e.terrainH(_eb.x, _eb.z) < E.len * 1.2 + 0.03 * cfg.s;
|
|
337
|
-
let need = 0;
|
|
338
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
339
|
-
_ed.set(0, 1, 0).applyQuaternion(_q);
|
|
340
|
-
_ea.crossVectors(_ed, tv(0, 1, 0));
|
|
341
|
-
const axOk = _ea.lengthSq() > 1e-8;
|
|
342
|
-
if (near && axOk && e.bindQ?.[name]) {
|
|
343
|
-
_ea.normalize();
|
|
344
|
-
_qr.copy(e.bindQ[name]).invert().premultiply(_q);
|
|
345
|
-
for (const pt of E.pts) {
|
|
346
|
-
_ep.copy(pt).applyQuaternion(_qr);
|
|
347
|
-
const floor = e.terrainH(_eb.x + _ep.x, _eb.z + _ep.z) + 0.012 * cfg.s;
|
|
348
|
-
const lack = floor - (_eb.y + _ep.y);
|
|
349
|
-
if (lack <= 0) continue;
|
|
350
|
-
const gain = _ea.z * _ep.x - _ea.x * _ep.z;
|
|
351
|
-
need = Math.max(need, gain > 0.02 * E.len ? lack / gain : 1.2);
|
|
352
|
-
}
|
|
353
|
-
need = Math.min(1.2, need * 1.1);
|
|
354
|
-
}
|
|
355
|
-
E.lift = need > E.lift ? Math.min(need, E.lift + 25 * dt) : E.lift + (need - E.lift) * (1 - Math.exp(-dt * 10));
|
|
356
|
-
if (E.lift < 1e-4 || !axOk) continue;
|
|
357
|
-
_q.premultiply(tqa(_ea, E.lift));
|
|
358
|
-
bone.matrixWorld.compose(_eb, _q, _s);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// ------------------------------------------------------------------------------------------------
|
|
363
|
-
// actions
|
|
364
|
-
|
|
365
|
-
// grunt: 1-3 short jaw pulses with a flank pulse; emits vocalize { kind: 'grunt' }
|
|
366
|
-
const grunt = {
|
|
367
|
-
kind: 'oneshot', fade: 0.08, overlay: true, // a vocalisation: it neither cuts nor is cut by a commanded one-shot (eat, root, attack...)
|
|
368
|
-
start(inst, L) { const b = B(L.engine); inst.n = 1 + Math.floor(L.engine.rand() * 3); inst.dur = 0.32 * inst.n + 0.1; b.grunt = inst; inst.said = 0; },
|
|
369
|
-
update(inst, dt, L) {
|
|
370
|
-
const k = Math.floor(inst.t / 0.32);
|
|
371
|
-
if (k >= inst.said && k < inst.n) { inst.said = k + 1; L.engine.emit('vocalize', { kind: 'grunt', position: L.engine.headPose.position.clone() }); }
|
|
372
|
-
if (inst.t >= inst.dur) { B(L.engine).grunt = null; return true; }
|
|
373
|
-
return false;
|
|
374
|
-
},
|
|
375
|
-
apply(P, w, inst) {
|
|
376
|
-
const x = (inst.t % 0.32) / 0.32, on = inst.t < 0.32 * inst.n ? 1 : 0;
|
|
377
|
-
const pulse = Math.sin(Math.PI * clamp(x / 0.6, 0, 1)) * on;
|
|
378
|
-
P.jaw = Math.max(P.jaw, 0.07 * pulse * w);
|
|
379
|
-
P.jawOmega = Math.max(P.jawOmega, 30);
|
|
380
|
-
P.breathAmp += 1.2 * pulse * w;
|
|
381
|
-
},
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
// sniff: head up, the disc twitching fast, a look around
|
|
385
|
-
const sniff = {
|
|
386
|
-
kind: 'oneshot', fade: 0.35,
|
|
387
|
-
start(inst, L) { inst.dur = 2.2 + L.engine.rand() * 1.5; inst.dir = L.engine.rand() < 0.5 ? -1 : 1; },
|
|
388
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
389
|
-
apply(P, w, inst, L) {
|
|
390
|
-
const u = 1 / L.engine.cfg.unit, t = inst.t;
|
|
391
|
-
const k = smooth(0, 0.5, t) * (1 - smooth(inst.dur - 0.5, inst.dur, t)) * w;
|
|
392
|
-
mx(P, 'headRaise', 0.06 * u, k); mx(P, 'headPitch', -0.3, k); mx(P, 'neckReach', 0.02 * u, k);
|
|
393
|
-
// (no look to the side while the pig turns on the spot)
|
|
394
|
-
inst.turnK = Math.max((inst.turnK ?? 0) * Math.exp(-L.engine.frameDt * 2), turning(L.engine));
|
|
395
|
-
P.headYaw += 0.25 * inst.dir * Math.sin(t * 1.3) * k * (1 - inst.turnK);
|
|
396
|
-
mx(P, 'lookW', 0.2, k);
|
|
397
|
-
B(L.engine).sniff = Math.max(B(L.engine).sniff, k);
|
|
398
|
-
},
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
// root: rooting in the ground (the built-in eat, looped; behaviour adds the nudges)
|
|
402
|
-
const root = {
|
|
403
|
-
...ONESHOTS.eat, kind: 'oneshot',
|
|
404
|
-
start(inst, L) { inst.tune = L.tuning.eat || {}; inst.dur = inst.opts.duration ?? Infinity; inst.fade = 0.8; },
|
|
405
|
-
update(inst, dt, L) { return inst.t >= inst.dur || L.engine.wantSpeed > 0.05 || !!L.engine.input.follow; },
|
|
406
|
-
apply(P, w, inst, L) { ONESHOTS.eat.apply(P, w, inst, L); B(L.engine).sniff = Math.max(B(L.engine).sniff, w); },
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
// lie: kneels on the carpi, drops the hindquarters, then flops onto its side (lateral), head flat,
|
|
410
|
-
// awake (eyes open, ears and look alive)
|
|
411
|
-
const flop = (P, w, inst, L, sleep) => {
|
|
412
|
-
POSTURES.sleep.apply(P, w, inst, L);
|
|
413
|
-
const c = smooth(1.0, 3.0, inst.t) * w;
|
|
414
|
-
// (the spine a little rounded toward the up side instead of the core's lateral curl: lying on its side, the
|
|
415
|
-
// curl sagged the middle toward the ground and the back read as a saddle between shoulder and ham;
|
|
416
|
-
// with the wider barrel the outline over shoulder, ribs and ham varies by 2 cm, was 6.5)
|
|
417
|
-
mx(P, 'bend', -inst.side * PIG_LIE_BEND, c);
|
|
418
|
-
// the broad head (jowls and cheek) rests on its side higher than the engine's slim skull
|
|
419
|
-
P.headPos.y += HEAD_REST * L.engine.cfg.s * c;
|
|
420
|
-
// (the chin out: the deep double chin under the jaw otherwise ploughs into the ground; while the
|
|
421
|
-
// forequarters go down the head is held up until it is laid on its side)
|
|
422
|
-
mx(P, 'headPitch', -0.1, c);
|
|
423
|
-
if (inst.target > 0) {
|
|
424
|
-
const hold = smooth(0.3, 1.0, inst.t) * (1 - smooth(1.9, 2.9, inst.t)) * w;
|
|
425
|
-
P.headRaise += 0.08 / L.engine.cfg.unit * hold; P.headPitch -= 0.3 * hold;
|
|
426
|
-
}
|
|
427
|
-
// the short legs stretched out from the body (the lower claws otherwise rest in the ground); the
|
|
428
|
-
// forelegs less (PIG_FRONT_*)
|
|
429
|
-
for (let i = 0; i < 4; i++) { P.legs[i].spread = Math.max(P.legs[i].spread, (i < 2 ? PIG_FRONT_SPREAD : 0.55) * c); }
|
|
430
|
-
for (let i = 0; i < 2; i++) P.legs[i].side = lerp(P.legs[i].side, PIG_FRONT_SIDE, c);
|
|
431
|
-
P.lift += 0.03 / L.engine.cfg.unit * c;
|
|
432
|
-
if (!sleep) {
|
|
433
|
-
// awake: eyes open, breathing normal, the head a little raised off the ground now and then
|
|
434
|
-
mx(P, 'eyelid', 0.1, c); mx(P, 'breathRate', 0.8, c); mx(P, 'earTwitch', 0.8, c); mx(P, 'tailIdle', 0.5, c);
|
|
435
|
-
mx(P, 'headLimp', 0.1, c);
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
const lie = { kind: 'posture', fadeIn: 1.6, fadeOut: 1.4, apply(P, w, inst, L) { flop(P, w, inst, L, false); } };
|
|
439
|
-
const sleep = { kind: 'posture', fadeIn: 1.6, fadeOut: 1.5, apply(P, w, inst, L) { flop(P, w, inst, L, true); } };
|
|
440
|
-
|
|
441
|
-
// wallow: lying on the side and rocking back and forth (rubbing the flank and back in the mud),
|
|
442
|
-
// the legs paddling in the air as it rolls toward its back
|
|
443
|
-
const wallow = {
|
|
444
|
-
kind: 'posture', fadeIn: 1.6, fadeOut: 1.5,
|
|
445
|
-
apply(P, w, inst, L) {
|
|
446
|
-
flop(P, w, inst, L, false);
|
|
447
|
-
// (the rocking starts as soon as the pig is down on its side, ~1.8 s)
|
|
448
|
-
const c = smooth(1.8, 3.0, inst.t) * w;
|
|
449
|
-
const r = 0.5 - 0.5 * Math.cos(TAU * 0.22 * Math.max(0, inst.t - 1.8));
|
|
450
|
-
P.roll += inst.side * 0.35 * r * c;
|
|
451
|
-
for (let i = 0; i < 4; i++) { P.legs[i].spread += 0.25 * r * c; P.legs[i].fold += 0.3 * Math.max(0, Math.sin(TAU * 0.44 * inst.t + i)) * r * c; }
|
|
452
|
-
P.headRoll += inst.side * 0.2 * r * c;
|
|
453
|
-
},
|
|
454
|
-
};
|
|
455
|
-
|
|
456
|
-
// attack. Sow: a shoulder shove with a sideways bite (the head swipes across, mouth open). Boar (or
|
|
457
|
-
// { style: 'slash' }): head low and turned, then an upward sideways swipe of the tusks.
|
|
458
|
-
const attack = {
|
|
459
|
-
kind: 'oneshot', fade: 0.15, needsStand: true,
|
|
460
|
-
start(inst, L) {
|
|
461
|
-
const e = L.engine;
|
|
462
|
-
inst.style = inst.opts.style || ((e.params.boar || 0) >= 0.5 ? 'slash' : 'shove');
|
|
463
|
-
inst.target = inst.opts.target ? inst.opts.target.clone() : null;
|
|
464
|
-
inst.dir = e.rand() < 0.5 ? -1 : 1;
|
|
465
|
-
if (inst.target) {
|
|
466
|
-
const lx = (inst.target.x - e.pos.x) * Math.cos(e.heading) - (inst.target.z - e.pos.z) * Math.sin(e.heading);
|
|
467
|
-
inst.dir = lx > 0 ? 1 : -1;
|
|
468
|
-
}
|
|
469
|
-
inst.dur = inst.style === 'slash' ? 1.25 : 1.1;
|
|
470
|
-
inst.hitAt = inst.style === 'slash' ? 0.62 : 0.55;
|
|
471
|
-
inst.hit = false;
|
|
472
|
-
B(e).fear = 0;
|
|
473
|
-
},
|
|
474
|
-
update(inst, dt, L) {
|
|
475
|
-
if (!inst.hit && inst.t >= inst.hitAt) {
|
|
476
|
-
inst.hit = true;
|
|
477
|
-
const e = L.engine;
|
|
478
|
-
const p = new THREE.Vector3().copy(e.cfg.mouthLocal).applyQuaternion(e.headPose.quaternion).add(e.headPose.position);
|
|
479
|
-
const dir = e.forward(e.heading, new THREE.Vector3()).addScaledVector(e.left(e.heading, new THREE.Vector3()), inst.dir * 0.6).normalize();
|
|
480
|
-
if (inst.style === 'slash') dir.y = 0.5;
|
|
481
|
-
e.emit('attackHit', { position: p, direction: dir.normalize(), style: inst.style === 'slash' ? 'tusk' : 'bite' });
|
|
482
|
-
}
|
|
483
|
-
return inst.t >= inst.dur;
|
|
484
|
-
},
|
|
485
|
-
apply(P, w, inst, L) {
|
|
486
|
-
const e = L.engine, u = 1 / e.cfg.unit, t = inst.t, d = inst.dir;
|
|
487
|
-
if (inst.target) { P.look = inst.target; mx(P, 'lookW', 1, w); }
|
|
488
|
-
mx(P, 'earFlat', 0.7, w * smooth(0, 0.2, t)); mx(P, 'earTwitch', 0, w);
|
|
489
|
-
const wind = smooth(0, 0.4, t) * (1 - smooth(inst.hitAt - 0.05, inst.hitAt + 0.1, t));
|
|
490
|
-
const strike = smooth(inst.hitAt - 0.18, inst.hitAt, t) * (1 - smooth(inst.hitAt + 0.15, inst.dur - 0.05, t));
|
|
491
|
-
if (inst.style === 'slash') {
|
|
492
|
-
// head low and turned away, then swung up and across: the tusk rips upward
|
|
493
|
-
mx(P, 'headRaise', -0.07 * u, wind * w); mx(P, 'headPitch', 0.45, wind * w); mx(P, 'headYaw', -d * 0.3, wind * w);
|
|
494
|
-
mx(P, 'dropF', 0.15, wind * w); mx(P, 'fwd', -0.03 * u, wind * w);
|
|
495
|
-
mx(P, 'headRaise', 0.06 * u, strike * w); mx(P, 'headPitch', -0.45, strike * w); mx(P, 'headYaw', d * 0.35, strike * w);
|
|
496
|
-
mx(P, 'headRoll', d * 0.35, strike * w); mx(P, 'fwd', 0.06 * u, strike * w); mx(P, 'jaw', 0.25, strike * w);
|
|
497
|
-
} else {
|
|
498
|
-
// shoulder shove: the body lunges forward and into the target, the head swipes across, bites
|
|
499
|
-
mx(P, 'fwd', -0.03 * u, wind * w); mx(P, 'headYaw', -d * 0.25, wind * w); mx(P, 'jaw', 0.3, wind * w);
|
|
500
|
-
mx(P, 'fwd', 0.08 * u, strike * w); mx(P, 'side', d * 0.04 * u, strike * w); mx(P, 'roll', -d * 0.08, strike * w);
|
|
501
|
-
mx(P, 'headYaw', d * 0.35, strike * w); mx(P, 'neckReach', 0.03 * u, strike * w);
|
|
502
|
-
mx(P, 'jaw', 0.4 * (1 - smooth(inst.hitAt - 0.03, inst.hitAt + 0.05, t)) + 0.05, strike * w); mx(P, 'jawOmega', 30, w);
|
|
503
|
-
}
|
|
504
|
-
mx(P, 'gaitW', 0.4, (wind + strike > 0 ? 1 : 0) * w);
|
|
505
|
-
},
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
// hit: the engine's stagger with a squeal (mouth wide), then the tail stays uncurled for a while
|
|
509
|
-
const hit = {
|
|
510
|
-
...ONESHOTS.hit, kind: 'oneshot',
|
|
511
|
-
start(inst, L) { ONESHOTS.hit.start(inst, L); B(L.engine).fear = 5; L.engine.emit('vocalize', { kind: 'squeal', position: L.engine.headPose.position.clone() }); },
|
|
512
|
-
apply(P, w, inst, L) {
|
|
513
|
-
ONESHOTS.hit.apply(P, w, inst, L);
|
|
514
|
-
const k = smooth(0.02, 0.12, inst.t) * (1 - smooth(0.45, 0.7, inst.t)) * w;
|
|
515
|
-
mx(P, 'jaw', 0.35, k); mx(P, 'jawOmega', 30, w); mx(P, 'headPitch', -0.2, k);
|
|
516
|
-
},
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
// frolic (piglets): two quick stiff-legged bounces in place with a head toss and a twist of the
|
|
520
|
-
// body (the legs stay planted: a crouch, then the body springs up on extended legs)
|
|
521
|
-
const frolic = {
|
|
522
|
-
kind: 'oneshot', fade: 0.1,
|
|
523
|
-
start(inst, L) { inst.dur = 1.0; inst.toss = L.engine.rand() < 0.5 ? -1 : 1; },
|
|
524
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
525
|
-
apply(P, w, inst) {
|
|
526
|
-
const t = inst.t, T = 0.42;
|
|
527
|
-
const ph = clamp(t / T, 0, 2.2);
|
|
528
|
-
const cyc = ph < 2 ? ph % 1 : 1;
|
|
529
|
-
// per bounce: crouch (0 - 0.35), spring up (0.35 - 0.6), settle (0.6 - 1)
|
|
530
|
-
const crouch = smooth(0, 0.3, cyc) * (1 - smooth(0.3, 0.5, cyc));
|
|
531
|
-
const up = smooth(0.32, 0.55, cyc) * (1 - smooth(0.6, 0.95, cyc));
|
|
532
|
-
const env = (1 - smooth(0.85, 1.0, t / inst.dur)) * w;
|
|
533
|
-
P.dropF += (0.14 * crouch - 0.08 * up) * env; P.dropH += (0.16 * crouch - 0.09 * up) * env;
|
|
534
|
-
P.pitch += 0.05 * (up - crouch) * env;
|
|
535
|
-
const k = Math.sin(Math.PI * clamp(t / inst.dur, 0, 1));
|
|
536
|
-
P.headYaw += inst.toss * 0.35 * Math.sin(TAU * t / (2 * T)) * k * w; P.headRoll += inst.toss * 0.2 * up * env;
|
|
537
|
-
P.roll -= inst.toss * 0.06 * up * env; P.headPitch -= 0.15 * up * env;
|
|
538
|
-
mx(P, 'earFlat', 0.2, up * env);
|
|
539
|
-
},
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
// jump: the built-in, with the forelegs tucking up more gradually after take-off (the short legs'
|
|
543
|
-
// elbows flipped when they folded within a few frames of leaving the ground)
|
|
544
|
-
const JUMP_TUCK = 0.4; // s (the built-in: 0.12)
|
|
545
|
-
const jump = {
|
|
546
|
-
...ONESHOTS.jump, kind: 'oneshot',
|
|
547
|
-
apply(P, w, inst, L) {
|
|
548
|
-
ONESHOTS.jump.apply(P, w, inst, L);
|
|
549
|
-
if (inst.phase === 'air') {
|
|
550
|
-
const x = smooth(0, JUMP_TUCK * L.engine.cfg.sk, inst.t - inst.tAir);
|
|
551
|
-
for (let i = 0; i < 2; i++) P.legs[i].tuck = Math.min(P.legs[i].tuck, x);
|
|
552
|
-
}
|
|
553
|
-
},
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
// death: the engine's collapse onto the side, the broad head resting on its cheek, the tail hanging
|
|
557
|
-
const death = {
|
|
558
|
-
...POSTURES.death, kind: 'posture',
|
|
559
|
-
apply(P, w, inst, L) {
|
|
560
|
-
POSTURES.death.apply(P, w, inst, L);
|
|
561
|
-
P.headPos.y += HEAD_REST * L.engine.cfg.s * smooth(0.35, 1.0, inst.t) * w;
|
|
562
|
-
// the hind legs only partly in the side-lying pose (legs laid out on the ground), slightly flexed:
|
|
563
|
-
// laid out full, the lower leg's foot target pressed the lower thigh's lateral bulge (the stifle)
|
|
564
|
-
// 8-11 mm into bumps on a slope (death-uneven, between the torso sections the rest solver checks)
|
|
565
|
-
const k = smooth(0.8, 1.6, inst.t) * w;
|
|
566
|
-
for (let i = 2; i < 4; i++) P.legs[i].side = lerp(P.legs[i].side, 0.3, k);
|
|
567
|
-
for (let i = 0; i < 2; i++) { P.legs[i].spread = lerp(P.legs[i].spread, PIG_FRONT_SPREAD, k); P.legs[i].side = lerp(P.legs[i].side, PIG_FRONT_SIDE, k); }
|
|
568
|
-
},
|
|
569
|
-
};
|
|
570
|
-
|
|
571
|
-
export const behaviour = {
|
|
572
|
-
update,
|
|
573
|
-
pose,
|
|
574
|
-
actions: { jump, lie, sleep, wallow, death, attack, hit, grunt, sniff, root, frolic },
|
|
575
|
-
};
|