Skip to content

Commit

Permalink
Merge pull request #159 from vircadia/entity-data
Browse files Browse the repository at this point in the history
Provide Image, Text, Web, and Light entities
  • Loading branch information
ctrlaltdavid authored Aug 8, 2022
2 parents b1398b2 + 47ead50 commit b02c512
Show file tree
Hide file tree
Showing 25 changed files with 928 additions and 275 deletions.
4 changes: 3 additions & 1 deletion jsdoc/dev-mainpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ This SDK provides interfaces to:

<hr />

The top-level namespaces and classes provided for an application to use are, per the _Vircadia Web SDK Reference_:
The primary top-level namespaces and classes provided for an application to use are, per the _Vircadia Web SDK Reference_:
- `Vircadia`
- `DomainServer`
- `AudioMixer`
- `AvatarMixer`
- `EntityServer`
- `MessageMixer`
- `Camera`

<hr />

Expand Down
11 changes: 11 additions & 0 deletions jsdoc/sdk-mainpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ This SDK provides interfaces to:

<hr />

The primary top-level namespaces and classes provided for an application to use are:
- `Vircadia`
- `DomainServer`
- `AudioMixer`
- `AvatarMixer`
- `EntityServer`
- `MessageMixer`
- `Camera`

<hr />

To use the API, import the namespaces and classes that you want to use &mdash; either from the SDK package installed in your
project or directly from the SDK TypeScript.

Expand Down
2 changes: 1 addition & 1 deletion src/domain/audio/AudioInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import SignalEmitter, { Signal } from "../shared/SignalEmitter";
* audio mixer.
* <p>C++: QAudioInput, QIODevice</p>
* @class AudioInput
* @property {MediaStream | null} audioInput - The user client's audio input stream.
* @property {MediaStream|null} audioInput - The user client's audio input stream.
* <em>Write-only.</em>
* <p>This must be set to a non-null value only when the audio input isn't running (hasn't been started or has been
* stopped). Setting to <code>null</code> stops the audio input if it is running.</p>
Expand Down
12 changes: 8 additions & 4 deletions src/domain/entities/EntityTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,21 @@
* {@link ShapeEntityProperties}
* @property {number} Model - <code>4</code> - A mesh model from a glTF, FBX, or OBJ file.<br />
* {@link ModelEntityProperties}
* @property {number} Text - <code>5</code> - A pane of text oriented in space.
* @property {number} Image - <code>6</code> - An image oriented in space.
* @property {number} Web - <code>7</code> - A browsable web page.
* @property {number} Text - <code>5</code> - A pane of text oriented in space.<br />
* {@link TextEntityProperties}
* @property {number} Image - <code>6</code> - An image oriented in space.<br />
* {@link ImageEntityProperties}
* @property {number} Web - <code>7</code> - A browsable web page.<br />
* {@link WebEntityProperties}
* @property {number} ParticleEffect - <code>8</code> - A particle system that can be used to simulate things such as fire,
* smoke, snow, magic spells, etc.
* @property {number} Line - <code>9</code> - A sequence of one or more simple straight lines.
* @property {number} PolyLine - <code>10</code> - A sequence of one or more textured straight lines.
* @property {number} PolyVox - <code>11</code> - A set of textured voxels.
* @property {number} Grid - <code>12</code> - A grid of lines in a plane.
* @property {number} Gizmo - <code>13</code> - A gizmo intended for UI.
* @property {number} Light - <code>14</code> - A local lighting effect.
* @property {number} Light - <code>14</code> - A local lighting effect.<br />
* {@link LightEntityProperties}
* @property {number} Zone - <code>15</code> - A volume of lighting effects and avatar permissions.
* @property {number} Material - <code>16</code> - Modifies the existing materials on entities and avatars.
* @property {number} NUM_TYPES - <code>17</code> - The number of entity types.
Expand Down
1 change: 1 addition & 0 deletions src/domain/entities/GridEntityItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class GridEntityItem {
}

const pulseProperties = PulsePropertyGroup.readEntitySubclassDataFromBuffer(data, dataPosition, propertyFlags);
// Ignore deprecated pulse property.
dataPosition += pulseProperties.bytesRead;

