- 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:
Casper Warden
2018-11-15 03:10:14 +00:00
parent 0b4960eb4f
commit 76b080757b
37 changed files with 2864 additions and 415 deletions

View File

@@ -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');
}
}