- Mesh upload support
- LLMesh asset decoding and encoding (inc. LLPhysicsConvex, LLSkin, LLSubMesh) - Query inventory folder by type - onSelectedObject event - fetchInventoryItem command - Fix packing/unpacking of object shape - Time sync with SimulatorViewerTimeMessage - Changed several classes to a .from style rather than setting up in the constructor (exception friendly) - Whole bunch of other improvements - Object building
This commit is contained in:
@@ -5,9 +5,9 @@ import {Utils} from './Utils';
|
||||
|
||||
export class TextureEntry
|
||||
{
|
||||
static MAX_UINT32 = 4294967295;
|
||||
defaultTexture: TextureEntryFace | null;
|
||||
faces: TextureEntryFace[] = [];
|
||||
binary: Buffer;
|
||||
|
||||
static readFaceBitfield(buf: Buffer, pos: number): {
|
||||
result: boolean,
|
||||
@@ -27,9 +27,19 @@ export class TextureEntry
|
||||
return result;
|
||||
}
|
||||
let b = 0;
|
||||
let outputValue = false;
|
||||
let str = '0x';
|
||||
do
|
||||
{
|
||||
b = buf.readUInt8(result.pos);
|
||||
if (b === 0x81)
|
||||
{
|
||||
outputValue = true;
|
||||
}
|
||||
if (outputValue)
|
||||
{
|
||||
str += b.toString(16);
|
||||
}
|
||||
result.faceBits = (result.faceBits << 7) | (b & 0x7F);
|
||||
result.bitfieldSize += 7;
|
||||
result.pos++;
|
||||
@@ -39,22 +49,51 @@ export class TextureEntry
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor(buf: Buffer)
|
||||
static getFaceBitfieldBuffer(bitfield: number): Buffer
|
||||
{
|
||||
this.binary = buf;
|
||||
let byteLength = 0;
|
||||
let tmpBitfield = bitfield;
|
||||
while (tmpBitfield !== 0)
|
||||
{
|
||||
tmpBitfield >>= 7;
|
||||
byteLength++;
|
||||
}
|
||||
|
||||
|
||||
if (byteLength === 0)
|
||||
{
|
||||
const buf = Buffer.allocUnsafe(1);
|
||||
buf[0] = 0;
|
||||
return buf;
|
||||
}
|
||||
const bytes = Buffer.allocUnsafe(byteLength);
|
||||
for (let i = 0; i < byteLength; i++)
|
||||
{
|
||||
bytes[i] = ((bitfield >> (7 * (byteLength - i - 1))) & 0x7F);
|
||||
if (i < byteLength - 1)
|
||||
{
|
||||
bytes[i] |= 0x80;
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static from(buf: Buffer)
|
||||
{
|
||||
const te = new TextureEntry();
|
||||
if (buf.length < 16)
|
||||
{
|
||||
this.defaultTexture = null;
|
||||
te.defaultTexture = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.defaultTexture = new TextureEntryFace(null);
|
||||
te.defaultTexture = new TextureEntryFace(null);
|
||||
const pos = 0;
|
||||
let i = pos;
|
||||
|
||||
// Texture
|
||||
{
|
||||
this.defaultTexture.textureID = new UUID(buf, i);
|
||||
te.defaultTexture.textureID = new UUID(buf, i);
|
||||
i += 16;
|
||||
|
||||
let done = false;
|
||||
@@ -71,8 +110,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].textureID = uuid;
|
||||
te.createFace(face);
|
||||
te.faces[face].textureID = uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +120,7 @@ export class TextureEntry
|
||||
|
||||
// Colour
|
||||
{
|
||||
this.defaultTexture.rgba = new Color4(buf, i, true);
|
||||
te.defaultTexture.rgba = new Color4(buf, i, true);
|
||||
i += 4;
|
||||
|
||||
let done = false;
|
||||
@@ -98,8 +137,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].rgba = tmpColor;
|
||||
te.createFace(face);
|
||||
te.faces[face].rgba = tmpColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +147,7 @@ export class TextureEntry
|
||||
|
||||
// RepeatU
|
||||
{
|
||||
this.defaultTexture.repeatU = buf.readFloatLE(i);
|
||||
te.defaultTexture.repeatU = buf.readFloatLE(i);
|
||||
i += 4;
|
||||
|
||||
let done = false;
|
||||
@@ -125,8 +164,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].repeatU = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].repeatU = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +174,7 @@ export class TextureEntry
|
||||
|
||||
// RepeatV
|
||||
{
|
||||
this.defaultTexture.repeatV = buf.readFloatLE(i);
|
||||
te.defaultTexture.repeatV = buf.readFloatLE(i);
|
||||
i += 4;
|
||||
|
||||
let done = false;
|
||||
@@ -152,8 +191,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].repeatV = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].repeatV = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,7 +201,7 @@ export class TextureEntry
|
||||
|
||||
// OffsetU
|
||||
{
|
||||
this.defaultTexture.offsetU = Utils.ReadOffsetFloat(buf, i);
|
||||
te.defaultTexture.offsetU = Utils.ReadOffsetFloat(buf, i);
|
||||
i += 2;
|
||||
|
||||
let done = false;
|
||||
@@ -179,8 +218,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].offsetU = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].offsetU = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,7 +228,7 @@ export class TextureEntry
|
||||
|
||||
// OffsetV
|
||||
{
|
||||
this.defaultTexture.offsetV = Utils.ReadOffsetFloat(buf, i);
|
||||
te.defaultTexture.offsetV = Utils.ReadOffsetFloat(buf, i);
|
||||
i += 2;
|
||||
|
||||
let done = false;
|
||||
@@ -206,8 +245,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].offsetV = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].offsetV = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +255,7 @@ export class TextureEntry
|
||||
|
||||
// Rotation
|
||||
{
|
||||
this.defaultTexture.rotation = Utils.ReadRotationFloat(buf, i);
|
||||
te.defaultTexture.rotation = Utils.ReadRotationFloat(buf, i);
|
||||
i += 2;
|
||||
|
||||
let done = false;
|
||||
@@ -233,8 +272,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].rotation = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].rotation = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +282,7 @@ export class TextureEntry
|
||||
|
||||
// Material
|
||||
{
|
||||
this.defaultTexture.material = buf[i++];
|
||||
te.defaultTexture.material = buf[i++];
|
||||
|
||||
let done = false;
|
||||
while (!done)
|
||||
@@ -258,8 +297,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].material = tmpByte;
|
||||
te.createFace(face);
|
||||
te.faces[face].material = tmpByte;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +307,7 @@ export class TextureEntry
|
||||
|
||||
// Media
|
||||
{
|
||||
this.defaultTexture.media = buf[i++];
|
||||
te.defaultTexture.media = buf[i++];
|
||||
|
||||
let done = false;
|
||||
while (i - pos < buf.length && !done)
|
||||
@@ -283,8 +322,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].media = tmpByte;
|
||||
te.createFace(face);
|
||||
te.faces[face].media = tmpByte;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,7 +332,7 @@ export class TextureEntry
|
||||
|
||||
// Glow
|
||||
{
|
||||
this.defaultTexture.glow = Utils.ReadGlowFloat(buf, i++);
|
||||
te.defaultTexture.glow = Utils.ReadGlowFloat(buf, i++);
|
||||
|
||||
let done = false;
|
||||
while (!done)
|
||||
@@ -308,8 +347,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].glow = tmpFloat;
|
||||
te.createFace(face);
|
||||
te.faces[face].glow = tmpFloat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +360,7 @@ export class TextureEntry
|
||||
const len = i - pos + 16;
|
||||
if (i - pos + 16 <= buf.length)
|
||||
{
|
||||
this.defaultTexture.materialID = new UUID(buf, i);
|
||||
te.defaultTexture.materialID = new UUID(buf, i);
|
||||
i += 16;
|
||||
|
||||
let done = false;
|
||||
@@ -338,8 +377,8 @@ export class TextureEntry
|
||||
{
|
||||
if ((result.faceBits & bit) !== 0)
|
||||
{
|
||||
this.createFace(face);
|
||||
this.faces[face].materialID = uuid;
|
||||
te.createFace(face);
|
||||
te.faces[face].materialID = uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,6 +386,11 @@ export class TextureEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
return te;
|
||||
}
|
||||
|
||||
constructor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -361,4 +405,235 @@ export class TextureEntry
|
||||
this.faces.push(new TextureEntryFace(this.defaultTexture));
|
||||
}
|
||||
}
|
||||
|
||||
toBuffer(): Buffer
|
||||
{
|
||||
if (this.defaultTexture === null)
|
||||
{
|
||||
return Buffer.allocUnsafe(0);
|
||||
}
|
||||
const textures: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const rgbas: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const repeatus: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const repeatvs: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const offsetus: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const offsetvs: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const rotations: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const materials: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const medias: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const glows: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
const materialIDs: number[] = Utils.fillArray<number>(TextureEntry.MAX_UINT32, this.faces.length);
|
||||
|
||||
for (let i = 0; i < this.faces.length; i++)
|
||||
{
|
||||
if (this.faces[i] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.faces[i].textureID.equals(this.defaultTexture.textureID))
|
||||
{
|
||||
if (textures[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
textures[i] = 0;
|
||||
}
|
||||
textures[i] |= (1 << i);
|
||||
}
|
||||
if (!this.faces[i].rgba.equals(this.defaultTexture.rgba))
|
||||
{
|
||||
if (rgbas[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
rgbas[i] = 0;
|
||||
}
|
||||
rgbas[i] |= (1 << i);
|
||||
}
|
||||
if (this.faces[i].repeatU !== this.defaultTexture.repeatU)
|
||||
{
|
||||
if (repeatus[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
repeatus[i] = 0;
|
||||
}
|
||||
repeatus[i] |= (1 << i);
|
||||
}
|
||||
if (this.faces[i].repeatV !== this.defaultTexture.repeatV)
|
||||
{
|
||||
if (repeatvs[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
repeatvs[i] = 0;
|
||||
}
|
||||
repeatvs[i] |= (1 << i);
|
||||
}
|
||||
if (Utils.TEOffsetShort(this.faces[i].offsetU) !== Utils.TEOffsetShort(this.defaultTexture.offsetU))
|
||||
{
|
||||
if (offsetus[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
offsetus[i] = 0;
|
||||
}
|
||||
offsetus[i] |= (1 << i);
|
||||
}
|
||||
if (Utils.TEOffsetShort(this.faces[i].offsetV) !== Utils.TEOffsetShort(this.defaultTexture.offsetV))
|
||||
{
|
||||
if (offsetvs[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
offsetvs[i] = 0;
|
||||
}
|
||||
offsetvs[i] |= (1 << i);
|
||||
}
|
||||
if (Utils.TERotationShort(this.faces[i].rotation) !== Utils.TERotationShort(this.defaultTexture.rotation))
|
||||
{
|
||||
if (rotations[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
rotations[i] = 0;
|
||||
}
|
||||
rotations[i] |= (1 << i);
|
||||
}
|
||||
if (this.faces[i].material !== this.defaultTexture.material)
|
||||
{
|
||||
if (materials[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
materials[i] = 0;
|
||||
}
|
||||
materials[i] |= (1 << i);
|
||||
}
|
||||
if (this.faces[i].media !== this.defaultTexture.media)
|
||||
{
|
||||
if (medias[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
medias[i] = 0;
|
||||
}
|
||||
medias[i] |= (1 << i);
|
||||
}
|
||||
if (Utils.TEGlowByte(this.faces[i].glow) !== Utils.TEGlowByte(this.defaultTexture.glow))
|
||||
{
|
||||
if (glows[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
glows[i] = 0;
|
||||
}
|
||||
glows[i] |= (1 << i);
|
||||
}
|
||||
if (!this.faces[i].materialID.equals(this.defaultTexture.materialID))
|
||||
{
|
||||
if (materialIDs[i] === TextureEntry.MAX_UINT32)
|
||||
{
|
||||
materialIDs[i] = 0;
|
||||
}
|
||||
materialIDs[i] |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
const chunks: Buffer[] = [];
|
||||
|
||||
// Textures
|
||||
this.getChunks( chunks, textures, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return face.textureID.getBuffer();
|
||||
});
|
||||
// Colour
|
||||
this.getChunks(chunks, rgbas, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return face.rgba.getBuffer(true);
|
||||
});
|
||||
// RepeatU
|
||||
this.getChunks( chunks, repeatus, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToFloatBuffer(face.repeatU);
|
||||
});
|
||||
// RepeatV
|
||||
this.getChunks(chunks, repeatvs, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToFloatBuffer(face.repeatV);
|
||||
});
|
||||
// OffsetU
|
||||
this.getChunks( chunks, offsetus, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToShortBuffer(Utils.TEOffsetShort(face.offsetU));
|
||||
});
|
||||
// OffsetV
|
||||
this.getChunks( chunks, offsetvs, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToShortBuffer(Utils.TEOffsetShort(face.offsetV));
|
||||
});
|
||||
// Rotation
|
||||
this.getChunks( chunks, rotations, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToShortBuffer(Utils.TERotationShort(face.rotation));
|
||||
});
|
||||
// Material
|
||||
this.getChunks( chunks, materials, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToByteBuffer(face.material);
|
||||
});
|
||||
// Media
|
||||
this.getChunks( chunks, medias, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToByteBuffer(face.media);
|
||||
});
|
||||
// Glows
|
||||
this.getChunks( chunks, glows, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return Utils.NumberToByteBuffer(Utils.TEGlowByte(face.glow));
|
||||
});
|
||||
// MaterialID
|
||||
this.getChunks(chunks, materialIDs, (face: TextureEntryFace): Buffer =>
|
||||
{
|
||||
return face.materialID.getBuffer();
|
||||
});
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
getChunks(chunks: Buffer[], items: number[], func: (item: TextureEntryFace) => Buffer)
|
||||
{
|
||||
if (this.defaultTexture !== null)
|
||||
{
|
||||
if (chunks.length > 0)
|
||||
{
|
||||
// Finish off the last chunk
|
||||
const zero = Buffer.allocUnsafe(1);
|
||||
zero[0] = 0;
|
||||
chunks.push(zero);
|
||||
}
|
||||
chunks.push(func(this.defaultTexture));
|
||||
const existingChunks: {
|
||||
buf: Buffer,
|
||||
bitfield: number
|
||||
}[] = [];
|
||||
for (let i = items.length - 1; i > -1; i--)
|
||||
{
|
||||
if (items[i] !== TextureEntry.MAX_UINT32)
|
||||
{
|
||||
const bitField = items[i];
|
||||
const buf = func(this.faces[i]);
|
||||
|
||||
let found = false;
|
||||
for (const ch of existingChunks)
|
||||
{
|
||||
if (ch.buf.compare(buf) === 0)
|
||||
{
|
||||
ch.bitfield = ch.bitfield | bitField;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
existingChunks.push({
|
||||
bitfield: bitField,
|
||||
buf: buf
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const chunk of existingChunks)
|
||||
{
|
||||
chunks.push(TextureEntry.getFaceBitfieldBuffer(chunk.bitfield));
|
||||
chunks.push(chunk.buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toBase64(): string
|
||||
{
|
||||
return this.toBuffer().toString('base64');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user