if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_GRID_FOLLOW_CAMERA)) {
Expand Down
102 changes: 89 additions & 13 deletions src/domain/entities/ImageEntityItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,77 @@

import { CommonEntityProperties } from "../networking/packets/EntityData";
import UDT from "../networking/udt/UDT";
import type { color } from "../shared/Color";
import PropertyFlags from "../shared/PropertyFlags";
import { rect } from "../shared/Rect";
import { EntityPropertyFlags } from "./EntityPropertyFlags";
import PulsePropertyGroup from "./PulsePropertyGroup";


// WEBRTC TODO: Replace Record<string, never> with ImageEntityItem's special properties.
type ImageEntitySubclassProperties = Record<string, never>;
type ImageEntitySubclassProperties = {
imageURL: string | undefined;
emissive: boolean | undefined;
keepAspectRatio: boolean | undefined;
subImage: rect | undefined;
color: color | undefined;
alpha: number | undefined;
};

// WEBRTC TODO: Make a union with ImageEntitySubclassProperties.
type ImageEntityProperties = CommonEntityProperties;
type ImageEntityProperties = CommonEntityProperties & ImageEntitySubclassProperties;

// WEBRTC TODO: Replace Record<string, never> with ImageEntityProperties.
type ImageEntitySubclassData = {
bytesRead: number;
properties: ImageEntitySubclassProperties;
};


/*@devdoc
* The <code>ImageEntityItem</code> class provides facilities for reading Image entity properties from a packet.
* @class ImageEntityItem
*/
class ImageEntityItem {
// C++ class ImageEntityItem : public EntityItem

/*@sdkdoc
* Defines a rectangular portion of an image or screen, or similar.
* @typedef {object} rect
* @property {number} x - Left, x-coordinate value.
* @property {number} y - Top, y-coordinate value.
* @property {number} width - Width of the rectangle.
* @property {number} height - Height of the rectangle.
*/

/*@sdkdoc
* The <code>Image</code> {@link EntityType} displays an image on a 2D rectangle in the domain.
* <p>It has properties in addition to the {@link EntityProperties|common EntityProperties}. A property value may be
* undefined if it couldn't fit in the data packet sent by the server.</p>
* @typedef {object} ImageEntityProperties
* @property {string|undefined} imageURL - The URL of the image to use.
* @property {boolean|undefined} emissive - <code>true</code> if the image should be emissive (unlit), <code>false</code>
* if it shouldn't.
* @property {boolean|undefined} keepAspectRatio - <code>true</code> if the image should maintain its aspect ratio,
* <code>false</code> if it shouldn't.
* @property {rect|undefined} subImage - The portion of the image to display. If width or height are <code>0</code>, it
* defaults to the full image in that dimension.
* @property {color|undefined} color - The color of the entity.
* @property {number|undefined} alpha - The opacity of the image.
*/

/*@devdoc
* A wrapper for providing {@link ImageEntityProperties} and the number of bytes read.
* @typedef {object} ImageEntitySubclassData
* @property {number} bytesRead - The number of bytes read.
* @property {ImageEntityProperties} properties - The Image entity properties.
*/

/*@devdoc
* Reads, if present, Image entity properties in an {@link PacketType(1)|EntityData} packet.
* <p><em>Static</em></p>
* @param {DataView} data - The {@link Packets|EntityData} message data to read.
* @param {number} position - The position of the Image entity properties in the {@link Packets|EntityData} message data.
* @param {PropertyFlags} propertyFlags - The property flags.
* @returns {ImageEntitySubclassData} The Image entity properties and the number of bytes read.
*/
static readEntitySubclassDataFromBuffer(data: DataView, position: number, propertyFlags: PropertyFlags): ImageEntitySubclassData { // eslint-disable-line class-methods-use-this, max-len
// C++ int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
// ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
Expand All @@ -41,47 +91,73 @@ class ImageEntityItem {

let dataPosition = position;

const textDecoder = new TextDecoder();

let color: color | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_COLOR)) {
// WEBRTC TODO: Read color property.
color = {
red: data.getUint8(dataPosition),
green: data.getUint8(dataPosition + 1),
blue: data.getUint8(dataPosition + 2)
};
dataPosition += 3;
}

let alpha: number | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_ALPHA)) {
// WEBRTC TODO: Read alpha property.
alpha = data.getFloat32(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 4;
}

const pulseProperties = PulsePropertyGroup.readEntitySubclassDataFromBuffer(data, dataPosition, propertyFlags);
// Ignore deprecated pulse property.
dataPosition += pulseProperties.bytesRead;

let imageURL: string | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_IMAGE_URL)) {
const length = data.getUint16(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 2;

if (length > 0) {
// WEBRTC TODO: Read imageUrl property.
imageURL = textDecoder.decode(new Uint8Array(data.buffer, data.byteOffset + dataPosition, length));
dataPosition += length;
} else {
imageURL = "";
}
}

let emissive: boolean | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_EMISSIVE)) {
// WEBRTC TODO: Read emissive property.
emissive = Boolean(data.getUint8(dataPosition));
dataPosition += 1;
}

let keepAspectRatio: boolean | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_KEEP_ASPECT_RATIO)) {
// WEBRTC TODO: Read keepAspectRatio property.
keepAspectRatio = Boolean(data.getUint8(dataPosition));
dataPosition += 1;
}

let subImage: rect | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_SUB_IMAGE)) {
// WEBRTC TODO: Read keepAspectRatio property.
subImage = {
x: data.getUint32(dataPosition, UDT.LITTLE_ENDIAN),
y: data.getUint32(dataPosition + 4, UDT.LITTLE_ENDIAN),
width: data.getUint32(dataPosition + 4, UDT.LITTLE_ENDIAN),
height: data.getUint32(dataPosition + 4, UDT.LITTLE_ENDIAN)
};
dataPosition += 16;
}

return {
bytesRead: dataPosition - position,
properties: {}
properties: {
imageURL,
emissive,
keepAspectRatio,
subImage,
color,
alpha
}
};

