Improved gltf support + tests
This commit is contained in:
@@ -60,6 +60,7 @@ export class Caps
|
||||
req.push('FetchInventoryDescendents2');
|
||||
req.push('IncrementCOFVersion');
|
||||
req.push('InterestList');
|
||||
req.push('InventoryThumbnailUpload');
|
||||
req.push('GetDisplayNames');
|
||||
req.push('GetExperiences');
|
||||
req.push('AgentExperiences');
|
||||
@@ -74,9 +75,12 @@ export class Caps
|
||||
req.push('IsExperienceContributor');
|
||||
req.push('RegionExperiences');
|
||||
req.push('ExperienceQuery');
|
||||
req.push('GetMesh');
|
||||
req.push('GetMesh2');
|
||||
req.push('GetMetadata');
|
||||
req.push('GetObjectCost');
|
||||
req.push('GetObjectPhysicsData');
|
||||
req.push('GetTexture');
|
||||
req.push('GroupAPIv1');
|
||||
req.push('GroupMemberData');
|
||||
req.push('GroupProposalBallot');
|
||||
@@ -86,6 +90,7 @@ export class Caps
|
||||
req.push('MapLayer');
|
||||
req.push('MapLayerGod');
|
||||
req.push('MeshUploadFlag');
|
||||
req.push('ModifyMaterialParams');
|
||||
req.push('NavMeshGenerationStatus');
|
||||
req.push('NewFileAgentInventory');
|
||||
req.push('ObjectAnimation');
|
||||
@@ -128,6 +133,8 @@ export class Caps
|
||||
req.push('UpdateSettingsAgentInventory');
|
||||
req.push('UpdateSettingsTaskInventory');
|
||||
req.push('UploadAgentProfileImage');
|
||||
req.push('UpdateMaterialAgentInventory');
|
||||
req.push('UpdateMaterialTaskInventory');
|
||||
req.push('UploadBakedTexture');
|
||||
req.push('UserInfo');
|
||||
req.push('ViewerAsset');
|
||||
|
||||
@@ -117,7 +117,6 @@ export class Circuit
|
||||
};
|
||||
pos.position += packetLength;
|
||||
}
|
||||
console.log('Sent packet ' + packetID + ', ' + packetLength + ' bytes');
|
||||
this.sendMessage(sendXfer, PacketFlags.Reliable);
|
||||
if (final)
|
||||
{
|
||||
@@ -148,7 +147,6 @@ export class Circuit
|
||||
{
|
||||
if (pos.position > -1)
|
||||
{
|
||||
console.log('Packet confirmed, sending next. Position: ' + pos.position);
|
||||
packetID++;
|
||||
this.sendXferPacket(xferID, packetID, data, pos);
|
||||
}
|
||||
@@ -160,7 +158,6 @@ export class Circuit
|
||||
const msg = packet.message as AbortXferMessage;
|
||||
if (msg.XferID.ID.equals(xferID))
|
||||
{
|
||||
console.log('Transfer aborted');
|
||||
subs.unsubscribe();
|
||||
reject(new Error('Transfer aborted'));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,43 @@ export interface LLGLTFTexture
|
||||
|
||||
export type LLGLTFTextureInfo = LLGLTFTexture & LLGLTFExtensionsAndExtras;
|
||||
|
||||
export interface LLGLTFMaterialEntry
|
||||
{
|
||||
name?: string;
|
||||
emissiveFactor?: number[];
|
||||
alphaMode?: string;
|
||||
alphaCutoff?: number;
|
||||
doubleSided?: boolean;
|
||||
pbrMetallicRoughness?: {
|
||||
baseColorFactor?: number[];
|
||||
baseColorTexture?: LLGLTFTextureInfo;
|
||||
metallicRoughnessTexture?: LLGLTFTextureInfo;
|
||||
metallicFactor?: number;
|
||||
roughnessFactor?: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
normalTexture?: {
|
||||
index: number;
|
||||
texCoord?: number;
|
||||
scale?: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
occlusionTexture?: {
|
||||
index: number;
|
||||
texCoord?: number;
|
||||
strength?: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
emissiveTexture?: {
|
||||
extensions?: {
|
||||
KHR_texture_transform?: {
|
||||
offset: number[],
|
||||
rotation: number,
|
||||
scale: number[]
|
||||
}
|
||||
},
|
||||
index: number
|
||||
texCoord?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface LLGLTFMaterialDataPart
|
||||
{
|
||||
asset?: {
|
||||
@@ -95,41 +132,7 @@ export interface LLGLTFMaterialDataPart
|
||||
nodes?: number[];
|
||||
} & LLGLTFExtensionsAndExtras)[];
|
||||
scene?: number;
|
||||
materials?: ({
|
||||
name?: string;
|
||||
emissiveFactor?: number[];
|
||||
alphaMode?: string;
|
||||
alphaCutoff?: number;
|
||||
doubleSided?: boolean;
|
||||
pbrMetallicRoughness?: {
|
||||
baseColorFactor: number[];
|
||||
baseColorTexture?: LLGLTFTextureInfo;
|
||||
metallicRoughnessTexture?: LLGLTFTextureInfo;
|
||||
metallicFactor: number;
|
||||
roughnessFactor: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
normalTexture?: {
|
||||
index: number;
|
||||
texCoord?: number;
|
||||
scale?: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
occlusionTexture?: {
|
||||
index: number;
|
||||
texCoord?: number;
|
||||
strength?: number;
|
||||
} & LLGLTFExtensionsAndExtras,
|
||||
emissiveTexture?: {
|
||||
extensions?: {
|
||||
KHR_texture_transform?: {
|
||||
offset: number[],
|
||||
rotation: number,
|
||||
scale: number[]
|
||||
}
|
||||
},
|
||||
index: number
|
||||
texCoord?: number;
|
||||
}
|
||||
} & LLGLTFExtensionsAndExtras)[];
|
||||
materials?: (LLGLTFMaterialEntry & LLGLTFExtensionsAndExtras)[];
|
||||
images?: (({
|
||||
bufferView: number;
|
||||
mimeType: string;
|
||||
|
||||
239
lib/classes/LLGLTFMaterialOverride.spec.ts
Normal file
239
lib/classes/LLGLTFMaterialOverride.spec.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
import { LLGLTFMaterialOverride } from './LLGLTFMaterialOverride';
|
||||
import * as assert from 'assert';
|
||||
|
||||
|
||||
const m = new LLGLTFMaterialOverride();
|
||||
m.textures = [
|
||||
'a6edc906-2f9f-5fb2-a373-efac406f0ef2',
|
||||
'2f70a4f7-4ece-48d2-8963-32192608067d',
|
||||
'45a45cc0-463c-49dd-9133-5202399a16d4',
|
||||
'39bf5b2b-0619-4892-872c-024e2f601684'
|
||||
];
|
||||
m.doubleSided = true;
|
||||
m.emissiveFactor = [
|
||||
0.1,
|
||||
0.69,
|
||||
0.420
|
||||
];
|
||||
m.alphaCutoff = 0.42;
|
||||
m.alphaMode = 1;
|
||||
m.roughnessFactor = 0.23;
|
||||
m.metallicFactor = 0.91;
|
||||
m.baseColor = [
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4
|
||||
];
|
||||
m.textureTransforms = [
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.2,
|
||||
0.4
|
||||
],
|
||||
offset: [
|
||||
1.0,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
{
|
||||
rotation: 0.52,
|
||||
scale: [
|
||||
0.9,
|
||||
0.1
|
||||
],
|
||||
offset: [
|
||||
0.8,
|
||||
0.3
|
||||
]
|
||||
},
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.1,
|
||||
0.9
|
||||
],
|
||||
offset: [
|
||||
1.3,
|
||||
0.6
|
||||
]
|
||||
},
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.0,
|
||||
0.11
|
||||
],
|
||||
offset: [
|
||||
0.5,
|
||||
0.4
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const m3 = new LLGLTFMaterialOverride();
|
||||
m3.textures = [
|
||||
null,
|
||||
null,
|
||||
'45a45cc0-463c-49dd-9133-5202399a16d4',
|
||||
'39bf5b2b-0619-4892-872c-024e2f601684'
|
||||
];
|
||||
m3.doubleSided = false;
|
||||
m3.emissiveFactor = [
|
||||
0.1,
|
||||
0.69,
|
||||
0.420
|
||||
];
|
||||
m3.alphaCutoff = 0.42;
|
||||
m3.alphaMode = 0;
|
||||
m3.roughnessFactor = 0.23;
|
||||
m3.metallicFactor = 0.91;
|
||||
m3.baseColor = [
|
||||
0.1,
|
||||
0.2,
|
||||
0.3,
|
||||
0.4
|
||||
];
|
||||
m3.textureTransforms = [
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.2,
|
||||
0.4
|
||||
],
|
||||
offset: [
|
||||
1.0,
|
||||
0.5
|
||||
]
|
||||
},
|
||||
null,
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.1,
|
||||
0.9
|
||||
],
|
||||
offset: [
|
||||
1.3,
|
||||
0.6
|
||||
]
|
||||
},
|
||||
{
|
||||
rotation: 0.43,
|
||||
scale: [
|
||||
0.0,
|
||||
0.11
|
||||
],
|
||||
offset: [
|
||||
0.5,
|
||||
0.4
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
describe('LLGLTFMaterialOverride', () =>
|
||||
{
|
||||
it('outputs valid JSON', () =>
|
||||
{
|
||||
assert.equal(m.getFullMaterialJSON(), '{"asset":{"version":"2.0"},"images":[{"uri":"a6edc906-2f9f-5fb2-a373-efac406f0ef2"},{"uri":"45a45cc0-463c-49dd-9133-5202399a16d4"},{"uri":"39bf5b2b-0619-4892-872c-024e2f601684"},{"uri":"2f70a4f7-4ece-48d2-8963-32192608067d"}],"textures":[{"source":0,"extensions":{"KHR_texture_transform":{"offset":[1,0.5],"scale":[0.2,0.4],"rotation":0.43}}},{"source":1,"extensions":{"KHR_texture_transform":{"offset":[1.3,0.6],"scale":[0.1,0.9],"rotation":0.43}}},{"source":2,"extensions":{"KHR_texture_transform":{"offset":[0.5,0.4],"scale":[0,0.11],"rotation":0.43}}},{"source":3,"extensions":{"KHR_texture_transform":{"offset":[0.8,0.3],"scale":[0.9,0.1],"rotation":0.52}}}],"materials":[{"occlusionTexture":{"index":1},"pbrMetallicRoughness":{"baseColorFactor":[0.1,0.2,0.3,0.4],"metallicFactor":0.91,"roughnessFactor":0.23,"baseColorTexture":{"index":0},"metallicRoughnessTexture":{"index":1}},"alphaMode":"BLEND","alphaCutoff":0.42,"emissiveFactor":[0.1,0.69,0.42],"doubleSided":true,"emissiveTexture":{"index":2},"normalTexture":{"index":3}}]}');
|
||||
})
|
||||
|
||||
it('parses json JSON correctly', () =>
|
||||
{
|
||||
let json = m.getFullMaterialJSON();
|
||||
const m2 = LLGLTFMaterialOverride.fromFullMaterialJSON(json);
|
||||
assert.equal(m2.roughnessFactor, m.roughnessFactor);
|
||||
assert.equal(m2.doubleSided, m.doubleSided);
|
||||
assert.equal(m2.alphaCutoff, m.alphaCutoff);
|
||||
assert.equal(m2.alphaMode, m.alphaMode);
|
||||
assert.equal(m2.metallicFactor, m.metallicFactor);
|
||||
assert.equal(m2.baseColor?.length, m.baseColor?.length);
|
||||
assert.equal(m2.baseColor?.[0], m.baseColor?.[0]);
|
||||
assert.equal(m2.baseColor?.[1], m.baseColor?.[1]);
|
||||
assert.equal(m2.baseColor?.[2], m.baseColor?.[2]);
|
||||
assert.equal(m2.baseColor?.[3], m.baseColor?.[3]);
|
||||
assert.equal(m2.emissiveFactor?.length, m.emissiveFactor?.length);
|
||||
assert.equal(m2.emissiveFactor?.[0], m.emissiveFactor?.[0]);
|
||||
assert.equal(m2.emissiveFactor?.[1], m.emissiveFactor?.[1]);
|
||||
assert.equal(m2.emissiveFactor?.[2], m.emissiveFactor?.[2]);
|
||||
assert.equal(m2.textures?.length, m.textures?.length);
|
||||
assert.equal(m2.textures?.[0], m.textures?.[0]);
|
||||
assert.equal(m2.textures?.[1], m.textures?.[1]);
|
||||
assert.equal(m2.textures?.[2], m.textures?.[2]);
|
||||
assert.equal(m2.textures?.[3], m.textures?.[3]);
|
||||
assert.equal(m2.textureTransforms?.length, m.textureTransforms?.length);
|
||||
assert.equal(m2.textureTransforms?.[0]?.offset?.[0], m.textureTransforms?.[0]?.offset?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[0]?.offset?.[1], m.textureTransforms?.[0]?.offset?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[0]?.scale?.[0], m.textureTransforms?.[0]?.scale?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[0]?.scale?.[1], m.textureTransforms?.[0]?.scale?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[0]?.rotation, m.textureTransforms?.[0]?.rotation);
|
||||
|
||||
assert.equal(m2.textureTransforms?.[1]?.offset?.[0], m.textureTransforms?.[1]?.offset?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[1]?.offset?.[1], m.textureTransforms?.[1]?.offset?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[1]?.scale?.[0], m.textureTransforms?.[1]?.scale?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[1]?.scale?.[1], m.textureTransforms?.[1]?.scale?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[1]?.rotation, m.textureTransforms?.[1]?.rotation);
|
||||
|
||||
|
||||
assert.equal(m2.textureTransforms?.[2]?.offset?.[0], m.textureTransforms?.[2]?.offset?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[2]?.offset?.[1], m.textureTransforms?.[2]?.offset?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[2]?.scale?.[0], m.textureTransforms?.[2]?.scale?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[2]?.scale?.[1], m.textureTransforms?.[2]?.scale?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[2]?.rotation, m.textureTransforms?.[2]?.rotation);
|
||||
|
||||
assert.equal(m2.textureTransforms?.[3]?.offset?.[0], m.textureTransforms?.[3]?.offset?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[3]?.offset?.[1], m.textureTransforms?.[3]?.offset?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[3]?.scale?.[0], m.textureTransforms?.[3]?.scale?.[0]);
|
||||
assert.equal(m2.textureTransforms?.[3]?.scale?.[1], m.textureTransforms?.[3]?.scale?.[1]);
|
||||
assert.equal(m2.textureTransforms?.[3]?.rotation, m.textureTransforms?.[3]?.rotation);
|
||||
|
||||
json = m3.getFullMaterialJSON();
|
||||
const m4 = LLGLTFMaterialOverride.fromFullMaterialJSON(json);
|
||||
assert.equal(m4.roughnessFactor, m3.roughnessFactor);
|
||||
assert.equal(m4.doubleSided, m3.doubleSided);
|
||||
assert.equal(m4.alphaCutoff, m3.alphaCutoff);
|
||||
assert.equal(m4.alphaMode, m3.alphaMode);
|
||||
assert.equal(m4.metallicFactor, m3.metallicFactor);
|
||||
assert.equal(m4.baseColor?.length, m3.baseColor?.length);
|
||||
assert.equal(m4.baseColor?.[0], m3.baseColor?.[0]);
|
||||
assert.equal(m4.baseColor?.[1], m3.baseColor?.[1]);
|
||||
assert.equal(m4.baseColor?.[2], m3.baseColor?.[2]);
|
||||
assert.equal(m4.baseColor?.[3], m3.baseColor?.[3]);
|
||||
assert.equal(m4.emissiveFactor?.length, m3.emissiveFactor?.length);
|
||||
assert.equal(m4.emissiveFactor?.[0], m3.emissiveFactor?.[0]);
|
||||
assert.equal(m4.emissiveFactor?.[1], m3.emissiveFactor?.[1]);
|
||||
assert.equal(m4.emissiveFactor?.[2], m3.emissiveFactor?.[2]);
|
||||
assert.equal(m4.textures?.length, m3.textures?.length);
|
||||
assert.equal(m4.textures?.[0], m3.textures?.[0]);
|
||||
assert.equal(m4.textures?.[1], m3.textures?.[1]);
|
||||
assert.equal(m4.textures?.[2], m3.textures?.[2]);
|
||||
assert.equal(m4.textures?.[3], m3.textures?.[3]);
|
||||
assert.equal(m4.textureTransforms?.length, m3.textureTransforms?.length);
|
||||
assert.equal(m4.textureTransforms?.[0]?.offset?.[0], m3.textureTransforms?.[0]?.offset?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[0]?.offset?.[1], m3.textureTransforms?.[0]?.offset?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[0]?.scale?.[0], m3.textureTransforms?.[0]?.scale?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[0]?.scale?.[1], m3.textureTransforms?.[0]?.scale?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[0]?.rotation, m3.textureTransforms?.[0]?.rotation);
|
||||
|
||||
assert.equal(m4.textureTransforms?.[1]?.offset?.[0], m3.textureTransforms?.[1]?.offset?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[1]?.offset?.[1], m3.textureTransforms?.[1]?.offset?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[1]?.scale?.[0], m3.textureTransforms?.[1]?.scale?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[1]?.scale?.[1], m3.textureTransforms?.[1]?.scale?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[1]?.rotation, m3.textureTransforms?.[1]?.rotation);
|
||||
|
||||
|
||||
assert.equal(m4.textureTransforms?.[2]?.offset?.[0], m3.textureTransforms?.[2]?.offset?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[2]?.offset?.[1], m3.textureTransforms?.[2]?.offset?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[2]?.scale?.[0], m3.textureTransforms?.[2]?.scale?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[2]?.scale?.[1], m3.textureTransforms?.[2]?.scale?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[2]?.rotation, m3.textureTransforms?.[2]?.rotation);
|
||||
|
||||
assert.equal(m4.textureTransforms?.[3]?.offset?.[0], m3.textureTransforms?.[3]?.offset?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[3]?.offset?.[1], m3.textureTransforms?.[3]?.offset?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[3]?.scale?.[0], m3.textureTransforms?.[3]?.scale?.[0]);
|
||||
assert.equal(m4.textureTransforms?.[3]?.scale?.[1], m3.textureTransforms?.[3]?.scale?.[1]);
|
||||
assert.equal(m4.textureTransforms?.[3]?.rotation, m3.textureTransforms?.[3]?.rotation);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,397 @@
|
||||
import {
|
||||
LLGLTFExtensionsAndExtras,
|
||||
LLGLTFMaterialData,
|
||||
LLGLTFMaterialEntry,
|
||||
LLGLTFTextureInfo,
|
||||
} from './LLGLTFMaterialData';
|
||||
import { UUID } from './UUID';
|
||||
|
||||
export interface LLGLTFTextureTransformOverride
|
||||
{
|
||||
offset: number[];
|
||||
scale: number[];
|
||||
rotation: number
|
||||
offset?: number[];
|
||||
scale?: number[];
|
||||
rotation?: number
|
||||
}
|
||||
|
||||
export class LLGLTFMaterialOverride
|
||||
{
|
||||
public textures?: string[];
|
||||
public textures?: (string | null)[];
|
||||
public baseColor?: number[];
|
||||
public emissiveColor?: number[];
|
||||
public emissiveFactor?: number[];
|
||||
public metallicFactor?: number;
|
||||
public roughnessFactor?: number;
|
||||
public alphaMode?: number;
|
||||
public alphaCutoff?: number;
|
||||
public doubleSided?: boolean;
|
||||
public textureTransforms?: LLGLTFTextureTransformOverride[];
|
||||
public textureTransforms?: (LLGLTFTextureTransformOverride | null)[];
|
||||
|
||||
public getFullMaterialJSON(): string
|
||||
{
|
||||
const obj: LLGLTFMaterialData = {};
|
||||
obj.asset = {
|
||||
version: '2.0',
|
||||
};
|
||||
|
||||
let texIndex = 0;
|
||||
|
||||
const material: LLGLTFMaterialEntry & LLGLTFExtensionsAndExtras = {};
|
||||
|
||||
const addTexture = (texNum: number): number | undefined =>
|
||||
{
|
||||
let idx: number | undefined = undefined;
|
||||
if ((this.textures && this.textures.length > texNum && this.textures[texNum] !== null) || (this.textureTransforms && this.textureTransforms.length > texNum && this.textureTransforms[texNum] !== null))
|
||||
{
|
||||
idx = texIndex++;
|
||||
if (idx === 0)
|
||||
{
|
||||
obj.images = [];
|
||||
obj.textures = [];
|
||||
}
|
||||
|
||||
const texture = this.textures?.[texNum];
|
||||
if (texture)
|
||||
{
|
||||
obj.images!.push({
|
||||
uri: texture
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.images!.push({
|
||||
uri: UUID.zero().toString()
|
||||
});
|
||||
}
|
||||
|
||||
const tex: {
|
||||
source: number
|
||||
} & LLGLTFExtensionsAndExtras = {
|
||||
source: idx
|
||||
};
|
||||
|
||||
if (this.textureTransforms && this.textureTransforms.length > texNum && this.textureTransforms[texNum] !== null)
|
||||
{
|
||||
const trans = this.textureTransforms[texNum];
|
||||
tex.extensions = {
|
||||
KHR_texture_transform: {
|
||||
offset: trans?.offset ?? undefined,
|
||||
scale: trans?.scale ?? undefined,
|
||||
rotation: trans?.rotation ?? undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (obj.textures === undefined)
|
||||
{
|
||||
obj.textures = [
|
||||
tex
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.textures.push(tex);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
if (
|
||||
this.baseColor !== undefined
|
||||
|| (this.textures !== undefined
|
||||
&& ((this.textures.length > 0
|
||||
&& this.textures[0] !== undefined
|
||||
)
|
||||
|| (this.textures.length > 2
|
||||
&& this.textures[2] !== undefined
|
||||
)))
|
||||
|| this.metallicFactor !== undefined
|
||||
|| this.roughnessFactor !== undefined
|
||||
)
|
||||
{
|
||||
const pbrMetallicRoughness: {
|
||||
baseColorFactor?: number[];
|
||||
baseColorTexture?: LLGLTFTextureInfo;
|
||||
metallicRoughnessTexture?: LLGLTFTextureInfo;
|
||||
metallicFactor?: number;
|
||||
roughnessFactor?: number;
|
||||
} & LLGLTFExtensionsAndExtras = {
|
||||
baseColorFactor: this.baseColor,
|
||||
metallicFactor: this.metallicFactor,
|
||||
roughnessFactor: this.roughnessFactor
|
||||
};
|
||||
|
||||
|
||||
let texIdx2 = addTexture(0);
|
||||
if (texIdx2 !== undefined)
|
||||
{
|
||||
pbrMetallicRoughness.baseColorTexture = {
|
||||
index: texIdx2
|
||||
};
|
||||
}
|
||||
|
||||
texIdx2 = addTexture(2);
|
||||
if (texIdx2 !== undefined)
|
||||
{
|
||||
pbrMetallicRoughness.metallicRoughnessTexture = {
|
||||
index: texIdx2
|
||||
};
|
||||
|
||||
material.occlusionTexture = {
|
||||
index: texIdx2
|
||||
};
|
||||
}
|
||||
|
||||
material.pbrMetallicRoughness = pbrMetallicRoughness;
|
||||
}
|
||||
|
||||
if (this.alphaMode !== undefined)
|
||||
{
|
||||
if (this.alphaMode === 0) // OPAQUE
|
||||
{
|
||||
material.extras = {
|
||||
override_alpha_mode: true
|
||||
};
|
||||
}
|
||||
else if (this.alphaMode === 1)
|
||||
{
|
||||
material.alphaMode = 'BLEND';
|
||||
}
|
||||
else if (this.alphaMode === 2)
|
||||
{
|
||||
material.alphaMode = 'MASK';
|
||||
}
|
||||
}
|
||||
|
||||
if (this.alphaCutoff !== undefined)
|
||||
{
|
||||
material.alphaCutoff = this.alphaCutoff;
|
||||
}
|
||||
|
||||
if (this.emissiveFactor !== undefined)
|
||||
{
|
||||
material.emissiveFactor = this.emissiveFactor;
|
||||
}
|
||||
|
||||
if (this.doubleSided)
|
||||
{
|
||||
material.doubleSided = this.doubleSided;
|
||||
}
|
||||
else if (this.doubleSided === false)
|
||||
{
|
||||
if (!material.extras)
|
||||
{
|
||||
material.extras = {};
|
||||
}
|
||||
material.extras.override_double_sided = true;
|
||||
}
|
||||
|
||||
// Emissive Texture
|
||||
let texIdx = addTexture(3);
|
||||
if (texIdx !== undefined)
|
||||
{
|
||||
material.emissiveTexture = {
|
||||
index: texIdx
|
||||
};
|
||||
}
|
||||
|
||||
// Normal Map Texture
|
||||
texIdx = addTexture(1);
|
||||
if (texIdx !== undefined)
|
||||
{
|
||||
material.normalTexture = {
|
||||
index: texIdx
|
||||
};
|
||||
}
|
||||
|
||||
if (Object.keys(material).length > 0)
|
||||
{
|
||||
obj.materials = [
|
||||
material
|
||||
];
|
||||
}
|
||||
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
public setTexture(idx: number, uuid: string): void
|
||||
{
|
||||
if (!this.textures)
|
||||
{
|
||||
this.textures = [];
|
||||
}
|
||||
for (let x = this.textures.length; x < idx + 1; x++)
|
||||
{
|
||||
this.textures.push(null);
|
||||
}
|
||||
this.textures[idx] = uuid;
|
||||
}
|
||||
|
||||
public setTransform(idx: number, trans: LLGLTFTextureTransformOverride): void
|
||||
{
|
||||
if (!this.textureTransforms)
|
||||
{
|
||||
this.textureTransforms = [];
|
||||
}
|
||||
for (let x = this.textureTransforms.length; x < idx + 1; x++)
|
||||
{
|
||||
this.textureTransforms.push(null);
|
||||
}
|
||||
this.textureTransforms[idx] = trans;
|
||||
}
|
||||
|
||||
public static fromFullMaterialJSON(json: string): LLGLTFMaterialOverride
|
||||
{
|
||||
const obj = JSON.parse(json) as LLGLTFMaterialData;
|
||||
|
||||
const over = new LLGLTFMaterialOverride();
|
||||
|
||||
if (!obj.materials?.length)
|
||||
{
|
||||
return over;
|
||||
}
|
||||
const mat = obj.materials[0];
|
||||
|
||||
const getTexture = (idx: number): { uuid: string | null, transform: LLGLTFTextureTransformOverride | null } =>
|
||||
{
|
||||
const found: {
|
||||
uuid: string | null,
|
||||
transform: LLGLTFTextureTransformOverride | null
|
||||
} = {
|
||||
uuid: null,
|
||||
transform: null
|
||||
};
|
||||
|
||||
if (obj.textures && Array.isArray(obj.textures) && obj.textures.length > idx)
|
||||
{
|
||||
const source = obj.textures[idx].source;
|
||||
if (source !== undefined && obj.images && Array.isArray(obj.images) && obj.images.length > source)
|
||||
{
|
||||
const img = obj.images[source];
|
||||
if ('uri' in img)
|
||||
{
|
||||
found.uuid = img.uri ?? null;
|
||||
if (found.uuid === UUID.zero().toString())
|
||||
{
|
||||
found.uuid = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
const transform = obj.textures[idx].extensions?.KHR_texture_transform as {
|
||||
offset?: number[],
|
||||
scale?: number[],
|
||||
rotation?: number
|
||||
};
|
||||
if (transform)
|
||||
{
|
||||
found.transform = transform ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
};
|
||||
|
||||
if (mat.pbrMetallicRoughness)
|
||||
{
|
||||
const pbr = mat.pbrMetallicRoughness;
|
||||
if (pbr.metallicFactor !== undefined)
|
||||
{
|
||||
over.metallicFactor = pbr.metallicFactor;
|
||||
}
|
||||
if (pbr.roughnessFactor !== undefined)
|
||||
{
|
||||
over.roughnessFactor = pbr.roughnessFactor;
|
||||
}
|
||||
if (pbr.baseColorFactor !== undefined && Array.isArray(pbr.baseColorFactor) && pbr.baseColorFactor.length === 4)
|
||||
{
|
||||
over.baseColor = pbr.baseColorFactor;
|
||||
}
|
||||
if (pbr.baseColorTexture?.index !== undefined)
|
||||
{
|
||||
const tex = getTexture(pbr.baseColorTexture.index);
|
||||
if (tex && tex.uuid)
|
||||
{
|
||||
over.setTexture(0, tex.uuid);
|
||||
}
|
||||
if (tex && tex.transform)
|
||||
{
|
||||
over.setTransform(0, tex.transform);
|
||||
}
|
||||
}
|
||||
if (pbr.metallicRoughnessTexture?.index !== undefined)
|
||||
{
|
||||
const tex = getTexture(pbr.metallicRoughnessTexture.index);
|
||||
if (tex && tex.uuid)
|
||||
{
|
||||
over.setTexture(2, tex.uuid);
|
||||
}
|
||||
if (tex && tex.transform)
|
||||
{
|
||||
over.setTransform(2, tex.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mat.alphaMode)
|
||||
{
|
||||
switch (mat.alphaMode)
|
||||
{
|
||||
case 'BLEND':
|
||||
over.alphaMode = 1;
|
||||
break;
|
||||
case 'MASK':
|
||||
over.alphaMode = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (mat.extras && mat.extras.override_alpha_mode)
|
||||
{
|
||||
over.alphaMode = 0;
|
||||
}
|
||||
|
||||
if (mat.alphaCutoff !== undefined)
|
||||
{
|
||||
over.alphaCutoff = mat.alphaCutoff;
|
||||
}
|
||||
|
||||
if (mat.emissiveFactor !== undefined)
|
||||
{
|
||||
over.emissiveFactor = mat.emissiveFactor;
|
||||
}
|
||||
|
||||
if (mat.doubleSided === true)
|
||||
{
|
||||
over.doubleSided = true;
|
||||
}
|
||||
else if (mat.extras && mat.extras.override_double_sided)
|
||||
{
|
||||
over.doubleSided = false;
|
||||
}
|
||||
|
||||
if (mat.normalTexture?.index !== undefined)
|
||||
{
|
||||
const tex = getTexture(mat.normalTexture?.index);
|
||||
if (tex && tex.uuid)
|
||||
{
|
||||
over.setTexture(1, tex.uuid);
|
||||
}
|
||||
if (tex && tex.transform)
|
||||
{
|
||||
over.setTransform(1, tex.transform);
|
||||
}
|
||||
}
|
||||
|
||||
if (mat.emissiveTexture?.index !== undefined)
|
||||
{
|
||||
const tex = getTexture(mat.emissiveTexture?.index);
|
||||
if (tex && tex.uuid)
|
||||
{
|
||||
over.setTexture(3, tex.uuid);
|
||||
}
|
||||
if (tex && tex.transform)
|
||||
{
|
||||
over.setTransform(3, tex.transform);
|
||||
}
|
||||
}
|
||||
|
||||
return over;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ export class ObjectStoreLite implements IObjectStore
|
||||
|
||||
if (emissiveColor !== undefined && Array.isArray(emissiveColor) && emissiveColor.length === 3 && isNumberArray(emissiveColor))
|
||||
{
|
||||
override.emissiveColor = emissiveColor;
|
||||
override.emissiveFactor = emissiveColor;
|
||||
}
|
||||
|
||||
if (metallicFactor !== undefined && typeof metallicFactor === 'number')
|
||||
@@ -242,9 +242,17 @@ export class ObjectStoreLite implements IObjectStore
|
||||
override.textureTransforms = [];
|
||||
for (const transform of textureTransforms)
|
||||
{
|
||||
if (isLLGLTFTextureTransformOverride(transform))
|
||||
if (transform instanceof LLSDMap)
|
||||
{
|
||||
override.textureTransforms.push(transform);
|
||||
const tObj = {
|
||||
offset: transform.get('o'),
|
||||
scale: transform.get('s'),
|
||||
rotation: transform.get('r')
|
||||
}
|
||||
if (isLLGLTFTextureTransformOverride(tObj))
|
||||
{
|
||||
override.textureTransforms.push(tObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('GameObject', () =>
|
||||
'1e079cce-eeca-4e05-9a4f-e58d8398ecf1',
|
||||
'03573ae5-4c1a-44f7-9cd3-8b49028f9e48'
|
||||
];
|
||||
override.emissiveColor = [0.2, 0.5, 0.6];
|
||||
override.emissiveFactor = [0.2, 0.5, 0.6];
|
||||
override.baseColor = [0.1, 0.2, 0.3, 0.4];
|
||||
override.textureTransforms = [
|
||||
{
|
||||
@@ -94,12 +94,12 @@ describe('GameObject', () =>
|
||||
{
|
||||
assert(false, 'Textures is not an array');
|
||||
}
|
||||
if (Array.isArray(entry.emissiveColor))
|
||||
if (Array.isArray(entry.emissiveFactor))
|
||||
{
|
||||
assert.equal(entry.emissiveColor.length, 3);
|
||||
assert.equal(entry.emissiveColor[0], 0.2);
|
||||
assert.equal(entry.emissiveColor[1], 0.5);
|
||||
assert.equal(entry.emissiveColor[2], 0.6);
|
||||
assert.equal(entry.emissiveFactor.length, 3);
|
||||
assert.equal(entry.emissiveFactor[0], 0.2);
|
||||
assert.equal(entry.emissiveFactor[1], 0.5);
|
||||
assert.equal(entry.emissiveFactor[2], 0.6);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -123,7 +123,7 @@ describe('GameObject', () =>
|
||||
for (let x = 0; x < 4; x++)
|
||||
{
|
||||
const transform = entry.textureTransforms[x];
|
||||
if (Array.isArray(transform.scale))
|
||||
if (transform?.scale && Array.isArray(transform.scale))
|
||||
{
|
||||
assert.equal(transform.scale.length, 2);
|
||||
assert.equal(transform.scale[0], 0.5);
|
||||
@@ -133,7 +133,7 @@ describe('GameObject', () =>
|
||||
{
|
||||
assert(false, 'Scale is not an array');
|
||||
}
|
||||
if (Array.isArray(transform.offset))
|
||||
if (transform?.offset && Array.isArray(transform.offset))
|
||||
{
|
||||
assert.equal(transform.offset.length, 2);
|
||||
assert.equal(transform.offset[0], 0.1);
|
||||
|
||||
@@ -55,7 +55,7 @@ import { Subject } from 'rxjs';
|
||||
import { RezScriptMessage } from '../messages/RezScript';
|
||||
import { PermissionMask } from '../../enums/PermissionMask';
|
||||
import { AssetType } from '../../enums/AssetType';
|
||||
import { LLGLTFMaterialOverride, LLGLTFTextureTransformOverride } from '../LLGLTFMaterialOverride';
|
||||
import { LLGLTFMaterialOverride } from '../LLGLTFMaterialOverride';
|
||||
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
@@ -381,123 +381,19 @@ export class GameObject implements IGameObjectData
|
||||
const buf = Buffer.from(prop, 'base64');
|
||||
go.TextureEntry = TextureEntry.from(buf);
|
||||
}
|
||||
if (go.TextureEntry && shape['GLTFMaterialOverrides'] && Array.isArray(shape['GLTFMaterialOverrides']) && shape['GLTFMaterialOverrides'].length > 0)
|
||||
if (go.TextureEntry && shape['MatOvrd'] && Array.isArray(shape['MatOvrd']) && shape['MatOvrd'].length > 0)
|
||||
{
|
||||
const te = go.TextureEntry;
|
||||
te.gltfMaterialOverrides = new Map<number, LLGLTFMaterialOverride>();
|
||||
const children = shape['GLTFMaterialOverrides'][0];
|
||||
const childObj = children['GLTFMaterialOverride'];
|
||||
if (childObj)
|
||||
const tex = Buffer.from(shape['MatOvrd'][0], 'base64');
|
||||
let pos = 0;
|
||||
const entryCount = tex.readUInt8(pos++);
|
||||
for (let x = 0; x < entryCount; x++)
|
||||
{
|
||||
for (const entry of childObj)
|
||||
{
|
||||
const override = new LLGLTFMaterialOverride();
|
||||
let textureEntry = 0;
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'TextureEntry')) !== undefined)
|
||||
{
|
||||
textureEntry = prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'DoubleSided')) !== undefined)
|
||||
{
|
||||
override.doubleSided = prop;
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'AlphaCutoff')) !== undefined)
|
||||
{
|
||||
override.alphaCutoff = parseFloat(prop);
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'RoughnessFactor')) !== undefined)
|
||||
{
|
||||
override.roughnessFactor = parseFloat(prop);
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'MetallicFactor')) !== undefined)
|
||||
{
|
||||
override.metallicFactor = parseFloat(prop);
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(entry, 'AlphaMode')) !== undefined)
|
||||
{
|
||||
override.alphaMode = prop;
|
||||
}
|
||||
if (entry['Textures'] && Array.isArray(entry['Textures']) && entry['Textures'].length > 0)
|
||||
{
|
||||
override.textures = [];
|
||||
const childArr = entry['Textures'][0];
|
||||
for (const tex of childArr['UUID'])
|
||||
{
|
||||
override.textures.push(tex);
|
||||
}
|
||||
}
|
||||
if (entry['EmissiveColor'] && Array.isArray(entry['EmissiveColor']) && entry['EmissiveColor'].length > 0)
|
||||
{
|
||||
const childArr = entry['EmissiveColor'][0];
|
||||
const red = parseFloat(childArr['R'][0]);
|
||||
const green = parseFloat(childArr['G'][0]);
|
||||
const blue = parseFloat(childArr['B'][0]);
|
||||
override.emissiveColor = [
|
||||
red,
|
||||
green,
|
||||
blue
|
||||
];
|
||||
}
|
||||
if (entry['BaseColor'] && Array.isArray(entry['BaseColor']) && entry['BaseColor'].length > 0)
|
||||
{
|
||||
const childArr = entry['BaseColor'][0];
|
||||
const red = parseFloat(childArr['R'][0]);
|
||||
const green = parseFloat(childArr['G'][0]);
|
||||
const blue = parseFloat(childArr['B'][0]);
|
||||
const alpha = parseFloat(childArr['A'][0]);
|
||||
override.baseColor = [
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha
|
||||
];
|
||||
}
|
||||
if (entry['TextureTransforms'] && Array.isArray(entry['TextureTransforms']) && entry['TextureTransforms'].length > 0)
|
||||
{
|
||||
const childArr = entry['TextureTransforms'][0];
|
||||
override.textureTransforms = [];
|
||||
for (const tex of childArr['Transform'])
|
||||
{
|
||||
const t: LLGLTFTextureTransformOverride = {
|
||||
offset: [],
|
||||
scale: [],
|
||||
rotation: 0,
|
||||
};
|
||||
|
||||
if ((prop = Utils.getFromXMLJS(tex, 'Rotation')) !== undefined)
|
||||
{
|
||||
t.rotation = parseFloat(prop);
|
||||
}
|
||||
if (tex['Offsets'] && Array.isArray(tex['Offsets']) && tex['Offsets'].length > 0)
|
||||
{
|
||||
const offsetArr = tex['Offsets'][0];
|
||||
const xOffset = parseFloat(offsetArr['X'][0]);
|
||||
const yOffset = parseFloat(offsetArr['Y'][0]);
|
||||
t.offset = [
|
||||
xOffset,
|
||||
yOffset
|
||||
];
|
||||
}
|
||||
if (tex['Scale'] && Array.isArray(tex['Scale']) && tex['Scale'].length > 0)
|
||||
{
|
||||
const offsetArr = tex['Scale'][0];
|
||||
const xOffset = parseFloat(offsetArr['X'][0]);
|
||||
const yOffset = parseFloat(offsetArr['Y'][0]);
|
||||
t.scale = [
|
||||
xOffset,
|
||||
yOffset
|
||||
];
|
||||
}
|
||||
|
||||
override.textureTransforms.push(t);
|
||||
}
|
||||
}
|
||||
te.gltfMaterialOverrides.set(textureEntry, override);
|
||||
}
|
||||
const te_index = tex.readUInt8(pos++);
|
||||
const len = tex.readUInt16LE(pos++);
|
||||
pos++;
|
||||
const json = tex.slice(pos, pos + len).toString('utf-8');
|
||||
pos = pos + len;
|
||||
go.TextureEntry.gltfMaterialOverrides.set(te_index, LLGLTFMaterialOverride.fromFullMaterialJSON(json));
|
||||
}
|
||||
}
|
||||
if ((prop = Utils.getFromXMLJS(shape, 'PathBegin')) !== undefined)
|
||||
@@ -1661,75 +1557,33 @@ export class GameObject implements IGameObjectData
|
||||
|
||||
if (this.TextureEntry.gltfMaterialOverrides)
|
||||
{
|
||||
const overrides = shape.ele('GLTFMaterialOverrides');
|
||||
for (const te of this.TextureEntry.gltfMaterialOverrides.keys())
|
||||
{
|
||||
const entry = overrides.ele('GLTFMaterialOverride');
|
||||
entry.ele('TextureEntry', te);
|
||||
const override = this.TextureEntry.gltfMaterialOverrides.get(te);
|
||||
if (override)
|
||||
{
|
||||
if (override.doubleSided !== undefined)
|
||||
{
|
||||
entry.ele('DoubleSided', override.doubleSided);
|
||||
}
|
||||
if (override.alphaCutoff !== undefined)
|
||||
{
|
||||
entry.ele('AlphaCutoff', override.alphaCutoff);
|
||||
}
|
||||
if (override.roughnessFactor !== undefined)
|
||||
{
|
||||
entry.ele('RoughnessFactor', override.roughnessFactor);
|
||||
}
|
||||
if (override.metallicFactor !== undefined)
|
||||
{
|
||||
entry.ele('MetallicFactor', override.metallicFactor);
|
||||
}
|
||||
if (override.alphaMode !== undefined)
|
||||
{
|
||||
entry.ele('AlphaMode', override.alphaMode);
|
||||
}
|
||||
if (override.textures !== undefined)
|
||||
{
|
||||
const texs = entry.ele('Textures');
|
||||
for (const tex of override.textures)
|
||||
{
|
||||
texs.ele('UUID', tex);
|
||||
}
|
||||
}
|
||||
if (override.emissiveColor !== undefined && override.emissiveColor.length === 3)
|
||||
{
|
||||
const emissive = entry.ele('EmissiveColor');
|
||||
emissive.ele('R', override.emissiveColor[0]);
|
||||
emissive.ele('G', override.emissiveColor[1]);
|
||||
emissive.ele('B', override.emissiveColor[2]);
|
||||
}
|
||||
if (override.baseColor !== undefined && override.baseColor.length === 4)
|
||||
{
|
||||
const base = entry.ele('BaseColor');
|
||||
base.ele('R', override.baseColor[0]);
|
||||
base.ele('G', override.baseColor[1]);
|
||||
base.ele('B', override.baseColor[2]);
|
||||
base.ele('A', override.baseColor[3]);
|
||||
}
|
||||
if (override.textureTransforms && override.textureTransforms.length === 4)
|
||||
{
|
||||
const transforms = entry.ele('TextureTransforms');
|
||||
for (const trans of override.textureTransforms)
|
||||
{
|
||||
const tfm = transforms.ele('Transform');
|
||||
tfm.ele('Rotation', trans.rotation);
|
||||
const overrideKeys = Array.from(this.TextureEntry.gltfMaterialOverrides.keys());
|
||||
const numEntries = overrideKeys.length;
|
||||
|
||||
const offsets = tfm.ele('Offsets');
|
||||
offsets.ele('X', trans.offset[0]);
|
||||
offsets.ele('Y', trans.offset[1]);
|
||||
if (numEntries > 0)
|
||||
{
|
||||
const buf: Buffer[] = [];
|
||||
|
||||
const scale = tfm.ele('Scale');
|
||||
scale.ele('X', trans.scale[0]);
|
||||
scale.ele('Y', trans.scale[1]);
|
||||
}
|
||||
const num = Buffer.allocUnsafe(1);
|
||||
num.writeUInt8(numEntries, 0);
|
||||
buf.push(num)
|
||||
for (const overrideKey of overrideKeys)
|
||||
{
|
||||
const override = this.TextureEntry.gltfMaterialOverrides.get(overrideKey);
|
||||
if (override === undefined)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const header = Buffer.allocUnsafe(3);
|
||||
header.writeUInt8(overrideKey, 0);
|
||||
|
||||
const json = override.getFullMaterialJSON();
|
||||
header.writeUInt16LE(json.length, 1);
|
||||
buf.push(header);
|
||||
buf.push(Buffer.from(json, 'utf-8'));
|
||||
}
|
||||
shape.ele('MatOvrd', Buffer.concat(buf).toString('base64'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@caspertech/node-metaverse",
|
||||
"version": "0.6.6",
|
||||
"version": "0.6.7",
|
||||
"description": "A node.js interface for Second Life.",
|
||||
"main": "dist/lib/index.js",
|
||||
"types": "dist/lib/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user