Skip to content

Commit 070a2ec

Browse files
Fix LLSD format GLTF MatOvrd parsing
1 parent 8b5cdce commit 070a2ec

3 files changed

Lines changed: 158 additions & 2 deletions

File tree

lib/classes/LLGLTFMaterialOverride.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import type {
44
LLGLTFMaterialEntry,
55
LLGLTFTextureInfo,
66
} from './LLGLTFMaterialData';
7+
import { LLSD } from './llsd/LLSD';
8+
import { LLSDInteger } from './llsd/LLSDInteger';
9+
import { LLSDMap } from './llsd/LLSDMap';
10+
import { LLSDReal } from './llsd/LLSDReal';
11+
import type { LLSDType } from './llsd/LLSDType';
712
import { UUID } from './UUID';
813

914
export interface LLGLTFTextureTransformOverride
@@ -25,6 +30,118 @@ export class LLGLTFMaterialOverride
2530
public doubleSided?: boolean;
2631
public textureTransforms?: (LLGLTFTextureTransformOverride | null)[];
2732

33+
public static fromStoredMaterial(data: string): LLGLTFMaterialOverride
34+
{
35+
try
36+
{
37+
return LLGLTFMaterialOverride.fromFullMaterialJSON(data);
38+
}
39+
catch (_error: unknown)
40+
{
41+
return LLGLTFMaterialOverride.fromOverrideLLSDNotation(data);
42+
}
43+
}
44+
45+
public static fromOverrideLLSDNotation(notation: string): LLGLTFMaterialOverride
46+
{
47+
const over = new LLGLTFMaterialOverride();
48+
const parsed = LLSD.parseNotation(notation);
49+
if (!(parsed instanceof LLSDMap))
50+
{
51+
return over;
52+
}
53+
54+
const tex = parsed.get('tex');
55+
if (Array.isArray(tex))
56+
{
57+
for (let i = 0; i < tex.length; i++)
58+
{
59+
const entry = tex[i];
60+
if (entry instanceof UUID && !entry.isZero())
61+
{
62+
over.setTexture(i, entry.toString());
63+
}
64+
}
65+
}
66+
67+
const baseColor = LLGLTFMaterialOverride.llsdNumberArray(parsed.get('bc'));
68+
if (baseColor !== undefined && baseColor.length === 4)
69+
{
70+
over.baseColor = baseColor;
71+
}
72+
73+
const emissive = LLGLTFMaterialOverride.llsdNumberArray(parsed.get('ec'));
74+
if (emissive !== undefined)
75+
{
76+
over.emissiveFactor = emissive;
77+
}
78+
79+
const metallic = LLGLTFMaterialOverride.llsdNumber(parsed.get('mf'));
80+
if (metallic !== undefined)
81+
{
82+
over.metallicFactor = metallic;
83+
}
84+
85+
const roughness = LLGLTFMaterialOverride.llsdNumber(parsed.get('rf'));
86+
if (roughness !== undefined)
87+
{
88+
over.roughnessFactor = roughness;
89+
}
90+
91+
const alphaMode = LLGLTFMaterialOverride.llsdNumber(parsed.get('am'));
92+
if (alphaMode !== undefined)
93+
{
94+
over.alphaMode = alphaMode;
95+
}
96+
97+
const alphaCutoff = LLGLTFMaterialOverride.llsdNumber(parsed.get('ac'));
98+
if (alphaCutoff !== undefined)
99+
{
100+
over.alphaCutoff = alphaCutoff;
101+
}
102+
103+
const doubleSided = parsed.get('ds');
104+
if (typeof doubleSided === 'boolean')
105+
{
106+
over.doubleSided = doubleSided;
107+
}
108+
109+
const transforms = parsed.get('ti');
110+
if (Array.isArray(transforms))
111+
{
112+
for (let i = 0; i < transforms.length; i++)
113+
{
114+
const entry = transforms[i];
115+
if (!(entry instanceof LLSDMap))
116+
{
117+
continue;
118+
}
119+
const transform: LLGLTFTextureTransformOverride = {};
120+
const offset = LLGLTFMaterialOverride.llsdNumberArray(entry.get('o'));
121+
if (offset !== undefined)
122+
{
123+
transform.offset = offset;
124+
}
125+
const scale = LLGLTFMaterialOverride.llsdNumberArray(entry.get('s'));
126+
if (scale !== undefined)
127+
{
128+
transform.scale = scale;
129+
}
130+
const rotation = LLGLTFMaterialOverride.llsdNumber(entry.get('r'));
131+
if (rotation !== undefined)
132+
{
133+
transform.rotation = rotation;
134+
}
135+
if (Object.keys(transform).length > 0)
136+
{
137+
over.setTransform(i, transform);
138+
}
139+
}
140+
}
141+
142+
return over;
143+
}
144+
28145
public static fromFullMaterialJSON(json: string): LLGLTFMaterialOverride
29146
{
30147
const obj = JSON.parse(json) as LLGLTFMaterialData;
@@ -400,4 +517,36 @@ export class LLGLTFMaterialOverride
400517
}
401518
this.textureTransforms[idx] = trans;
402519
}
520+
521+
private static llsdNumber(value: LLSDType | undefined): number | undefined
522+
{
523+
if (value instanceof LLSDInteger || value instanceof LLSDReal)
524+
{
525+
return value.valueOf();
526+
}
527+
if (typeof value === 'number')
528+
{
529+
return value;
530+
}
531+
return undefined;
532+
}
533+
534+
private static llsdNumberArray(value: LLSDType | undefined): number[] | undefined
535+
{
536+
if (!Array.isArray(value))
537+
{
538+
return undefined;
539+
}
540+
const result: number[] = [];
541+
for (const entry of value)
542+
{
543+
const num = LLGLTFMaterialOverride.llsdNumber(entry);
544+
if (num === undefined)
545+
{
546+
return undefined;
547+
}
548+
result.push(num);
549+
}
550+
return result;
551+
}
403552
}

lib/classes/public/GameObject.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1544,7 +1544,14 @@ export class GameObject implements IGameObjectData
15441544
pos++;
15451545
const json = tex.subarray(pos, pos + len).toString('utf-8');
15461546
pos = pos + len;
1547-
go.TextureEntry.gltfMaterialOverrides.set(te_index, LLGLTFMaterialOverride.fromFullMaterialJSON(json));
1547+
try
1548+
{
1549+
go.TextureEntry.gltfMaterialOverrides.set(te_index, LLGLTFMaterialOverride.fromStoredMaterial(json));
1550+
}
1551+
catch (error: unknown)
1552+
{
1553+
console.error('Failed to parse material override for face ' + String(te_index) + ': ' + String(error));
1554+
}
15481555
}
15491556
}
15501557
if ((prop = Utils.getFromXMLJS(shape, 'PathBegin')) !== undefined)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@caspertech/node-metaverse",
3-
"version": "0.8.8",
3+
"version": "0.8.9",
44
"description": "A node.js interface for Second Life.",
55
"main": "dist/lib/index.js",
66
"types": "dist/lib/index.d.ts",

0 commit comments

Comments
 (0)