@adatechnology/game-interactables-three 0.1.14 → 0.2.0
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 +33 -12
- package/dist/index.global.js +210 -65
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +68 -45
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { ActiveEmitter, ObjectSpec, Motion, World } from '@adatechnology/game-interactables';
|
|
2
|
+
import { LightBudget, SourceHandle } from '@adatechnology/game-render-three';
|
|
2
3
|
import * as ThreeNS from 'three';
|
|
3
4
|
import { PropsApi } from '@adatechnology/game-props3d';
|
|
5
|
+
import { catenary } from '@adatechnology/game-shapes-three';
|
|
6
|
+
export { catenary, createCord } from '@adatechnology/game-shapes-three';
|
|
7
|
+
|
|
8
|
+
/** The kinds of particle pool of the effects, as `effects.ts` draws them. */
|
|
9
|
+
type PoolKind = 'smoke' | 'steam' | 'fire' | 'spark' | 'water';
|
|
10
|
+
/** What `EffectSink.play` of `game-contracts` takes, as a structural type. */
|
|
11
|
+
interface ParticleEffectRequest {
|
|
12
|
+
readonly effect: string;
|
|
13
|
+
readonly point: [number, number, number];
|
|
14
|
+
readonly values: Readonly<Record<string, number>>;
|
|
15
|
+
}
|
|
16
|
+
/** The host's effects world as far as the particles need it (`EffectSink` of `game-contracts` fits). */
|
|
17
|
+
interface ParticleEffects {
|
|
18
|
+
play(request: ParticleEffectRequest): unknown;
|
|
19
|
+
}
|
|
4
20
|
|
|
5
21
|
/** The host's `THREE` namespace (or any object with the same classes). Always passed in, never imported at runtime. */
|
|
6
22
|
type ThreeLib = typeof ThreeNS;
|
|
@@ -48,6 +64,11 @@ interface EffectsOptions {
|
|
|
48
64
|
maxStreams?: number;
|
|
49
65
|
/** Most gas flame rings drawn at once (all rings share one draw call). Default 16. */
|
|
50
66
|
maxFlames?: number;
|
|
67
|
+
/**
|
|
68
|
+
* The host's effects world, read at each particle. With one, smoke, steam, fire and sparks go through it and its one budget (`maxParticles` then only caps water);
|
|
69
|
+
* without one every kind is drawn here with its own cap (deprecated, removed in the next major).
|
|
70
|
+
*/
|
|
71
|
+
effects?: () => ParticleEffects | undefined;
|
|
51
72
|
}
|
|
52
73
|
/** What the effects read from a camera. */
|
|
53
74
|
interface PerspectiveLike {
|
|
@@ -60,7 +81,7 @@ interface EffectsStats {
|
|
|
60
81
|
capacity: number;
|
|
61
82
|
byKind: Record<PoolKind, number>;
|
|
62
83
|
}
|
|
63
|
-
|
|
84
|
+
|
|
64
85
|
interface Effects {
|
|
65
86
|
/**
|
|
66
87
|
* Spawns for the active emitters and advances every particle by `dt` seconds, sizing the sprites for the camera given to
|
|
@@ -91,15 +112,6 @@ declare function createEffects(THREE: ThreeLib, options: EffectsOptions): Effect
|
|
|
91
112
|
/** @deprecated Pass `{ scene, camera, ... }` as the one options argument. */
|
|
92
113
|
declare function createEffects(THREE: ThreeLib, scene: ThreeNS.Object3D, options?: Partial<EffectsOptions>): Effects;
|
|
93
114
|
|
|
94
|
-
/**
|
|
95
|
-
* Points of a hanging cord between `a` and `b` (n points including both ends, n >= 2). The deepest point sits `sag` meters below
|
|
96
|
-
* the straight line between the ends, on a real catenary (y = a cosh(x/a)); when the ends differ in height the curve is
|
|
97
|
-
* measured against the straight line between them.
|
|
98
|
-
*/
|
|
99
|
-
declare function catenary(a: Vec3, b: Vec3, sag: number, n?: number): Vec3[];
|
|
100
|
-
/** A thin tube through `points` (Catmull-Rom smoothed) for wires, cords and conduits. */
|
|
101
|
-
declare function createCord(THREE: ThreeLib, points: readonly Vec3[], radius: number, material: ThreeNS.Material, radialSegments?: number): ThreeNS.Mesh;
|
|
102
|
-
|
|
103
115
|
type MaterialMap = Partial<Record<MaterialKey, ThreeNS.Material>>;
|
|
104
116
|
interface MeshApiOptions {
|
|
105
117
|
/** Materials per key. Missing keys get a default (vertex-colored) material. */
|
|
@@ -123,14 +135,21 @@ interface MeshApiOptions {
|
|
|
123
135
|
* clothes) keep what you return, including its `onBeforeCompile`, `customProgramCacheKey`, `defines` and `userData`.
|
|
124
136
|
*/
|
|
125
137
|
materialFor?: (key: MaterialKey, partId: string | null) => ThreeNS.Material | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* The host's light budget: each `api.light` becomes a source of it (it competes for a slot by distance, and following its bulb) instead of a `PointLight` of its own, so lamps coming and going
|
|
140
|
+
* never change the lit materials' program key. Without it the lamps are real lights (deprecated, removed in the next major).
|
|
141
|
+
*/
|
|
142
|
+
lights?: LightBudget;
|
|
126
143
|
}
|
|
127
144
|
interface MeshResult {
|
|
128
145
|
/** Root group: static meshes (one per material) plus one child group per part (merged parts share one group, see `mergeParts`). */
|
|
129
146
|
group: ThreeNS.Group;
|
|
130
147
|
/** Part groups by id. Origin at the pivot, rotated by the part's `ry`; `userData.rest` holds the rest pose. A merged part maps to the shared group (`userData.merged`). */
|
|
131
148
|
parts: Record<string, ThreeNS.Group>;
|
|
132
|
-
/** Real lights requested by the builders (already children of their group). */
|
|
149
|
+
/** Real lights requested by the builders (already children of their group). Empty with `MeshApiOptions.lights`. */
|
|
133
150
|
lights: ThreeNS.Light[];
|
|
151
|
+
/** With `MeshApiOptions.lights`: the lamps as sources of the budget (`remove()` one when its lamp breaks or the object goes). Empty without it. */
|
|
152
|
+
sources: SourceHandle[];
|
|
134
153
|
}
|
|
135
154
|
interface FinishOptions {
|
|
136
155
|
/** Same as `MeshApiOptions.materialFor`; wins over it for this call. */
|
|
@@ -337,6 +356,8 @@ interface ThreeAdapterOptions {
|
|
|
337
356
|
/** `Reflector` and env map for `createMirrors`. */
|
|
338
357
|
Reflector?: MirrorOptions['Reflector'];
|
|
339
358
|
envMap?: MirrorOptions['envMap'];
|
|
359
|
+
/** The host's light budget: the lamps of every mesh api this adapter makes become sources of it (see `MeshApiOptions.lights`). */
|
|
360
|
+
lights?: LightBudget;
|
|
340
361
|
}
|
|
341
362
|
/** The package functions with `THREE` and the common options already bound. */
|
|
342
363
|
interface ThreeAdapter {
|
|
@@ -395,4 +416,4 @@ type MergedGroup = ThreeNS.Group & {
|
|
|
395
416
|
*/
|
|
396
417
|
declare function mergeParts(THREE: ThreeLib, root: ThreeNS.Group, parts: Record<string, ThreeNS.Group>, spec: ObjectSpec, options?: MergeOptions): void;
|
|
397
418
|
|
|
398
|
-
export { type CanvasFactory, type Effects, type EffectsOptions, type EffectsStats, type FinishOptions, type HouseholdApi, MATERIAL_KEYS, type MaterialKey, type MaterialMap, type MergeOptions, type MergedGroup, type MeshApi, type MeshApiOptions, type MeshResult, type MirrorCandidate, type MirrorOptions, type Mirrors, type PerspectiveLike, type PoolKind, type Pose, type PoseBatch, type Quality, type ReflectorConstructor, type Screen, type ScreenOptions, type SwayBatch, type SwayHandle, type SwayOptions, type SwayUniforms, type SyncOptions, type ThreeAdapter, type ThreeAdapterOptions, type ThreeLib, type Vec3, applyPose, attachSway,
|
|
419
|
+
export { type CanvasFactory, type Effects, type EffectsOptions, type EffectsStats, type FinishOptions, type HouseholdApi, MATERIAL_KEYS, type MaterialKey, type MaterialMap, type MergeOptions, type MergedGroup, type MeshApi, type MeshApiOptions, type MeshResult, type MirrorCandidate, type MirrorOptions, type Mirrors, type PerspectiveLike, type PoolKind, type Pose, type PoseBatch, type Quality, type ReflectorConstructor, type Screen, type ScreenOptions, type SwayBatch, type SwayHandle, type SwayOptions, type SwayUniforms, type SyncOptions, type ThreeAdapter, type ThreeAdapterOptions, type ThreeLib, type Vec3, applyPose, attachSway, createDefaultMaterials, createEffects, createMeshApi, createMirrors, createScreen, createThreeAdapter, mergeParts, patchSwayShader, poseOf, rememberRest, swayMaterial, syncObject };
|
package/dist/index.global.js
CHANGED
|
@@ -40,6 +40,117 @@ var GameInteractablesThree = (() => {
|
|
|
40
40
|
syncObject: () => syncObject
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// ../game-contracts/dist/index.js
|
|
44
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
45
|
+
var DEFERRED_QUEUE_ID = {
|
|
46
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
47
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
48
|
+
AUDIO_VOICES: "audio.voices",
|
|
49
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
50
|
+
};
|
|
51
|
+
var DEFERRED_PRIORITY = {
|
|
52
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
53
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
54
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
55
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
56
|
+
};
|
|
57
|
+
var WARNED_KEY = /* @__PURE__ */ Symbol.for("@adatechnology/game-contracts.warned");
|
|
58
|
+
var warnedKeys = () => {
|
|
59
|
+
const holder = globalThis;
|
|
60
|
+
return holder[WARNED_KEY] ?? (holder[WARNED_KEY] = /* @__PURE__ */ new Set());
|
|
61
|
+
};
|
|
62
|
+
var isProduction = () => {
|
|
63
|
+
try {
|
|
64
|
+
return process.env.NODE_ENV === "production";
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var isQuiet = () => globalThis.__GAME_KIT_QUIET__ === true;
|
|
70
|
+
var warnOnce = (key, message) => {
|
|
71
|
+
if (isQuiet() || isProduction()) return;
|
|
72
|
+
const seen = warnedKeys();
|
|
73
|
+
if (seen.has(key)) return;
|
|
74
|
+
seen.add(key);
|
|
75
|
+
console.warn(`[game-kit] ${message}`);
|
|
76
|
+
};
|
|
77
|
+
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
78
|
+
function markKitOrigin(object2, origin) {
|
|
79
|
+
const node = object2;
|
|
80
|
+
node.userData = node.userData ?? {};
|
|
81
|
+
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
82
|
+
return object2;
|
|
83
|
+
}
|
|
84
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
85
|
+
var GAIT_IDS = ["walk", "run"];
|
|
86
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
87
|
+
var BODY_SOUND_IDS = [
|
|
88
|
+
"jump",
|
|
89
|
+
"cloth_rustle",
|
|
90
|
+
"body_fall",
|
|
91
|
+
"fall_damage",
|
|
92
|
+
"player_hurt",
|
|
93
|
+
"player_breath_run",
|
|
94
|
+
"player_death",
|
|
95
|
+
"bite",
|
|
96
|
+
"grab",
|
|
97
|
+
"punch_swing",
|
|
98
|
+
"punch_hit_body",
|
|
99
|
+
"punch_hit_face",
|
|
100
|
+
"punch_hit_object",
|
|
101
|
+
"kick_swing",
|
|
102
|
+
"kick_hit",
|
|
103
|
+
"kick_hit_object",
|
|
104
|
+
"shove_two_hands",
|
|
105
|
+
"knife_swing",
|
|
106
|
+
"knife_stab",
|
|
107
|
+
"knife_slash",
|
|
108
|
+
"knife_hit_object",
|
|
109
|
+
"blunt_swing",
|
|
110
|
+
"blunt_hit",
|
|
111
|
+
"blunt_hit_object",
|
|
112
|
+
"axe_swing",
|
|
113
|
+
"axe_chop",
|
|
114
|
+
"axe_hit_object"
|
|
115
|
+
];
|
|
116
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
117
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
118
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing) => `land_${surface}_${landing}`));
|
|
119
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
120
|
+
|
|
121
|
+
// src/routed-particles.ts
|
|
122
|
+
var channel = (value) => Math.round(Math.min(1, Math.max(0, value)) * 255);
|
|
123
|
+
var rgb = (red, green, blue) => channel(red) << 16 | channel(green) << 8 | channel(blue);
|
|
124
|
+
var EFFECT_OF = { smoke: "particle_puff", steam: "particle_puff", fire: "particle_glow", spark: "particle_streak" };
|
|
125
|
+
var isRoutedKind = (kind) => EFFECT_OF[kind] !== void 0;
|
|
126
|
+
function routedParticleRequest(particle) {
|
|
127
|
+
const { kind, flag, tint } = particle;
|
|
128
|
+
const look = lookOf(kind, flag, tint);
|
|
129
|
+
return {
|
|
130
|
+
effect: EFFECT_OF[kind],
|
|
131
|
+
point: particle.position,
|
|
132
|
+
values: {
|
|
133
|
+
vx: particle.velocity[0],
|
|
134
|
+
vy: particle.velocity[1],
|
|
135
|
+
vz: particle.velocity[2],
|
|
136
|
+
life: particle.life,
|
|
137
|
+
size: particle.startSize,
|
|
138
|
+
grow: particle.endSize / particle.startSize,
|
|
139
|
+
color: look.color,
|
|
140
|
+
alpha: look.alpha,
|
|
141
|
+
gravity: 0,
|
|
142
|
+
drag: 0
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function lookOf(kind, flag, tint) {
|
|
147
|
+
if (kind === "smoke") return { color: rgb(tint, tint, tint), alpha: 0.55 };
|
|
148
|
+
if (kind === "steam") return { color: rgb(tint, tint, tint), alpha: 0.4 };
|
|
149
|
+
if (kind === "spark") return { color: rgb(1, 0.75, 0.3), alpha: 1 };
|
|
150
|
+
if (flag) return { color: rgb(0.25 + 0.15 * tint, 0.5 + 0.2 * tint, 1), alpha: 0.95 };
|
|
151
|
+
return { color: rgb(1, Math.max(0.15, 0.85 - tint * 0.1), 0.25), alpha: 0.8 };
|
|
152
|
+
}
|
|
153
|
+
|
|
43
154
|
// src/effects.ts
|
|
44
155
|
var POOLS = ["smoke", "steam", "fire", "water", "spark"];
|
|
45
156
|
var WEIGHT = { smoke: 0.27, steam: 0.15, fire: 0.2, water: 0.28, spark: 0.1 };
|
|
@@ -214,6 +325,12 @@ void main() {
|
|
|
214
325
|
let stamp = 0;
|
|
215
326
|
let clock = 0;
|
|
216
327
|
const spawn = (p, x, y, z, vx, vy, vz, life, s0, s1, tint, flag = 0, ground = -1e9) => {
|
|
328
|
+
const sink = isRoutedKind(p.kind) ? options.effects?.() : void 0;
|
|
329
|
+
if (sink) {
|
|
330
|
+
sink.play(routedParticleRequest({ kind: p.kind, flag, position: [x, y, z], velocity: [vx, vy, vz], life, startSize: s0, endSize: s1, tint }));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (isRoutedKind(p.kind)) warnOnce("game-interactables-three.own-particles", "game-interactables-three drew its smoke, steam, fire and sparks with pools of its own because the host lent no effects world (options.effects); pass the host effects so the particles share one budget");
|
|
217
334
|
if (p.count >= p.cap) return;
|
|
218
335
|
const i = p.count++;
|
|
219
336
|
p.pos[i * 3] = x;
|
|
@@ -704,51 +821,7 @@ void main() {
|
|
|
704
821
|
};
|
|
705
822
|
}
|
|
706
823
|
|
|
707
|
-
//
|
|
708
|
-
function catenary(a, b, sag, n = 12) {
|
|
709
|
-
const count = Math.max(2, Math.floor(n));
|
|
710
|
-
const span = Math.hypot(b[0] - a[0], b[2] - a[2]) || Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
711
|
-
const depth = Math.max(0, sag);
|
|
712
|
-
const out = [];
|
|
713
|
-
let shape = () => 0;
|
|
714
|
-
if (depth > 1e-6 && span > 1e-6) {
|
|
715
|
-
let lo = 1e-4;
|
|
716
|
-
let hi = span * 1e3;
|
|
717
|
-
for (let i = 0; i < 80; i++) {
|
|
718
|
-
const c2 = (lo + hi) / 2;
|
|
719
|
-
const d = c2 * (Math.cosh(span / (2 * c2)) - 1);
|
|
720
|
-
if (d > depth) lo = c2;
|
|
721
|
-
else hi = c2;
|
|
722
|
-
}
|
|
723
|
-
const c = (lo + hi) / 2;
|
|
724
|
-
shape = (s) => c * (Math.cosh((s - 0.5) * span / c) - Math.cosh(span / (2 * c)));
|
|
725
|
-
}
|
|
726
|
-
for (let i = 0; i < count; i++) {
|
|
727
|
-
const s = i / (count - 1);
|
|
728
|
-
out.push([a[0] + (b[0] - a[0]) * s, a[1] + (b[1] - a[1]) * s + shape(s), a[2] + (b[2] - a[2]) * s]);
|
|
729
|
-
}
|
|
730
|
-
return out;
|
|
731
|
-
}
|
|
732
|
-
function createCord(THREE, points, radius, material, radialSegments = 5) {
|
|
733
|
-
if (points.length < 2) throw new Error("createCord needs at least two points");
|
|
734
|
-
const curve = new THREE.CatmullRomCurve3(points.map((p) => new THREE.Vector3(p[0], p[1], p[2])), false, "centripetal");
|
|
735
|
-
const segments = Math.max(4, (points.length - 1) * 4);
|
|
736
|
-
const mesh2 = new THREE.Mesh(new THREE.TubeGeometry(curve, segments, radius, radialSegments, false), material);
|
|
737
|
-
mesh2.name = "cord";
|
|
738
|
-
mesh2.castShadow = true;
|
|
739
|
-
return mesh2;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
// ../game-contracts/dist/index.js
|
|
743
|
-
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
744
|
-
function markKitOrigin(object2, origin) {
|
|
745
|
-
const node = object2;
|
|
746
|
-
node.userData = node.userData ?? {};
|
|
747
|
-
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
748
|
-
return object2;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// ../game-shapes/dist/chunk-R4RY23RH.js
|
|
824
|
+
// ../game-shapes/dist/chunk-IFXQIDSA.js
|
|
752
825
|
var __defProp2 = Object.defineProperty;
|
|
753
826
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
754
827
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -2230,8 +2303,20 @@ void main() {
|
|
|
2230
2303
|
};
|
|
2231
2304
|
}
|
|
2232
2305
|
var streamFor = (seed, generator, path) => mulberry32(parseInt(hash64(`${String(seed)}\0${generator}\0${path}`).slice(0, 8), 16));
|
|
2233
|
-
var
|
|
2234
|
-
var
|
|
2306
|
+
var GENERATOR_NAME = /^[a-zA-Z][\w.:-]*$/;
|
|
2307
|
+
var generatorsOver = (generators) => ({
|
|
2308
|
+
register(name, generator) {
|
|
2309
|
+
if (!GENERATOR_NAME.test(name)) throw new Error(`game-shapes: generator name "${name}" must start with a letter and use letters, digits, ".", ":", "-" or "_"`);
|
|
2310
|
+
generators.set(name, generator);
|
|
2311
|
+
},
|
|
2312
|
+
unregister: (name) => generators.delete(name),
|
|
2313
|
+
get: (name) => generators.get(name),
|
|
2314
|
+
list: () => [...generators.keys()].sort(),
|
|
2315
|
+
record: () => Object.fromEntries(generators)
|
|
2316
|
+
});
|
|
2317
|
+
var defaultGenerators;
|
|
2318
|
+
var defaultShapeGenerators = () => defaultGenerators ?? (defaultGenerators = generatorsOver(/* @__PURE__ */ new Map()));
|
|
2319
|
+
var getGenerator = (name) => defaultShapeGenerators().get(name);
|
|
2235
2320
|
var num = (v) => typeof v === "number" && Number.isFinite(v) ? null : "expected a finite number";
|
|
2236
2321
|
var bool = (v) => typeof v === "boolean" ? null : "expected a boolean";
|
|
2237
2322
|
var str = (v) => typeof v === "string" ? null : "expected a string";
|
|
@@ -2457,7 +2542,7 @@ void main() {
|
|
|
2457
2542
|
__publicField(this, "vertices", 0);
|
|
2458
2543
|
}
|
|
2459
2544
|
};
|
|
2460
|
-
function bake(acc, t, world,
|
|
2545
|
+
function bake(acc, t, world, rgb2, u, indexed) {
|
|
2461
2546
|
const e = world;
|
|
2462
2547
|
const nm = normalMatrix(world);
|
|
2463
2548
|
const affine = isAffine(world);
|
|
@@ -2468,7 +2553,7 @@ void main() {
|
|
|
2468
2553
|
acc.positions.reserve(emitted * 3);
|
|
2469
2554
|
acc.normals.reserve(emitted * 3);
|
|
2470
2555
|
acc.uvs.reserve(emitted * 2);
|
|
2471
|
-
if (
|
|
2556
|
+
if (rgb2) acc.colors.reserve(emitted * 3);
|
|
2472
2557
|
const P = acc.positions.array;
|
|
2473
2558
|
const N = acc.normals.array;
|
|
2474
2559
|
const U = acc.uvs.array;
|
|
@@ -2508,10 +2593,10 @@ void main() {
|
|
|
2508
2593
|
N[ni++] = vz * s;
|
|
2509
2594
|
U[ui++] = u.u0 + tu[i * 2] * du;
|
|
2510
2595
|
U[ui++] = u.v0 + tu[i * 2 + 1] * dv;
|
|
2511
|
-
if (
|
|
2512
|
-
C[ci++] =
|
|
2513
|
-
C[ci++] =
|
|
2514
|
-
C[ci++] =
|
|
2596
|
+
if (rgb2) {
|
|
2597
|
+
C[ci++] = rgb2[0];
|
|
2598
|
+
C[ci++] = rgb2[1];
|
|
2599
|
+
C[ci++] = rgb2[2];
|
|
2515
2600
|
}
|
|
2516
2601
|
}
|
|
2517
2602
|
acc.positions.length = pi;
|
|
@@ -2567,7 +2652,7 @@ void main() {
|
|
|
2567
2652
|
return r * Math.max(sx, sy, sz);
|
|
2568
2653
|
};
|
|
2569
2654
|
function expandCustom(node, settings, detail, path) {
|
|
2570
|
-
const generator = settings.generators?.[node.generator] ?? getGenerator(node.generator);
|
|
2655
|
+
const generator = settings.generators?.[node.generator] ?? (settings.isolatedGenerators ? void 0 : getGenerator(node.generator));
|
|
2571
2656
|
if (!generator) throw new Error(`game-shapes: no generator "${node.generator}" (register it with registerGenerator, in the worker too) at ${path}`);
|
|
2572
2657
|
const generated = generator(node.params, { random: streamFor(settings.seed, node.generator, path), seed: settings.seed, detail, path });
|
|
2573
2658
|
const { kind: _kind, generator: _generator, params: _params, ...common } = node;
|
|
@@ -2749,9 +2834,9 @@ void main() {
|
|
|
2749
2834
|
for (const group of autoGroups.values()) {
|
|
2750
2835
|
const template = buildPrimitive(group.node, level);
|
|
2751
2836
|
const n = group.matrices.length / 16;
|
|
2752
|
-
const
|
|
2837
|
+
const rgb2 = colorChannels(group.color, space ?? "srgb");
|
|
2753
2838
|
const colors = new Float32Array(n * 3);
|
|
2754
|
-
for (let i = 0; i < n; i++) colors.set(
|
|
2839
|
+
for (let i = 0; i < n; i++) colors.set(rgb2, i * 3);
|
|
2755
2840
|
instanced.push({
|
|
2756
2841
|
material: group.material,
|
|
2757
2842
|
part: null,
|
|
@@ -2775,6 +2860,7 @@ void main() {
|
|
|
2775
2860
|
...options.materialAlias ? { alias: options.materialAlias } : {},
|
|
2776
2861
|
seed: options.seed ?? 0,
|
|
2777
2862
|
...options.generators ? { generators: options.generators } : {},
|
|
2863
|
+
...options.isolatedGenerators ? { isolatedGenerators: true } : {},
|
|
2778
2864
|
...options.instancing ? { autoMin: Math.max(2, options.instancing.minCount) } : {}
|
|
2779
2865
|
};
|
|
2780
2866
|
const specs = [{ distance: 0, detail: 1, index: 0 }, ...(schema.lod ?? []).map((rule, index) => ({ ...rule, index: index + 1 }))];
|
|
@@ -2807,6 +2893,56 @@ void main() {
|
|
|
2807
2893
|
};
|
|
2808
2894
|
}
|
|
2809
2895
|
|
|
2896
|
+
// ../game-shapes-three/dist/index.js
|
|
2897
|
+
function catenary(a, b, sag, n = 12) {
|
|
2898
|
+
const count = Math.max(2, Math.floor(n));
|
|
2899
|
+
const span = Math.hypot(b[0] - a[0], b[2] - a[2]) || Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
2900
|
+
const depth = Math.max(0, sag);
|
|
2901
|
+
const out = [];
|
|
2902
|
+
let shape = () => 0;
|
|
2903
|
+
if (depth > 1e-6 && span > 1e-6) {
|
|
2904
|
+
let lo = 1e-4;
|
|
2905
|
+
let hi = span * 1e3;
|
|
2906
|
+
for (let i = 0; i < 80; i++) {
|
|
2907
|
+
const c2 = (lo + hi) / 2;
|
|
2908
|
+
const d = c2 * (Math.cosh(span / (2 * c2)) - 1);
|
|
2909
|
+
if (d > depth) lo = c2;
|
|
2910
|
+
else hi = c2;
|
|
2911
|
+
}
|
|
2912
|
+
const c = (lo + hi) / 2;
|
|
2913
|
+
shape = (s) => c * (Math.cosh((s - 0.5) * span / c) - Math.cosh(span / (2 * c)));
|
|
2914
|
+
}
|
|
2915
|
+
for (let i = 0; i < count; i++) {
|
|
2916
|
+
const s = i / (count - 1);
|
|
2917
|
+
out.push([a[0] + (b[0] - a[0]) * s, a[1] + (b[1] - a[1]) * s + shape(s), a[2] + (b[2] - a[2]) * s]);
|
|
2918
|
+
}
|
|
2919
|
+
return out;
|
|
2920
|
+
}
|
|
2921
|
+
function createCord(THREE, points, radius, material, radialSegments = 5) {
|
|
2922
|
+
if (points.length < 2) throw new Error("createCord needs at least two points");
|
|
2923
|
+
const curve = new THREE.CatmullRomCurve3(points.map((p) => new THREE.Vector3(p[0], p[1], p[2])), false, "centripetal");
|
|
2924
|
+
const segments = Math.max(4, (points.length - 1) * 4);
|
|
2925
|
+
const mesh2 = new THREE.Mesh(new THREE.TubeGeometry(curve, segments, radius, radialSegments, false), material);
|
|
2926
|
+
mesh2.name = "cord";
|
|
2927
|
+
mesh2.castShadow = true;
|
|
2928
|
+
return mesh2;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
// ../game-render-three/dist/index.js
|
|
2932
|
+
var DEFAULT_ANGLE = Math.PI / 3;
|
|
2933
|
+
var LIGHT_PRIORITY = {
|
|
2934
|
+
blast: 900,
|
|
2935
|
+
rocket: 800,
|
|
2936
|
+
muzzle: 750,
|
|
2937
|
+
fire: 600,
|
|
2938
|
+
flare: 500,
|
|
2939
|
+
headlight: 400,
|
|
2940
|
+
weaponLight: 400,
|
|
2941
|
+
lamp: 200,
|
|
2942
|
+
street: 150
|
|
2943
|
+
};
|
|
2944
|
+
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
2945
|
+
|
|
2810
2946
|
// ../game-props3d/dist/index.js
|
|
2811
2947
|
var T = (id, interior, w, d, h, y, solid, group) => ({ id, interior, w, d, h, y, solid, group });
|
|
2812
2948
|
var TYPE_DEFS = [
|
|
@@ -3390,6 +3526,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3390
3526
|
if (first !== k) materialAlias[k] = first;
|
|
3391
3527
|
}
|
|
3392
3528
|
const lightsOut = [];
|
|
3529
|
+
const sourcesOut = [];
|
|
3393
3530
|
const build = (batches, points, id, into, materialFor) => {
|
|
3394
3531
|
for (const batch of batches) {
|
|
3395
3532
|
const g = new THREE.BufferGeometry();
|
|
@@ -3411,6 +3548,14 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3411
3548
|
}
|
|
3412
3549
|
for (const point of points) {
|
|
3413
3550
|
const l = point.data;
|
|
3551
|
+
if (options.lights) {
|
|
3552
|
+
const bulb = new THREE.Object3D();
|
|
3553
|
+
bulb.name = "lamp";
|
|
3554
|
+
bulb.position.set(point.position[0], point.position[1], point.position[2]);
|
|
3555
|
+
into.add(bulb);
|
|
3556
|
+
sourcesOut.push(options.lights.addSource({ owner: "interactables.lamp", priority: LIGHT_PRIORITY.lamp, color: l.color, intensity: 1, distance: l.range, position: [0, 0, 0], follow: bulb }));
|
|
3557
|
+
continue;
|
|
3558
|
+
}
|
|
3414
3559
|
const light = new THREE.PointLight(l.color, 1, l.range);
|
|
3415
3560
|
light.position.set(point.position[0], point.position[1], point.position[2]);
|
|
3416
3561
|
into.add(light);
|
|
@@ -3454,7 +3599,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3454
3599
|
}
|
|
3455
3600
|
if (spec && (options.mergeParts ?? quality === "game")) mergeParts(THREE, group, parts, spec, { swayAmplitude: options.swayAmplitude });
|
|
3456
3601
|
if (spec) tagDestruction(group, parts, spec);
|
|
3457
|
-
return { group, parts, lights: lightsOut };
|
|
3602
|
+
return { group, parts, lights: lightsOut, sources: sourcesOut };
|
|
3458
3603
|
}
|
|
3459
3604
|
};
|
|
3460
3605
|
}
|
|
@@ -3646,7 +3791,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3646
3791
|
emissiveIntensity: 0
|
|
3647
3792
|
});
|
|
3648
3793
|
let on = false;
|
|
3649
|
-
let
|
|
3794
|
+
let channel2 = 0;
|
|
3650
3795
|
let clock = 0;
|
|
3651
3796
|
let acc = 0;
|
|
3652
3797
|
const fill = (style, x, y, rw, rh) => {
|
|
@@ -3656,7 +3801,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3656
3801
|
};
|
|
3657
3802
|
const drawBars = () => {
|
|
3658
3803
|
const n = BARS.length;
|
|
3659
|
-
for (let i = 0; i < n; i++) fill(BARS[(i +
|
|
3804
|
+
for (let i = 0; i < n; i++) fill(BARS[(i + channel2) % n], Math.floor(i * w / n), 0, Math.ceil(w / n), Math.floor(h * 0.75));
|
|
3660
3805
|
fill("#101010", 0, Math.floor(h * 0.75), w, h - Math.floor(h * 0.75));
|
|
3661
3806
|
const x = clock * 20 % (w + 12) - 12;
|
|
3662
3807
|
fill("#ffffff", x, Math.floor(h * 0.8), 12, Math.floor(h * 0.1));
|
|
@@ -3671,7 +3816,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3671
3816
|
}
|
|
3672
3817
|
};
|
|
3673
3818
|
const drawScene = () => {
|
|
3674
|
-
const hue =
|
|
3819
|
+
const hue = channel2 * 40 % 360;
|
|
3675
3820
|
fill(`hsl(${(200 + hue) % 360},60%,${55 + 10 * Math.sin(clock * 0.3)}%)`, 0, 0, w, Math.floor(h * 0.65));
|
|
3676
3821
|
fill(`hsl(${(110 + hue) % 360},40%,32%)`, 0, Math.floor(h * 0.65), w, h - Math.floor(h * 0.65));
|
|
3677
3822
|
const sx = (0.5 + 0.4 * Math.sin(clock * 0.5)) * w;
|
|
@@ -3683,9 +3828,9 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3683
3828
|
const draw = () => {
|
|
3684
3829
|
if (!on) {
|
|
3685
3830
|
fill("#000000", 0, 0, w, h);
|
|
3686
|
-
} else if (
|
|
3831
|
+
} else if (channel2 % 3 === 0) {
|
|
3687
3832
|
drawBars();
|
|
3688
|
-
} else if (
|
|
3833
|
+
} else if (channel2 % 3 === 1) {
|
|
3689
3834
|
drawNoise();
|
|
3690
3835
|
} else {
|
|
3691
3836
|
drawScene();
|
|
@@ -3706,7 +3851,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3706
3851
|
return on;
|
|
3707
3852
|
},
|
|
3708
3853
|
get channel() {
|
|
3709
|
-
return
|
|
3854
|
+
return channel2;
|
|
3710
3855
|
},
|
|
3711
3856
|
setOn(value) {
|
|
3712
3857
|
on = !!value;
|
|
@@ -3714,7 +3859,7 @@ ${QROT}${shader.vertexShader}`;
|
|
|
3714
3859
|
apply();
|
|
3715
3860
|
},
|
|
3716
3861
|
setChannel(n) {
|
|
3717
|
-
|
|
3862
|
+
channel2 = Math.max(0, Math.floor(n));
|
|
3718
3863
|
if (on) draw();
|
|
3719
3864
|
},
|
|
3720
3865
|
update(dt) {
|
|
@@ -3813,7 +3958,7 @@ uniform float swayAmplitude;
|
|
|
3813
3958
|
function createThreeAdapter(THREE, options = {}) {
|
|
3814
3959
|
return {
|
|
3815
3960
|
THREE,
|
|
3816
|
-
createMeshApi: (o = {}) => createMeshApi(THREE, { quality: options.quality, materials: options.materials, ...o }),
|
|
3961
|
+
createMeshApi: (o = {}) => createMeshApi(THREE, { quality: options.quality, materials: options.materials, ...options.lights ? { lights: options.lights } : {}, ...o }),
|
|
3817
3962
|
applyPose: (group, motion, t) => applyPose(THREE, group, motion, t),
|
|
3818
3963
|
syncObject: (world, objectId, parts, o) => syncObject(THREE, world, objectId, parts, o),
|
|
3819
3964
|
swayMaterial: (base, o) => swayMaterial(THREE, base, o),
|