@rezless/vm 0.6.1 → 0.7.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/builtins/base64.d.ts +5 -2
- package/dist/builtins/base64.d.ts.map +1 -1
- package/dist/builtins/base64.js +7 -5
- package/dist/builtins/base64.js.map +1 -1
- package/dist/builtins/detected.d.ts.map +1 -1
- package/dist/builtins/detected.js +1 -1
- package/dist/builtins/detected.js.map +1 -1
- package/dist/builtins/hash.d.ts +1 -0
- package/dist/builtins/hash.d.ts.map +1 -1
- package/dist/builtins/hash.js +12 -2
- package/dist/builtins/hash.js.map +1 -1
- package/dist/builtins/index.d.ts.map +1 -1
- package/dist/builtins/index.js +18 -7
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/inventory.d.ts +7 -5
- package/dist/builtins/inventory.d.ts.map +1 -1
- package/dist/builtins/inventory.js +36 -14
- package/dist/builtins/inventory.js.map +1 -1
- package/dist/builtins/json.d.ts.map +1 -1
- package/dist/builtins/json.js +45 -34
- package/dist/builtins/json.js.map +1 -1
- package/dist/builtins/link-info.js +2 -2
- package/dist/builtins/link-info.js.map +1 -1
- package/dist/builtins/linksetdata.d.ts.map +1 -1
- package/dist/builtins/linksetdata.js +6 -9
- package/dist/builtins/linksetdata.js.map +1 -1
- package/dist/builtins/lists.d.ts +15 -0
- package/dist/builtins/lists.d.ts.map +1 -1
- package/dist/builtins/lists.js +126 -19
- package/dist/builtins/lists.js.map +1 -1
- package/dist/builtins/math.d.ts +2 -0
- package/dist/builtins/math.d.ts.map +1 -1
- package/dist/builtins/math.js +34 -8
- package/dist/builtins/math.js.map +1 -1
- package/dist/builtins/object.d.ts +5 -2
- package/dist/builtins/object.d.ts.map +1 -1
- package/dist/builtins/object.js +13 -5
- package/dist/builtins/object.js.map +1 -1
- package/dist/builtins/prim-accessors.d.ts +1 -0
- package/dist/builtins/prim-accessors.d.ts.map +1 -1
- package/dist/builtins/prim-accessors.js +51 -24
- package/dist/builtins/prim-accessors.js.map +1 -1
- package/dist/builtins/prim-params.d.ts.map +1 -1
- package/dist/builtins/prim-params.js +6 -2
- package/dist/builtins/prim-params.js.map +1 -1
- package/dist/builtins/script-control.d.ts +4 -3
- package/dist/builtins/script-control.d.ts.map +1 -1
- package/dist/builtins/script-control.js +22 -8
- package/dist/builtins/script-control.js.map +1 -1
- package/dist/builtins/strings.d.ts +6 -0
- package/dist/builtins/strings.d.ts.map +1 -1
- package/dist/builtins/strings.js +47 -6
- package/dist/builtins/strings.js.map +1 -1
- package/dist/builtins/time.d.ts +3 -5
- package/dist/builtins/time.d.ts.map +1 -1
- package/dist/builtins/time.js +4 -7
- package/dist/builtins/time.js.map +1 -1
- package/dist/clock.d.ts +16 -6
- package/dist/clock.d.ts.map +1 -1
- package/dist/clock.js +38 -11
- package/dist/clock.js.map +1 -1
- package/dist/dispatch.d.ts +3 -2
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +15 -10
- package/dist/dispatch.js.map +1 -1
- package/dist/interpreter.d.ts +5 -9
- package/dist/interpreter.d.ts.map +1 -1
- package/dist/interpreter.js +143 -70
- package/dist/interpreter.js.map +1 -1
- package/dist/linkset.d.ts +11 -3
- package/dist/linkset.d.ts.map +1 -1
- package/dist/linkset.js +32 -11
- package/dist/linkset.js.map +1 -1
- package/dist/memory.d.ts +5 -2
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +5 -2
- package/dist/memory.js.map +1 -1
- package/dist/prim-params.d.ts +27 -10
- package/dist/prim-params.d.ts.map +1 -1
- package/dist/prim-params.js +198 -122
- package/dist/prim-params.js.map +1 -1
- package/dist/prim.d.ts +1 -1
- package/dist/prim.d.ts.map +1 -1
- package/dist/prim.js +2 -2
- package/dist/prim.js.map +1 -1
- package/dist/runtime.d.ts +11 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/script.d.ts +24 -10
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +118 -65
- package/dist/script.js.map +1 -1
- package/dist/typecheck.d.ts +3 -1
- package/dist/typecheck.d.ts.map +1 -1
- package/dist/typecheck.js +25 -5
- package/dist/typecheck.js.map +1 -1
- package/dist/values/coerce.d.ts +1 -1
- package/dist/values/coerce.d.ts.map +1 -1
- package/dist/values/coerce.js +10 -6
- package/dist/values/coerce.js.map +1 -1
- package/dist/values/format.d.ts +3 -1
- package/dist/values/format.d.ts.map +1 -1
- package/dist/values/format.js +12 -6
- package/dist/values/format.js.map +1 -1
- package/package.json +2 -2
package/dist/prim-params.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CLICK_ACTION_TOUCH, OVERRIDE_GLTF_BASE_ALPHA, OVERRIDE_GLTF_BASE_ALPHA_MASK, OVERRIDE_GLTF_BASE_ALPHA_MODE, OVERRIDE_GLTF_BASE_COLOR_FACTOR, OVERRIDE_GLTF_BASE_DOUBLE_SIDED, OVERRIDE_GLTF_EMISSIVE_FACTOR, OVERRIDE_GLTF_METALLIC_FACTOR, OVERRIDE_GLTF_ROUGHNESS_FACTOR, PRIM_ALPHA_MODE, PRIM_ALPHA_MODE_BLEND, PRIM_ALPHA_MODE_MASK, PRIM_ALLOW_UNSIT, PRIM_BUMP_NONE, PRIM_BUMP_SHINY, PRIM_CAST_SHADOWS, PRIM_CLICK_ACTION, PRIM_COLOR, PRIM_DAMAGE, PRIM_DESC, PRIM_FLEXIBLE, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_GLTF_BASE_COLOR, PRIM_GLTF_EMISSIVE, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_NORMAL, PRIM_HEALTH, PRIM_HOLE_DEFAULT, PRIM_LINK_TARGET, PRIM_MATERIAL, PRIM_MATERIAL_WOOD, PRIM_NAME, PRIM_NORMAL, PRIM_OMEGA, PRIM_PHANTOM, PRIM_PHYSICS, PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_TYPE, PRIM_POINT_LIGHT, PRIM_POSITION, PRIM_POS_LOCAL, PRIM_PROJECTOR, PRIM_REFLECTION_PROBE, PRIM_RENDER_MATERIAL, PRIM_ROTATION, PRIM_ROT_LOCAL, PRIM_SCRIPTED_SIT_ONLY, PRIM_SCULPT_TYPE_SPHERE, PRIM_SHINY_NONE, PRIM_SIT_FLAGS, PRIM_SIT_TARGET, PRIM_SIZE, PRIM_SLICE, PRIM_SPECULAR, PRIM_TEMP_ON_REZ, PRIM_TEXGEN, PRIM_TEXGEN_DEFAULT, PRIM_TEXT, PRIM_TEXTURE, PRIM_TYPE, PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_RING, PRIM_TYPE_SCULPT, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, STATUS_PHANTOM, STATUS_PHYSICS, TEXTURE_DEFAULT, } from './generated/constants.js';
|
|
2
2
|
import { NULL_KEY, isRotation, isVector } from './values/types.js';
|
|
3
3
|
import { listElementType } from './values/list-types.js';
|
|
4
|
+
import { InventoryType } from './inventory.js';
|
|
4
5
|
import { truncateUtf8 } from './values/utf8.js';
|
|
5
6
|
/**
|
|
6
7
|
* Typed-literal aliases for the PRIM_TYPE_* constants. The
|
|
@@ -45,18 +46,109 @@ export function defaultFace() {
|
|
|
45
46
|
fullBright: false,
|
|
46
47
|
glow: 0,
|
|
47
48
|
texgen: PRIM_TEXGEN_DEFAULT,
|
|
48
|
-
renderMaterial:
|
|
49
|
-
normal: defaultFaceMaterial(),
|
|
50
|
-
specular: { ...defaultFaceMaterial(), color: one(), glossiness: 51, environment: 0 },
|
|
51
|
-
alphaMode: { mode:
|
|
49
|
+
renderMaterial: NULL_KEY,
|
|
50
|
+
normal: { ...defaultFaceMaterial(), texture: NULL_KEY },
|
|
51
|
+
specular: { ...defaultFaceMaterial(), texture: NULL_KEY, color: one(), glossiness: 51, environment: 0 },
|
|
52
|
+
alphaMode: { mode: PRIM_ALPHA_MODE_BLEND, cutoff: 0 },
|
|
52
53
|
gltf: {
|
|
53
|
-
baseColor: { ...defaultFaceMaterial(), color:
|
|
54
|
+
baseColor: { ...defaultFaceMaterial(), color: '', alpha: '', alphaMode: '', alphaCutoff: '', doubleSided: '' },
|
|
54
55
|
normal: defaultFaceMaterial(),
|
|
55
|
-
metallicRoughness: { ...defaultFaceMaterial(), metallic:
|
|
56
|
-
emissive: { ...defaultFaceMaterial(), tint:
|
|
56
|
+
metallicRoughness: { ...defaultFaceMaterial(), metallic: '', roughness: '' },
|
|
57
|
+
emissive: { ...defaultFaceMaterial(), tint: '' },
|
|
57
58
|
},
|
|
58
59
|
};
|
|
59
60
|
}
|
|
61
|
+
function clearGltfOverrides(g) {
|
|
62
|
+
g.baseColor = { ...g.baseColor, texture: '', color: '', alpha: '', alphaMode: '', alphaCutoff: '', doubleSided: '' };
|
|
63
|
+
g.normal = { ...g.normal, texture: '' };
|
|
64
|
+
g.metallicRoughness = { ...g.metallicRoughness, texture: '', metallic: '', roughness: '' };
|
|
65
|
+
g.emissive = { ...g.emissive, texture: '', tint: '' };
|
|
66
|
+
}
|
|
67
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
68
|
+
const findItem = (prim, type, name) => prim.inventory.find((it) => it.type === type && it.name === name);
|
|
69
|
+
/** The key a render material argument names: "" (none), a key, or a material item's name; null if it names nothing. */
|
|
70
|
+
export function renderMaterialKey(prim, material) {
|
|
71
|
+
if (material === '')
|
|
72
|
+
return NULL_KEY;
|
|
73
|
+
if (UUID.test(material))
|
|
74
|
+
return material;
|
|
75
|
+
return findItem(prim, InventoryType.MATERIAL, material)?.key ?? null;
|
|
76
|
+
}
|
|
77
|
+
export function textureKey(prim, texture) {
|
|
78
|
+
if (texture === '')
|
|
79
|
+
return NULL_KEY;
|
|
80
|
+
if (UUID.test(texture))
|
|
81
|
+
return texture;
|
|
82
|
+
return findItem(prim, InventoryType.TEXTURE, texture)?.key ?? null;
|
|
83
|
+
}
|
|
84
|
+
const itemName = (prim, type, key) => key === NULL_KEY ? key : (prim.inventory.find((it) => it.type === type && it.key === key)?.name ?? key);
|
|
85
|
+
export const textureName = (prim, key) => itemName(prim, InventoryType.TEXTURE, key);
|
|
86
|
+
export const materialName = (prim, key) => itemName(prim, InventoryType.MATERIAL, key);
|
|
87
|
+
const OVERRIDE_TYPES = {
|
|
88
|
+
[OVERRIDE_GLTF_BASE_COLOR_FACTOR]: 'vector',
|
|
89
|
+
[OVERRIDE_GLTF_BASE_ALPHA]: 'float',
|
|
90
|
+
[OVERRIDE_GLTF_BASE_ALPHA_MODE]: 'integer',
|
|
91
|
+
[OVERRIDE_GLTF_BASE_ALPHA_MASK]: 'float',
|
|
92
|
+
[OVERRIDE_GLTF_BASE_DOUBLE_SIDED]: 'integer',
|
|
93
|
+
[OVERRIDE_GLTF_METALLIC_FACTOR]: 'float',
|
|
94
|
+
[OVERRIDE_GLTF_ROUGHNESS_FACTOR]: 'float',
|
|
95
|
+
[OVERRIDE_GLTF_EMISSIVE_FACTOR]: 'vector',
|
|
96
|
+
};
|
|
97
|
+
const overrideType = (code) => (typeof code === 'number' ? OVERRIDE_TYPES[code] : undefined);
|
|
98
|
+
/**
|
|
99
|
+
* Apply llSetLinkGLTFOverrides' [OVERRIDE_GLTF_*, value, ...] pairs. The base
|
|
100
|
+
* colour and alpha form one factor that "" leaves alone; "" clears the others.
|
|
101
|
+
* One wrong-typed value rejects the whole call; an unknown code is skipped.
|
|
102
|
+
*/
|
|
103
|
+
export function setGltfOverrides(g, params) {
|
|
104
|
+
for (let i = 0; i + 1 < params.length; i += 2) {
|
|
105
|
+
const expected = overrideType(params[i]);
|
|
106
|
+
if (expected === undefined || params[i + 1] === '')
|
|
107
|
+
continue;
|
|
108
|
+
const given = givenType(params, i + 1);
|
|
109
|
+
if (given !== expected && !(expected === 'float' && given === 'integer'))
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const bc = g.baseColor;
|
|
113
|
+
for (let i = 0; i + 1 < params.length; i += 2) {
|
|
114
|
+
const v = params[i + 1];
|
|
115
|
+
const n = typeof v === 'number' ? v : '';
|
|
116
|
+
switch (params[i]) {
|
|
117
|
+
case OVERRIDE_GLTF_BASE_COLOR_FACTOR:
|
|
118
|
+
if (isVector(v)) {
|
|
119
|
+
bc.color = clampVec(asVec(v), 0, 1);
|
|
120
|
+
if (bc.alpha === '')
|
|
121
|
+
bc.alpha = 1;
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case OVERRIDE_GLTF_BASE_ALPHA:
|
|
125
|
+
if (typeof v === 'number') {
|
|
126
|
+
bc.alpha = clamp(v, 0, 1);
|
|
127
|
+
if (bc.color === '')
|
|
128
|
+
bc.color = one();
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
case OVERRIDE_GLTF_BASE_ALPHA_MODE:
|
|
132
|
+
bc.alphaMode = n === '' ? '' : clamp(n, 0, 2);
|
|
133
|
+
break;
|
|
134
|
+
case OVERRIDE_GLTF_BASE_ALPHA_MASK:
|
|
135
|
+
bc.alphaCutoff = n === '' ? '' : clamp(n, 0, 1);
|
|
136
|
+
break;
|
|
137
|
+
case OVERRIDE_GLTF_BASE_DOUBLE_SIDED:
|
|
138
|
+
bc.doubleSided = n === '' ? '' : clamp(n, 0, 1);
|
|
139
|
+
break;
|
|
140
|
+
case OVERRIDE_GLTF_METALLIC_FACTOR:
|
|
141
|
+
g.metallicRoughness.metallic = n === '' ? '' : clamp(n, 0, 1);
|
|
142
|
+
break;
|
|
143
|
+
case OVERRIDE_GLTF_ROUGHNESS_FACTOR:
|
|
144
|
+
g.metallicRoughness.roughness = n === '' ? '' : clamp(n, 0, 1);
|
|
145
|
+
break;
|
|
146
|
+
case OVERRIDE_GLTF_EMISSIVE_FACTOR:
|
|
147
|
+
g.emissive.tint = isVector(v) ? clampVec(asVec(v), 0, 1) : '';
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
60
152
|
export function defaultShape() {
|
|
61
153
|
return {
|
|
62
154
|
kind: SHAPE_BOX,
|
|
@@ -74,7 +166,7 @@ export function defaultPrimParams() {
|
|
|
74
166
|
rotation: identityRot(),
|
|
75
167
|
size: { x: 0.5, y: 0.5, z: 0.5 },
|
|
76
168
|
faces: Array.from({ length: 6 }, () => defaultFace()),
|
|
77
|
-
pointLight: { enabled: false, color:
|
|
169
|
+
pointLight: { enabled: false, color: zero(), intensity: 0, radius: 0, falloff: 0 },
|
|
78
170
|
glow: [0, 0, 0, 0, 0, 0],
|
|
79
171
|
omega: { axis: zero(), spinrate: 0, gain: 0 },
|
|
80
172
|
physicsShapeType: PRIM_PHYSICS_SHAPE_PRIM,
|
|
@@ -128,11 +220,11 @@ function normalizeRot(r) {
|
|
|
128
220
|
return identityRot();
|
|
129
221
|
return { x: r.x / mag, y: r.y / mag, z: r.z / mag, s: r.s / mag };
|
|
130
222
|
}
|
|
131
|
-
/** Face indexes a face argument names: every face for
|
|
223
|
+
/** Face indexes a face argument names: every face for a negative face, none past the shape's face count. */
|
|
132
224
|
export function faceIndices(p, face) {
|
|
133
|
-
if (face
|
|
225
|
+
if (face < 0)
|
|
134
226
|
return p.faces.map((_, i) => i);
|
|
135
|
-
return face
|
|
227
|
+
return face < p.faces.length ? [face] : [];
|
|
136
228
|
}
|
|
137
229
|
const facesOf = (p, faceArg) => faceIndices(p, num(faceArg, 0) | 0);
|
|
138
230
|
/**
|
|
@@ -214,20 +306,23 @@ export function writePrimParamSlots(param, rules, cursor) {
|
|
|
214
306
|
* advances by `1 + consumed`). Returns `null` for unsupported / unknown
|
|
215
307
|
* rule constants — the walker stops parsing the list, matching LSL.
|
|
216
308
|
*/
|
|
217
|
-
export function writePrimParam(prim, param, rules, cursor) {
|
|
309
|
+
export function writePrimParam(prim, param, rules, cursor, caller = prim) {
|
|
218
310
|
const p = prim.params;
|
|
219
311
|
switch (param) {
|
|
220
312
|
case PRIM_NAME:
|
|
221
|
-
prim.name = truncateUtf8(str(rules[cursor]), 63);
|
|
313
|
+
prim.name = truncateUtf8(plainText(str(rules[cursor])), 63);
|
|
222
314
|
return 1;
|
|
223
315
|
case PRIM_DESC:
|
|
224
|
-
prim.description = truncateUtf8(str(rules[cursor]), 127);
|
|
316
|
+
prim.description = truncateUtf8(plainText(str(rules[cursor])), 127);
|
|
225
317
|
prim.appearance.description = prim.description;
|
|
226
318
|
return 1;
|
|
227
319
|
case PRIM_TEXT: {
|
|
228
320
|
const text = truncateUtf8(str(rules[cursor]), 254);
|
|
229
321
|
const color = asVec(rules[cursor + 1]);
|
|
230
322
|
const alpha = num(rules[cursor + 2], 1);
|
|
323
|
+
const outOfRange = (v) => v < 0 || v > 1;
|
|
324
|
+
if (outOfRange(alpha) || outOfRange(color.x) || outOfRange(color.y) || outOfRange(color.z))
|
|
325
|
+
return 3;
|
|
231
326
|
prim.appearance.text = { text, color, alpha };
|
|
232
327
|
return 3;
|
|
233
328
|
}
|
|
@@ -341,29 +436,33 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
341
436
|
}
|
|
342
437
|
case PRIM_TEXTURE: {
|
|
343
438
|
const faces = facesOf(p, rules[cursor]);
|
|
344
|
-
const tex = str(rules[cursor + 1]);
|
|
439
|
+
const tex = textureKey(caller, str(rules[cursor + 1])) ?? NULL_KEY;
|
|
345
440
|
const repeats = asVec(rules[cursor + 2]);
|
|
346
441
|
const offsets = asVec(rules[cursor + 3]);
|
|
347
442
|
const rot = num(rules[cursor + 4]);
|
|
348
443
|
for (const f of faces) {
|
|
349
444
|
p.faces[f].texture = tex;
|
|
350
|
-
p.faces[f].textureRepeats = { x: repeats.x, y: repeats.y, z:
|
|
351
|
-
p.faces[f].textureOffsets = { x: offsets.x, y: offsets.y, z:
|
|
445
|
+
p.faces[f].textureRepeats = { x: repeats.x, y: repeats.y, z: 0 };
|
|
446
|
+
p.faces[f].textureOffsets = { x: offsets.x, y: offsets.y, z: 0 };
|
|
352
447
|
p.faces[f].textureRotation = rot;
|
|
353
448
|
}
|
|
354
449
|
return 5;
|
|
355
450
|
}
|
|
356
451
|
case PRIM_RENDER_MATERIAL: {
|
|
357
452
|
const faces = facesOf(p, rules[cursor]);
|
|
358
|
-
const m = str(rules[cursor + 1]);
|
|
453
|
+
const m = renderMaterialKey(caller, str(rules[cursor + 1])) ?? NULL_KEY;
|
|
359
454
|
for (const f of faces) {
|
|
360
455
|
p.faces[f].renderMaterial = m;
|
|
456
|
+
clearGltfOverrides(p.faces[f].gltf);
|
|
361
457
|
}
|
|
362
458
|
return 2;
|
|
363
459
|
}
|
|
364
460
|
case PRIM_FULLBRIGHT: {
|
|
365
461
|
const faces = facesOf(p, rules[cursor]);
|
|
366
|
-
const
|
|
462
|
+
const raw = num(rules[cursor + 1]);
|
|
463
|
+
if (raw !== 0 && raw !== 1)
|
|
464
|
+
return 2;
|
|
465
|
+
const v = raw === 1;
|
|
367
466
|
for (const f of faces) {
|
|
368
467
|
p.faces[f].fullBright = v;
|
|
369
468
|
}
|
|
@@ -382,6 +481,8 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
382
481
|
const faces = facesOf(p, rules[cursor]);
|
|
383
482
|
const shiny = num(rules[cursor + 1]) | 0;
|
|
384
483
|
const bump = num(rules[cursor + 2]) | 0;
|
|
484
|
+
if (shiny < 0 || shiny > 3 || bump < 0 || bump > 17)
|
|
485
|
+
return 3;
|
|
385
486
|
for (const f of faces) {
|
|
386
487
|
p.faces[f].bumpShiny = { shiny, bump };
|
|
387
488
|
}
|
|
@@ -390,6 +491,8 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
390
491
|
case PRIM_TEXGEN: {
|
|
391
492
|
const faces = facesOf(p, rules[cursor]);
|
|
392
493
|
const mode = num(rules[cursor + 1]) | 0;
|
|
494
|
+
if (mode < 0 || mode > 1)
|
|
495
|
+
return 2;
|
|
393
496
|
for (const f of faces) {
|
|
394
497
|
p.faces[f].texgen = mode;
|
|
395
498
|
}
|
|
@@ -398,12 +501,13 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
398
501
|
case PRIM_NORMAL: {
|
|
399
502
|
const faces = facesOf(p, rules[cursor]);
|
|
400
503
|
const tex = str(rules[cursor + 1]);
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
const
|
|
504
|
+
const key = textureKey(caller, tex) ?? NULL_KEY;
|
|
505
|
+
const repeats = tex === '' ? { x: 1, y: 1, z: 0 } : asVec(rules[cursor + 2]);
|
|
506
|
+
const offsets = tex === '' ? zero() : asVec(rules[cursor + 3]);
|
|
507
|
+
const rot = tex === '' ? 0 : num(rules[cursor + 4]);
|
|
404
508
|
for (const f of faces) {
|
|
405
509
|
p.faces[f].normal = {
|
|
406
|
-
texture:
|
|
510
|
+
texture: key,
|
|
407
511
|
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
408
512
|
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
409
513
|
textureRotation: rot,
|
|
@@ -414,15 +518,17 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
414
518
|
case PRIM_SPECULAR: {
|
|
415
519
|
const faces = facesOf(p, rules[cursor]);
|
|
416
520
|
const tex = str(rules[cursor + 1]);
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
const
|
|
421
|
-
const
|
|
422
|
-
const
|
|
521
|
+
const key = textureKey(caller, tex) ?? NULL_KEY;
|
|
522
|
+
const reset = tex === '';
|
|
523
|
+
const repeats = reset ? { x: 1, y: 1, z: 0 } : asVec(rules[cursor + 2]);
|
|
524
|
+
const offsets = reset ? zero() : asVec(rules[cursor + 3]);
|
|
525
|
+
const rot = reset ? 0 : num(rules[cursor + 4]);
|
|
526
|
+
const color = reset ? one() : asVec(rules[cursor + 5]);
|
|
527
|
+
const gloss = reset ? 51 : clamp(num(rules[cursor + 6]) | 0, 0, 255);
|
|
528
|
+
const env = reset ? 0 : clamp(num(rules[cursor + 7]) | 0, 0, 255);
|
|
423
529
|
for (const f of faces) {
|
|
424
530
|
p.faces[f].specular = {
|
|
425
|
-
texture:
|
|
531
|
+
texture: key,
|
|
426
532
|
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
427
533
|
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
428
534
|
// Second Life stores a negative rotation as 0 and the colour in 8 bits per channel
|
|
@@ -436,99 +542,66 @@ export function writePrimParam(prim, param, rules, cursor) {
|
|
|
436
542
|
}
|
|
437
543
|
case PRIM_ALPHA_MODE: {
|
|
438
544
|
const faces = facesOf(p, rules[cursor]);
|
|
439
|
-
const mode = num(rules[cursor + 1]) | 0;
|
|
440
|
-
const cutoff = num(rules[cursor + 2]) | 0;
|
|
545
|
+
const mode = clamp(num(rules[cursor + 1]) | 0, 0, 3);
|
|
546
|
+
const cutoff = mode === PRIM_ALPHA_MODE_MASK ? clamp(num(rules[cursor + 2]) | 0, 0, 255) : 0;
|
|
441
547
|
for (const f of faces) {
|
|
442
548
|
p.faces[f].alphaMode = { mode, cutoff };
|
|
443
549
|
}
|
|
444
550
|
return 3;
|
|
445
551
|
}
|
|
446
552
|
case PRIM_GLTF_BASE_COLOR: {
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
for (const f of faces) {
|
|
458
|
-
p.faces[f].gltf.baseColor = {
|
|
459
|
-
texture: tex,
|
|
460
|
-
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
461
|
-
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
462
|
-
textureRotation: rot,
|
|
463
|
-
color: { x: color.x, y: color.y, z: color.z },
|
|
464
|
-
alpha,
|
|
465
|
-
alphaMode: aMode,
|
|
466
|
-
alphaCutoff: aCut,
|
|
467
|
-
doubleSided: dbl,
|
|
468
|
-
};
|
|
469
|
-
}
|
|
553
|
+
const color = rules[cursor + 5];
|
|
554
|
+
const alpha = rules[cursor + 6];
|
|
555
|
+
const factor = color !== '' || alpha !== '';
|
|
556
|
+
writeGltf(prim, caller, rules, cursor, 'baseColor', {
|
|
557
|
+
color: factor ? (color === '' ? one() : clampVec(asVec(color), 0, 1)) : '',
|
|
558
|
+
alpha: factor ? clamp(num(alpha, 1), 0, 1) : '',
|
|
559
|
+
alphaMode: valueOverride(rules[cursor + 7], (v) => clamp(num(v) | 0, 0, 2)),
|
|
560
|
+
alphaCutoff: valueOverride(rules[cursor + 8], (v) => clamp(num(v), 0, 1)),
|
|
561
|
+
doubleSided: valueOverride(rules[cursor + 9], (v) => clamp(num(v) | 0, 0, 1)),
|
|
562
|
+
});
|
|
470
563
|
return 10;
|
|
471
564
|
}
|
|
472
|
-
case PRIM_GLTF_NORMAL:
|
|
473
|
-
|
|
474
|
-
const tex = str(rules[cursor + 1]);
|
|
475
|
-
const repeats = asVec(rules[cursor + 2]);
|
|
476
|
-
const offsets = asVec(rules[cursor + 3]);
|
|
477
|
-
const rot = num(rules[cursor + 4]);
|
|
478
|
-
for (const f of faces) {
|
|
479
|
-
p.faces[f].gltf.normal = {
|
|
480
|
-
texture: tex,
|
|
481
|
-
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
482
|
-
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
483
|
-
textureRotation: rot,
|
|
484
|
-
};
|
|
485
|
-
}
|
|
565
|
+
case PRIM_GLTF_NORMAL:
|
|
566
|
+
writeGltf(prim, caller, rules, cursor, 'normal', {});
|
|
486
567
|
return 5;
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const offsets = asVec(rules[cursor + 3]);
|
|
493
|
-
const rot = num(rules[cursor + 4]);
|
|
494
|
-
const metallic = num(rules[cursor + 5]);
|
|
495
|
-
const rough = num(rules[cursor + 6]);
|
|
496
|
-
for (const f of faces) {
|
|
497
|
-
p.faces[f].gltf.metallicRoughness = {
|
|
498
|
-
texture: tex,
|
|
499
|
-
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
500
|
-
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
501
|
-
textureRotation: rot,
|
|
502
|
-
metallic,
|
|
503
|
-
roughness: rough,
|
|
504
|
-
};
|
|
505
|
-
}
|
|
568
|
+
case PRIM_GLTF_METALLIC_ROUGHNESS:
|
|
569
|
+
writeGltf(prim, caller, rules, cursor, 'metallicRoughness', {
|
|
570
|
+
metallic: valueOverride(rules[cursor + 5], (v) => clamp(num(v), 0, 1)),
|
|
571
|
+
roughness: valueOverride(rules[cursor + 6], (v) => clamp(num(v), 0, 1)),
|
|
572
|
+
});
|
|
506
573
|
return 7;
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const faces = facesOf(p, rules[cursor]);
|
|
510
|
-
const tex = str(rules[cursor + 1]);
|
|
511
|
-
const repeats = asVec(rules[cursor + 2]);
|
|
512
|
-
const offsets = asVec(rules[cursor + 3]);
|
|
513
|
-
const rot = num(rules[cursor + 4]);
|
|
514
|
-
const tint = asVec(rules[cursor + 5]);
|
|
515
|
-
for (const f of faces) {
|
|
516
|
-
p.faces[f].gltf.emissive = {
|
|
517
|
-
texture: tex,
|
|
518
|
-
textureRepeats: { x: repeats.x, y: repeats.y, z: repeats.z },
|
|
519
|
-
textureOffsets: { x: offsets.x, y: offsets.y, z: offsets.z },
|
|
520
|
-
textureRotation: rot,
|
|
521
|
-
tint: { x: tint.x, y: tint.y, z: tint.z },
|
|
522
|
-
};
|
|
523
|
-
}
|
|
574
|
+
case PRIM_GLTF_EMISSIVE:
|
|
575
|
+
writeGltf(prim, caller, rules, cursor, 'emissive', { tint: valueOverride(rules[cursor + 5], (v) => clampVec(asVec(v), 0, 1)) });
|
|
524
576
|
return 6;
|
|
525
|
-
}
|
|
526
577
|
case PRIM_LINK_TARGET:
|
|
527
578
|
return null;
|
|
528
579
|
default:
|
|
529
580
|
return null;
|
|
530
581
|
}
|
|
531
582
|
}
|
|
583
|
+
const valueOverride = (v, read) => (v === '' ? '' : read(v));
|
|
584
|
+
/**
|
|
585
|
+
* Write one PRIM_GLTF_* rule. "" in a transform slot resets it; "" in a texture
|
|
586
|
+
* or value slot unsets that override. Faces without a render material keep
|
|
587
|
+
* only the transforms.
|
|
588
|
+
*/
|
|
589
|
+
function writeGltf(prim, caller, rules, cursor, rule, values) {
|
|
590
|
+
const transform = {
|
|
591
|
+
textureRepeats: rules[cursor + 2] === '' ? { x: 1, y: 1, z: 0 } : asVec(rules[cursor + 2]),
|
|
592
|
+
textureOffsets: asVec(rules[cursor + 3]),
|
|
593
|
+
textureRotation: num(rules[cursor + 4]),
|
|
594
|
+
};
|
|
595
|
+
const name = str(rules[cursor + 1]);
|
|
596
|
+
const texture = name === '' ? '' : (textureKey(caller, name) ?? NULL_KEY);
|
|
597
|
+
for (const f of facesOf(prim.params, rules[cursor])) {
|
|
598
|
+
const face = prim.params.faces[f];
|
|
599
|
+
const overrides = face.renderMaterial === NULL_KEY ? {} : { texture, ...values };
|
|
600
|
+
face.gltf[rule] = { ...face.gltf[rule], ...transform, ...overrides };
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
/** Names and descriptions can't hold the separator characters; they become `?`. */
|
|
604
|
+
const plainText = (s) => s.replace(/[|\n]/g, '?');
|
|
532
605
|
function writePrimType(p, rules, cursor) {
|
|
533
606
|
const kind = (num(rules[cursor]) | 0);
|
|
534
607
|
const old = p.shape;
|
|
@@ -606,7 +679,7 @@ export function readPrimParam(prim, param, rules, cursor) {
|
|
|
606
679
|
return { values: [prim.description], consumed: 0 };
|
|
607
680
|
case PRIM_TEXT: {
|
|
608
681
|
const t = prim.appearance.text;
|
|
609
|
-
return { values: t ? [t.text, t.color, t.alpha] : ['', zero(),
|
|
682
|
+
return { values: t ? [t.text, t.color, t.alpha] : ['', zero(), 1], consumed: 0 };
|
|
610
683
|
}
|
|
611
684
|
case PRIM_POSITION:
|
|
612
685
|
return { values: [prim.regionPosition()], consumed: 0 };
|
|
@@ -683,7 +756,7 @@ export function readPrimParam(prim, param, rules, cursor) {
|
|
|
683
756
|
const out = [];
|
|
684
757
|
for (const f of faces) {
|
|
685
758
|
const fa = p.faces[f];
|
|
686
|
-
out.push(fa.texture, fa.textureRepeats, fa.textureOffsets, fa.textureRotation);
|
|
759
|
+
out.push(textureName(prim, fa.texture), fa.textureRepeats, fa.textureOffsets, fa.textureRotation);
|
|
687
760
|
}
|
|
688
761
|
return { values: out, consumed: 1 };
|
|
689
762
|
}
|
|
@@ -691,7 +764,7 @@ export function readPrimParam(prim, param, rules, cursor) {
|
|
|
691
764
|
const faces = facesOf(p, rules[cursor]);
|
|
692
765
|
const out = [];
|
|
693
766
|
for (const f of faces) {
|
|
694
|
-
out.push(p.faces[f].renderMaterial);
|
|
767
|
+
out.push(materialName(prim, p.faces[f].renderMaterial));
|
|
695
768
|
}
|
|
696
769
|
return { values: out, consumed: 1 };
|
|
697
770
|
}
|
|
@@ -732,7 +805,7 @@ export function readPrimParam(prim, param, rules, cursor) {
|
|
|
732
805
|
const out = [];
|
|
733
806
|
for (const f of faces) {
|
|
734
807
|
const n = p.faces[f].normal;
|
|
735
|
-
out.push(n.texture, n.textureRepeats, n.textureOffsets, n.textureRotation);
|
|
808
|
+
out.push(textureName(prim, n.texture), n.textureRepeats, n.textureOffsets, n.textureRotation);
|
|
736
809
|
}
|
|
737
810
|
return { values: out, consumed: 1 };
|
|
738
811
|
}
|
|
@@ -741,7 +814,7 @@ export function readPrimParam(prim, param, rules, cursor) {
|
|
|
741
814
|
const out = [];
|
|
742
815
|
for (const f of faces) {
|
|
743
816
|
const s = p.faces[f].specular;
|
|
744
|
-
out.push(s.texture, s.textureRepeats, s.textureOffsets, s.textureRotation, s.color, s.glossiness, s.environment);
|
|
817
|
+
out.push(textureName(prim, s.texture), s.textureRepeats, s.textureOffsets, s.textureRotation, s.color, s.glossiness, s.environment);
|
|
745
818
|
}
|
|
746
819
|
return { values: out, consumed: 1 };
|
|
747
820
|
}
|
|
@@ -812,6 +885,7 @@ function readPrimType(p) {
|
|
|
812
885
|
return [];
|
|
813
886
|
}
|
|
814
887
|
const MATERIAL_TYPES = ['string', 'vector', 'vector', 'float'];
|
|
888
|
+
const MAP_TYPES = ['key', 'vector', 'vector', 'float'];
|
|
815
889
|
/**
|
|
816
890
|
* LSL types of the values each PRIM_* rule reads. Per-face rules list one
|
|
817
891
|
* face's values; the pattern repeats for each face.
|
|
@@ -851,13 +925,13 @@ const PRIM_PARAM_TYPES = {
|
|
|
851
925
|
[PRIM_GLOW]: ['float'],
|
|
852
926
|
[PRIM_BUMP_SHINY]: ['integer', 'integer'],
|
|
853
927
|
[PRIM_TEXGEN]: ['integer'],
|
|
854
|
-
[PRIM_NORMAL]:
|
|
855
|
-
[PRIM_SPECULAR]: [...
|
|
928
|
+
[PRIM_NORMAL]: MAP_TYPES,
|
|
929
|
+
[PRIM_SPECULAR]: [...MAP_TYPES, 'vector', 'integer', 'integer'],
|
|
856
930
|
[PRIM_ALPHA_MODE]: ['integer', 'integer'],
|
|
857
|
-
[PRIM_GLTF_BASE_COLOR]: [...
|
|
858
|
-
[PRIM_GLTF_NORMAL]:
|
|
859
|
-
[PRIM_GLTF_METALLIC_ROUGHNESS]: [...
|
|
860
|
-
[PRIM_GLTF_EMISSIVE]: [...
|
|
931
|
+
[PRIM_GLTF_BASE_COLOR]: [...MAP_TYPES, 'vector', 'float', 'integer', 'float', 'integer'],
|
|
932
|
+
[PRIM_GLTF_NORMAL]: MAP_TYPES,
|
|
933
|
+
[PRIM_GLTF_METALLIC_ROUGHNESS]: [...MAP_TYPES, 'float', 'float'],
|
|
934
|
+
[PRIM_GLTF_EMISSIVE]: [...MAP_TYPES, 'vector'],
|
|
861
935
|
};
|
|
862
936
|
/** LSL types of PRIM_TYPE's values, which depend on the shape. */
|
|
863
937
|
function primTypeTypes(kind) {
|
|
@@ -871,10 +945,12 @@ function primTypeTypes(kind) {
|
|
|
871
945
|
}
|
|
872
946
|
return [...common, 'vector', 'vector'];
|
|
873
947
|
}
|
|
948
|
+
/** GLTF override rules take "" in any slot after the face to mean "no override", and read an unset one as "". */
|
|
949
|
+
const GLTF_RULES = new Set([PRIM_GLTF_BASE_COLOR, PRIM_GLTF_NORMAL, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_EMISSIVE]);
|
|
874
950
|
/** LSL types of the values `readPrimParam` returns for `param`. */
|
|
875
951
|
export function primParamTypes(param, values) {
|
|
876
952
|
const pattern = param === PRIM_TYPE ? primTypeTypes(values[0]) : (PRIM_PARAM_TYPES[param] ?? []);
|
|
877
|
-
return values.map((
|
|
953
|
+
return values.map((v, i) => (GLTF_RULES.has(param) && v === '' ? 'string' : pattern[i % pattern.length]));
|
|
878
954
|
}
|
|
879
955
|
const PER_FACE_RULES = new Set([
|
|
880
956
|
PRIM_COLOR, PRIM_TEXTURE, PRIM_RENDER_MATERIAL, PRIM_FULLBRIGHT, PRIM_GLOW, PRIM_BUMP_SHINY,
|
|
@@ -921,12 +997,12 @@ const formatG = (v) => String(Number(v.toPrecision(6)));
|
|
|
921
997
|
* the rule can run, otherwise the error text that follows "rule #N" in the
|
|
922
998
|
* simulator's message (e.g. " (PRIM_SIZE): arg #1 vector expected but string given").
|
|
923
999
|
*/
|
|
924
|
-
/** GLTF override rules take "" in any slot after the face to mean "no override". */
|
|
925
|
-
const GLTF_RULES = new Set([PRIM_GLTF_BASE_COLOR, PRIM_GLTF_NORMAL, PRIM_GLTF_METALLIC_ROUGHNESS, PRIM_GLTF_EMISSIVE]);
|
|
926
1000
|
export function checkPrimRule(param, rules, cursor) {
|
|
927
1001
|
const name = RULE_NAMES.get(param);
|
|
928
|
-
if (name === undefined
|
|
1002
|
+
if (name === undefined)
|
|
929
1003
|
return ': unknown rule';
|
|
1004
|
+
if (writePrimParamSlots(param, rules, cursor) === null)
|
|
1005
|
+
return param === PRIM_TYPE ? null : ': unknown rule';
|
|
930
1006
|
const pattern = param === PRIM_TYPE ? primTypeTypes(rules[cursor]) : PRIM_PARAM_TYPES[param];
|
|
931
1007
|
const expected = PER_FACE_RULES.has(param) ? ['integer', ...pattern] : pattern;
|
|
932
1008
|
for (let i = 0; i < expected.length; i++) {
|