Files
node-metaverse/lib/classes/TextureEntry.ts
Casper Warden da4cd459f1 - Add "GET" method to Caps
- New events: ObjectPhysicsDataEvent, ParcelPropertiesEvent, NewObjectEvent, ObjectUpdateEvent, ObjectKilledEvent
- Added getXML function to Color4, Vector2, Vector3, Vector4, GameObject, Region, Quaternion, UUID for opensim-compatible XML export
- Added TextureAnim and ParticleSystem decoding to the "full" ObjectStore
- Object store will automatically request missing "parent" prims
- "setPersist" - When persist is TRUE, the ObjectStore will not forget about "killed" prims - useful for region scanning
- Support for Flexible params, Light params, LightImage params, Mesh data, Sculpt maps
- Fixed object scale being incorrectly calculated
- Add terrain decoding (this was a ballache)
- Add parcel map decoding
- Add support for region windlight settings (region.environment)
- Add support for materials (normal / specular maps)
- Add getBuffer, getLong and bitwiseOr to UUID
- Added a circular-reference-safe JSONStringify to Utils
- Add XferFile capability to Circuit

PUBLIC API:

AssetCommands:
- Rework "downloadAsset" to detect failures
- NEW: downloadInventoryAsset() - uses TransferRequest for prim inventory items
- NEW: getMaterials() - resolves material UUIDs

RegionCommands:
- NEW: getTerrainTextures()
- NEW: exportSettings() - OpenSim XML export of region settings
- NEW: async getTerrain() - Get binary terrain heightmap, 256x256 float32
- resolveObjects() - now fetches task inventory contents too.
- resolveObjects() - fix calculation of land impact
- NEW: getObjectByLocalID(localID: number, timeout: number)
- NEW: getObjectByUUID(uuid: UUID, timeout: number)
- NEW: getParcels();
- NEW: pruneObjects - removes missing GameObjects from a list
- NEW: setPersist - prevent objectstore from forgetting about killed gameobjects
2018-10-31 11:28:24 +00:00

365 lines
12 KiB
TypeScript

import {TextureEntryFace} from './TextureEntryFace';
import {UUID} from './UUID';
import {Color4} from './Color4';
import {Utils} from './Utils';
export class TextureEntry
{
defaultTexture: TextureEntryFace | null;
faces: TextureEntryFace[] = [];
binary: Buffer;
static readFaceBitfield(buf: Buffer, pos: number): {
result: boolean,
pos: number,
faceBits: number,
bitfieldSize: number
}
{
const result = {
result: false,
pos: pos,
faceBits: 0,
bitfieldSize: 0
};
if (result.pos >= buf.length)
{
return result;
}
let b = 0;
do
{
b = buf.readUInt8(result.pos);
result.faceBits = (result.faceBits << 7) | (b & 0x7F);
result.bitfieldSize += 7;
result.pos++;
}
while ((b & 0x80) !== 0);
result.result = (result.faceBits !== 0);
return result;
}
constructor(buf: Buffer)
{
this.binary = buf;
if (buf.length < 16)
{
this.defaultTexture = null;
}
else
{
this.defaultTexture = new TextureEntryFace(null);
const pos = 0;
let i = pos;
// Texture
{
this.defaultTexture.textureID = new UUID(buf, i);
i += 16;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const uuid = new UUID(buf, i);
i += 16;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].textureID = uuid;
}
}
}
}
}
// Colour
{
this.defaultTexture.rgba = new Color4(buf, i, true);
i += 4;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpColor = new Color4(buf, i, true);
i += 4;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].rgba = tmpColor;
}
}
}
}
}
// RepeatU
{
this.defaultTexture.repeatU = buf.readFloatLE(i);
i += 4;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = buf.readFloatLE(i);
i += 4;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].repeatU = tmpFloat;
}
}
}
}
}
// RepeatV
{
this.defaultTexture.repeatV = buf.readFloatLE(i);
i += 4;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = buf.readFloatLE(i);
i += 4;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].repeatV = tmpFloat;
}
}
}
}
}
// OffsetU
{
this.defaultTexture.offsetU = Utils.ReadOffsetFloat(buf, i);
i += 2;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = Utils.ReadOffsetFloat(buf, i);
i += 2;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].offsetU = tmpFloat;
}
}
}
}
}
// OffsetV
{
this.defaultTexture.offsetV = Utils.ReadOffsetFloat(buf, i);
i += 2;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = Utils.ReadOffsetFloat(buf, i);
i += 2;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].offsetV = tmpFloat;
}
}
}
}
}
// Rotation
{
this.defaultTexture.rotation = Utils.ReadRotationFloat(buf, i);
i += 2;
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = Utils.ReadRotationFloat(buf, i);
i += 2;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].rotation = tmpFloat;
}
}
}
}
}
// Material
{
this.defaultTexture.material = buf[i++];
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpByte = buf[i++];
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].material = tmpByte;
}
}
}
}
}
// Media
{
this.defaultTexture.media = buf[i++];
let done = false;
while (i - pos < buf.length && !done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpByte = buf[i++];
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].media = tmpByte;
}
}
}
}
}
// Glow
{
this.defaultTexture.glow = Utils.ReadGlowFloat(buf, i++);
let done = false;
while (!done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const tmpFloat = Utils.ReadGlowFloat(buf, i++);
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].glow = tmpFloat;
}
}
}
}
}
// MaterialID
{
const len = i - pos + 16;
if (i - pos + 16 <= buf.length)
{
this.defaultTexture.materialID = new UUID(buf, i);
i += 16;
let done = false;
while (i - pos + 16 <= buf.length && !done)
{
const result = TextureEntry.readFaceBitfield(buf, i);
done = !result.result;
i = result.pos;
if (!done)
{
const uuid = new UUID(buf, i);
i += 16;
for (let face = 0, bit = 1; face < result.bitfieldSize; face++, bit <<= 1)
{
if ((result.faceBits & bit) !== 0)
{
this.createFace(face);
this.faces[face].materialID = uuid;
}
}
}
}
}
}
}
}
private createFace(face: number)
{
if (face > 32)
{
console.error('Warning: Face number exceeds maximum number of faces: 32');
}
while (this.faces.length <= face)
{
this.faces.push(new TextureEntryFace(this.defaultTexture));
}
}
}