/* eslint-enable @typescript-eslint/no-magic-numbers */
Expand Down
86 changes: 72 additions & 14 deletions src/domain/entities/LightEntityItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,69 @@
//

import { CommonEntityProperties } from "../networking/packets/EntityData";
import UDT from "../networking/udt/UDT";
import type { color } from "../shared/Color";
import PropertyFlags from "../shared/PropertyFlags";
import { EntityPropertyFlags } from "./EntityPropertyFlags";


// WEBRTC TODO: Replace Record<string, never> with LightEntityItem's special properties.
type LightEntitySubclassProperties = Record<string, never>;
type LightEntitySubclassProperties = {
color: color | undefined,
isSpotlight: boolean | undefined,
intensity: number | undefined,
exponent: number | undefined,
cutoff: number | undefined,
falloffRadius: number | undefined
};

// WEBRTC TODO: Make a union with LightEntitySubclassProperties.
type LightEntityProperties = CommonEntityProperties;
type LightEntityProperties = CommonEntityProperties & LightEntitySubclassProperties;

type LightEntitySubclassData = {
bytesRead: number;
properties: LightEntitySubclassProperties;
};


/*@devdoc
* The <code>LightEntityItem</code> class provides facilities for reading Light entity properties from a packet.
* @class LightEntityItem
*/
class LightEntityItem {
// C++ class LightEntityItem : public EntityItem

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
static readEntitySubclassDataFromBuffer(data: DataView, position: number, propertyFlags: PropertyFlags): LightEntitySubclassData { // eslint-disable-line class-methods-use-this, max-len
/*@sdkdoc
* The <code>Light</code> {@link EntityType} provides a local lighting effect. Surfaces outside the entity's dimensions are
* not lit by the light.
* <p>It has properties in addition to the {@link EntityProperties|common EntityProperties}. A property value may be
* undefined if it couldn't fit in the data packet sent by the server.</p>
* @typedef {object} LightEntityProperties
* @property {color|undefined} color - The color of the light emitted.
* @property {number|undefined} intensity - The brightness of the light.
* @property {number|undefined} falloffRadius - The distance from the light's center at which intensity is reduced by 25%.
* @property {boolean|undefined} isSpotlight - <code>true</code> if the light is directional, emitting along the entity's
* local negative z-axis; <code>false</code> if the light is a point light which emanates in all directions.
* @property {number|undefined} exponent - Affects the softness of the spotlight beam: the higher the value the softer the
* beam.
* @property {number|undefined} cutoff - Affects the size of the spotlight beam: the higher the value the larger the beam.
*/

/*@devdoc
* A wrapper for providing {@link LightEntityProperties} and the number of bytes read.
* @typedef {object} LightEntitySubclassData
* @property {number} bytesRead - The number of bytes read.
* @property {LightEntityProperties} properties - The Light entity properties.
*/

/*@devdoc
* Reads, if present, Light entity properties in an {@link PacketType(1)|EntityData} packet.
* <p><em>Static</em></p>
* @param {DataView} data - The {@link Packets|EntityData} message data to read.
* @param {number} position - The position of the Light entity properties in the {@link Packets|EntityData} message data.
* @param {PropertyFlags} propertyFlags - The property flags.
* @returns {LightEntitySubclassData} The Light entity properties and the number of bytes read.
*/
static readEntitySubclassDataFromBuffer(data: DataView, position: number,
propertyFlags: PropertyFlags): LightEntitySubclassData {
// C++ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
// ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
// bool& somethingChanged)
Expand All @@ -40,39 +81,56 @@ class LightEntityItem {

let dataPosition = position;

let color: color | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_COLOR)) {
// WEB TODO: Read color property.
color = {
red: data.getUint8(dataPosition),
green: data.getUint8(dataPosition + 1),
blue: data.getUint8(dataPosition + 2)
};
dataPosition += 3;
}

let isSpotlight: boolean | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_IS_SPOTLIGHT)) {
// WEB TODO: Read isSpotlight property.
isSpotlight = Boolean(data.getUint8(dataPosition));
dataPosition += 1;
}

let intensity: number | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_INTENSITY)) {
// WEB TODO: Read intensity property.
intensity = data.getFloat32(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 4;
}

let exponent: number | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_EXPONENT)) {
// WEB TODO: Read exponent property.
exponent = data.getFloat32(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 4;
}

let cutoff: number | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_CUTOFF)) {
// WEB TODO: Read cutoff property.
cutoff = data.getFloat32(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 4;
}

let falloffRadius: number | undefined = undefined;
if (propertyFlags.getHasProperty(EntityPropertyFlags.PROP_FALLOFF_RADIUS)) {
// WEB TODO: Read falloffRadius property.
falloffRadius = data.getFloat32(dataPosition, UDT.LITTLE_ENDIAN);
dataPosition += 4;
}

return {
bytesRead: dataPosition - position,
properties: {}
properties: {
color,
isSpotlight,
intensity,
exponent,
cutoff,
falloffRadius
}
};

/* eslint-enable @typescript-eslint/no-magic-numbers */
Expand Down
Loading

0 comments on commit b02c512

Please sign in to comment.