mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 20:56:25 +02:00
1162 lines
58 KiB
C++
1162 lines
58 KiB
C++
//
|
|
// EntityItemProperties.cpp
|
|
// libraries/entities/src
|
|
//
|
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include <QDebug>
|
|
#include <QHash>
|
|
#include <QObject>
|
|
#include <QtCore/QJsonDocument>
|
|
|
|
#include <ByteCountCoding.h>
|
|
#include <GLMHelpers.h>
|
|
#include <RegisteredMetaTypes.h>
|
|
|
|
#include "EntitiesLogging.h"
|
|
#include "EntityItem.h"
|
|
#include "EntityItemProperties.h"
|
|
#include "EntityItemPropertiesDefaults.h"
|
|
#include "ModelEntityItem.h"
|
|
#include "ParticleEffectEntityItem.h"
|
|
#include "TextEntityItem.h"
|
|
#include "ZoneEntityItem.h"
|
|
#include "PolyVoxEntityItem.h"
|
|
|
|
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
|
|
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
|
|
StagePropertyGroup EntityItemProperties::_staticStage;
|
|
|
|
EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1);
|
|
|
|
EntityItemProperties::EntityItemProperties() :
|
|
|
|
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
|
|
CONSTRUCT_PROPERTY(position, 0),
|
|
CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS),
|
|
CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION),
|
|
CONSTRUCT_PROPERTY(density, ENTITY_ITEM_DEFAULT_DENSITY),
|
|
CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY),
|
|
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
|
|
CONSTRUCT_PROPERTY(acceleration, ENTITY_ITEM_DEFAULT_ACCELERATION),
|
|
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
|
|
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
|
|
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
|
|
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
|
|
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
|
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
|
|
CONSTRUCT_PROPERTY(color, ),
|
|
CONSTRUCT_PROPERTY(modelURL, ""),
|
|
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
|
|
CONSTRUCT_PROPERTY(animationURL, ""),
|
|
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
|
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
|
|
CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING),
|
|
CONSTRUCT_PROPERTY(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
|
|
CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
|
|
CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
|
|
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
|
|
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
|
|
CONSTRUCT_PROPERTY(isSpotlight, false),
|
|
CONSTRUCT_PROPERTY(intensity, 1.0f),
|
|
CONSTRUCT_PROPERTY(exponent, 0.0f),
|
|
CONSTRUCT_PROPERTY(cutoff, ENTITY_ITEM_DEFAULT_CUTOFF),
|
|
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
|
|
CONSTRUCT_PROPERTY(textures, ""),
|
|
CONSTRUCT_PROPERTY(animationSettings, ""),
|
|
CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA),
|
|
CONSTRUCT_PROPERTY(simulatorID, ENTITY_ITEM_DEFAULT_SIMULATOR_ID),
|
|
CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT),
|
|
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
|
|
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
|
|
CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR),
|
|
CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE),
|
|
CONSTRUCT_PROPERTY(maxParticles, ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES),
|
|
CONSTRUCT_PROPERTY(lifespan, ParticleEffectEntityItem::DEFAULT_LIFESPAN),
|
|
CONSTRUCT_PROPERTY(emitRate, ParticleEffectEntityItem::DEFAULT_EMIT_RATE),
|
|
CONSTRUCT_PROPERTY(emitDirection, ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION),
|
|
CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH),
|
|
CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY),
|
|
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
|
|
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
|
CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
|
|
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
|
CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY),
|
|
CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION),
|
|
CONSTRUCT_PROPERTY(voxelVolumeSize, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
|
|
CONSTRUCT_PROPERTY(voxelData, PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
|
|
CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
|
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
|
|
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
|
|
CONSTRUCT_PROPERTY(sourceUrl, ""),
|
|
|
|
|
|
_id(UNKNOWN_ENTITY_ID),
|
|
_idSet(false),
|
|
_lastEdited(0),
|
|
_created(UNKNOWN_CREATED_TIME),
|
|
_type(EntityTypes::Unknown),
|
|
|
|
_glowLevel(0.0f),
|
|
_localRenderAlpha(1.0f),
|
|
|
|
_glowLevelChanged(false),
|
|
_localRenderAlphaChanged(false),
|
|
|
|
_defaultSettings(true),
|
|
_naturalDimensions(1.0f, 1.0f, 1.0f)
|
|
{
|
|
}
|
|
|
|
EntityItemProperties::~EntityItemProperties() {
|
|
}
|
|
|
|
void EntityItemProperties::setSittingPoints(const QVector<SittingPoint>& sittingPoints) {
|
|
_sittingPoints.clear();
|
|
foreach (SittingPoint sitPoint, sittingPoints) {
|
|
_sittingPoints.append(sitPoint);
|
|
}
|
|
}
|
|
|
|
void EntityItemProperties::setAnimationSettings(const QString& value) {
|
|
// the animations setting is a JSON string that may contain various animation settings.
|
|
// if it includes fps, frameIndex, or running, those values will be parsed out and
|
|
// will over ride the regular animation settings
|
|
|
|
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
|
|
QJsonObject settingsAsJsonObject = settingsAsJson.object();
|
|
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
|
|
if (settingsMap.contains("fps")) {
|
|
float fps = settingsMap["fps"].toFloat();
|
|
setAnimationFPS(fps);
|
|
}
|
|
|
|
if (settingsMap.contains("frameIndex")) {
|
|
float frameIndex = settingsMap["frameIndex"].toFloat();
|
|
setAnimationFrameIndex(frameIndex);
|
|
}
|
|
|
|
if (settingsMap.contains("running")) {
|
|
bool running = settingsMap["running"].toBool();
|
|
setAnimationIsPlaying(running);
|
|
}
|
|
|
|
_animationSettings = value;
|
|
_animationSettingsChanged = true;
|
|
}
|
|
|
|
QString EntityItemProperties::getAnimationSettings() const {
|
|
// the animations setting is a JSON string that may contain various animation settings.
|
|
// if it includes fps, frameIndex, or running, those values will be parsed out and
|
|
// will over ride the regular animation settings
|
|
QString value = _animationSettings;
|
|
|
|
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
|
|
QJsonObject settingsAsJsonObject = settingsAsJson.object();
|
|
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
|
|
|
|
QVariant fpsValue(getAnimationFPS());
|
|
settingsMap["fps"] = fpsValue;
|
|
|
|
QVariant frameIndexValue(getAnimationFrameIndex());
|
|
settingsMap["frameIndex"] = frameIndexValue;
|
|
|
|
QVariant runningValue(getAnimationIsPlaying());
|
|
settingsMap["running"] = runningValue;
|
|
|
|
settingsAsJsonObject = QJsonObject::fromVariantMap(settingsMap);
|
|
QJsonDocument newDocument(settingsAsJsonObject);
|
|
QByteArray jsonByteArray = newDocument.toJson(QJsonDocument::Compact);
|
|
QString jsonByteString(jsonByteArray);
|
|
return jsonByteString;
|
|
}
|
|
|
|
void EntityItemProperties::debugDump() const {
|
|
qCDebug(entities) << "EntityItemProperties...";
|
|
qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type);
|
|
qCDebug(entities) << " _id=" << _id;
|
|
qCDebug(entities) << " _idSet=" << _idSet;
|
|
qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z;
|
|
qCDebug(entities) << " _dimensions=" << getDimensions();
|
|
qCDebug(entities) << " _modelURL=" << _modelURL;
|
|
qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL;
|
|
|
|
getAtmosphere().debugDump();
|
|
getSkybox().debugDump();
|
|
|
|
qCDebug(entities) << " changed properties...";
|
|
EntityPropertyFlags props = getChangedProperties();
|
|
props.debugDumpBits();
|
|
}
|
|
|
|
void EntityItemProperties::setCreated(quint64 usecTime) {
|
|
_created = usecTime;
|
|
if (_lastEdited < _created) {
|
|
_lastEdited = _created;
|
|
}
|
|
}
|
|
|
|
void EntityItemProperties::setLastEdited(quint64 usecTime) {
|
|
_lastEdited = usecTime > _created ? usecTime : _created;
|
|
}
|
|
|
|
const char* shapeTypeNames[] = {"none", "box", "sphere", "ellipsoid", "plane", "compound", "capsule-x",
|
|
"capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"};
|
|
|
|
QHash<QString, ShapeType> stringToShapeTypeLookup;
|
|
|
|
void addShapeType(ShapeType type) {
|
|
stringToShapeTypeLookup[shapeTypeNames[type]] = type;
|
|
}
|
|
|
|
void buildStringToShapeTypeLookup() {
|
|
addShapeType(SHAPE_TYPE_NONE);
|
|
addShapeType(SHAPE_TYPE_BOX);
|
|
addShapeType(SHAPE_TYPE_SPHERE);
|
|
addShapeType(SHAPE_TYPE_ELLIPSOID);
|
|
addShapeType(SHAPE_TYPE_PLANE);
|
|
addShapeType(SHAPE_TYPE_COMPOUND);
|
|
addShapeType(SHAPE_TYPE_CAPSULE_X);
|
|
addShapeType(SHAPE_TYPE_CAPSULE_Y);
|
|
addShapeType(SHAPE_TYPE_CAPSULE_Z);
|
|
addShapeType(SHAPE_TYPE_CYLINDER_X);
|
|
addShapeType(SHAPE_TYPE_CYLINDER_Y);
|
|
addShapeType(SHAPE_TYPE_CYLINDER_Z);
|
|
}
|
|
|
|
QString EntityItemProperties::getShapeTypeAsString() const {
|
|
if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *))
|
|
return QString(shapeTypeNames[_shapeType]);
|
|
return QString(shapeTypeNames[SHAPE_TYPE_NONE]);
|
|
}
|
|
|
|
void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) {
|
|
if (stringToShapeTypeLookup.empty()) {
|
|
buildStringToShapeTypeLookup();
|
|
}
|
|
auto shapeTypeItr = stringToShapeTypeLookup.find(shapeName.toLower());
|
|
if (shapeTypeItr != stringToShapeTypeLookup.end()) {
|
|
_shapeType = shapeTypeItr.value();
|
|
_shapeTypeChanged = true;
|
|
}
|
|
}
|
|
|
|
const char* backgroundModeNames[] = {"inherit", "atmosphere", "skybox" };
|
|
|
|
QHash<QString, BackgroundMode> stringToBackgroundModeLookup;
|
|
|
|
void addBackgroundMode(BackgroundMode type) {
|
|
stringToBackgroundModeLookup[backgroundModeNames[type]] = type;
|
|
}
|
|
|
|
void buildStringToBackgroundModeLookup() {
|
|
addBackgroundMode(BACKGROUND_MODE_INHERIT);
|
|
addBackgroundMode(BACKGROUND_MODE_ATMOSPHERE);
|
|
addBackgroundMode(BACKGROUND_MODE_SKYBOX);
|
|
}
|
|
|
|
QString EntityItemProperties::getBackgroundModeAsString() const {
|
|
if (_backgroundMode < sizeof(backgroundModeNames) / sizeof(char *))
|
|
return QString(backgroundModeNames[_backgroundMode]);
|
|
return QString(backgroundModeNames[BACKGROUND_MODE_INHERIT]);
|
|
}
|
|
|
|
QString EntityItemProperties::getBackgroundModeString(BackgroundMode mode) {
|
|
if (mode < sizeof(backgroundModeNames) / sizeof(char *))
|
|
return QString(backgroundModeNames[mode]);
|
|
return QString(backgroundModeNames[BACKGROUND_MODE_INHERIT]);
|
|
}
|
|
|
|
void EntityItemProperties::setBackgroundModeFromString(const QString& backgroundMode) {
|
|
if (stringToBackgroundModeLookup.empty()) {
|
|
buildStringToBackgroundModeLookup();
|
|
}
|
|
auto backgroundModeItr = stringToBackgroundModeLookup.find(backgroundMode.toLower());
|
|
if (backgroundModeItr != stringToBackgroundModeLookup.end()) {
|
|
_backgroundMode = backgroundModeItr.value();
|
|
_backgroundModeChanged = true;
|
|
}
|
|
}
|
|
|
|
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|
EntityPropertyFlags changedProperties;
|
|
|
|
CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions);
|
|
CHECK_PROPERTY_CHANGE(PROP_POSITION, position);
|
|
CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation);
|
|
CHECK_PROPERTY_CHANGE(PROP_DENSITY, density);
|
|
CHECK_PROPERTY_CHANGE(PROP_VELOCITY, velocity);
|
|
CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity);
|
|
CHECK_PROPERTY_CHANGE(PROP_ACCELERATION, acceleration);
|
|
CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping);
|
|
CHECK_PROPERTY_CHANGE(PROP_RESTITUTION, restitution);
|
|
CHECK_PROPERTY_CHANGE(PROP_FRICTION, friction);
|
|
CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime);
|
|
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
|
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
|
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
|
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
|
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, animationFPS);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_SETTINGS, animationSettings);
|
|
CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible);
|
|
CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity);
|
|
CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping);
|
|
CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions);
|
|
CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove);
|
|
CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight);
|
|
CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity);
|
|
CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent);
|
|
CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff);
|
|
CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked);
|
|
CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures);
|
|
CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData);
|
|
CHECK_PROPERTY_CHANGE(PROP_SIMULATOR_ID, simulatorID);
|
|
CHECK_PROPERTY_CHANGE(PROP_TEXT, text);
|
|
CHECK_PROPERTY_CHANGE(PROP_LINE_HEIGHT, lineHeight);
|
|
CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor);
|
|
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor);
|
|
CHECK_PROPERTY_CHANGE(PROP_SHAPE_TYPE, shapeType);
|
|
CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles);
|
|
CHECK_PROPERTY_CHANGE(PROP_LIFESPAN, lifespan);
|
|
CHECK_PROPERTY_CHANGE(PROP_EMIT_RATE, emitRate);
|
|
CHECK_PROPERTY_CHANGE(PROP_EMIT_DIRECTION, emitDirection);
|
|
CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength);
|
|
CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity);
|
|
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
|
|
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
|
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
|
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor);
|
|
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity);
|
|
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity);
|
|
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
|
|
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
|
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
|
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
|
|
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
|
|
|
|
changedProperties += _stage.getChangedProperties();
|
|
changedProperties += _atmosphere.getChangedProperties();
|
|
changedProperties += _skybox.getChangedProperties();
|
|
|
|
return changedProperties;
|
|
}
|
|
|
|
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const {
|
|
QScriptValue properties = engine->newObject();
|
|
EntityItemProperties defaultEntityProperties;
|
|
|
|
if (_idSet) {
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
|
|
}
|
|
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(position);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions);
|
|
if (!skipDefaults) {
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(naturalDimensions); // gettable, but not settable
|
|
}
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(rotation);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(velocity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(gravity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(acceleration);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(damping);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(restitution);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(friction);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(density);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime);
|
|
if (!skipDefaults) {
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable
|
|
}
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(script);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(registrationPoint);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(angularVelocity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(animationSettings, getAnimationSettings());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(ignoreForCollisions);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionsWillMove);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(isSpotlight);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(intensity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(exponent);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(locked);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(textures);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(userData);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(simulatorID, getSimulatorIDAsString());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(text);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(lineHeight);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(textColor, getTextColor());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundColor, getBackgroundColor());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(shapeType, getShapeTypeAsString());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(maxParticles);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(lifespan);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(emitRate);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(emitDirection);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
|
|
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
|
|
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
|
|
|
|
// Sitting properties support
|
|
if (!skipDefaults) {
|
|
QScriptValue sittingPoints = engine->newObject();
|
|
for (int i = 0; i < _sittingPoints.size(); ++i) {
|
|
QScriptValue sittingPoint = engine->newObject();
|
|
sittingPoint.setProperty("name", _sittingPoints.at(i).name);
|
|
sittingPoint.setProperty("position", vec3toScriptValue(engine, _sittingPoints.at(i).position));
|
|
sittingPoint.setProperty("rotation", quatToScriptValue(engine, _sittingPoints.at(i).rotation));
|
|
sittingPoints.setProperty(i, sittingPoint);
|
|
}
|
|
sittingPoints.setProperty("length", _sittingPoints.size());
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
|
|
}
|
|
|
|
if (!skipDefaults) {
|
|
AABox aaBox = getAABox();
|
|
QScriptValue boundingBox = engine->newObject();
|
|
QScriptValue bottomRightNear = vec3toScriptValue(engine, aaBox.getCorner());
|
|
QScriptValue topFarLeft = vec3toScriptValue(engine, aaBox.calcTopFarLeft());
|
|
QScriptValue center = vec3toScriptValue(engine, aaBox.calcCenter());
|
|
QScriptValue boundingBoxDimensions = vec3toScriptValue(engine, aaBox.getDimensions());
|
|
boundingBox.setProperty("brn", bottomRightNear);
|
|
boundingBox.setProperty("tfl", topFarLeft);
|
|
boundingBox.setProperty("center", center);
|
|
boundingBox.setProperty("dimensions", boundingBoxDimensions);
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable
|
|
}
|
|
|
|
QString textureNamesList = _textureNames.join(",\n");
|
|
if (!skipDefaults) {
|
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable
|
|
}
|
|
|
|
_stage.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
|
|
_atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
|
|
_skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
|
|
|
|
return properties;
|
|
}
|
|
|
|
void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|
QScriptValue typeScriptValue = object.property("type");
|
|
if (typeScriptValue.isValid()) {
|
|
setType(typeScriptValue.toVariant().toString());
|
|
}
|
|
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(position, glmVec3, setPosition);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, glmVec3, setDimensions);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, glmQuat, setRotation);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(velocity, glmVec3, setVelocity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(gravity, glmVec3, setGravity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(acceleration, glmVec3, setAcceleration);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(damping, float, setDamping);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, glmVec3, setRegistrationPoint);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, glmVec3, setAngularVelocity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationIsPlaying, bool, setAnimationIsPlaying);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationFPS, float, setAnimationFPS);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationFrameIndex, float, setAnimationFrameIndex);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationSettings, QString, setAnimationSettings);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(exponent, float, setExponent);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(cutoff, float, setCutoff);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData);
|
|
//COPY_PROPERTY_FROM_QSCRIPTVALUE(simulatorID, QUuid, setSimulatorID); DO NOT accept this info from QScriptValue
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, xColor, setBackgroundColor);
|
|
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, float, setMaxParticles);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRate, float, setEmitRate);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitDirection, glmVec3, setEmitDirection);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitStrength, float, setEmitStrength);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(localGravity, float, setLocalGravity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
|
|
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightColor, xColor, setKeyLightColor);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightIntensity, float, setKeyLightIntensity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightAmbientIntensity, float, setKeyLightAmbientIntensity);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
|
|
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
|
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
|
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
|
|
|
|
_stage.copyFromScriptValue(object, _defaultSettings);
|
|
_atmosphere.copyFromScriptValue(object, _defaultSettings);
|
|
_skybox.copyFromScriptValue(object, _defaultSettings);
|
|
_lastEdited = usecTimestampNow();
|
|
}
|
|
|
|
QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) {
|
|
return properties.copyToScriptValue(engine, false);
|
|
}
|
|
|
|
QScriptValue EntityItemNonDefaultPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties) {
|
|
return properties.copyToScriptValue(engine, true);
|
|
}
|
|
|
|
void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties) {
|
|
properties.copyFromScriptValue(object);
|
|
}
|
|
|
|
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
|
|
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
|
|
// to how we handle this in the Octree streaming case.
|
|
//
|
|
// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer
|
|
// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties
|
|
//
|
|
// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property
|
|
// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that
|
|
// utilized the registration table to shorten up and simplify this code.
|
|
//
|
|
// TODO: Implement support for paged properties, spanning MTU, and custom properties
|
|
//
|
|
// TODO: Implement support for script and visible properties.
|
|
//
|
|
bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties,
|
|
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
|
|
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
|
|
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
|
|
|
|
bool success = true; // assume the best
|
|
OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best
|
|
sizeOut = 0;
|
|
|
|
// TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code
|
|
// didn't do anything special for jurisdictions, so we're keeping that same behavior here.)
|
|
//
|
|
// Always include the root octcode. This is only because the OctreeEditPacketSender will check these octcodes
|
|
// to determine which server to send the changes to in the case of multiple jurisdictions. The root will be sent
|
|
// to all servers.
|
|
glm::vec3 rootPosition(0);
|
|
float rootScale = 0.5f;
|
|
unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale);
|
|
|
|
success = packetData->startSubTree(octcode);
|
|
delete[] octcode;
|
|
|
|
// assuming we have rome to fit our octalCode, proceed...
|
|
if (success) {
|
|
|
|
// Now add our edit content details...
|
|
|
|
// id
|
|
// encode our ID as a byte count coded byte stream
|
|
QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
|
|
|
|
// encode our ID as a byte count coded byte stream
|
|
ByteCountCoded<quint32> tokenCoder;
|
|
QByteArray encodedToken;
|
|
|
|
// encode our type as a byte count coded byte stream
|
|
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
|
|
QByteArray encodedType = typeCoder;
|
|
|
|
quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync
|
|
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
|
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
|
|
|
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
|
EntityPropertyFlags requestedProperties = properties.getChangedProperties();
|
|
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
|
|
|
// TODO: we need to handle the multi-pass form of this, similar to how we handle entity data
|
|
//
|
|
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
|
|
// then our modelTreeElementExtraEncodeData should include data about which properties we need to append.
|
|
//if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
|
|
// requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
|
|
//}
|
|
|
|
LevelDetails entityLevel = packetData->startLevel();
|
|
|
|
// Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this
|
|
// timestamp for clock skew
|
|
quint64 lastEdited = properties.getLastEdited();
|
|
bool successLastEditedFits = packetData->appendValue(lastEdited);
|
|
|
|
bool successIDFits = packetData->appendRawData(encodedID);
|
|
if (successIDFits) {
|
|
successIDFits = packetData->appendRawData(encodedToken);
|
|
}
|
|
bool successTypeFits = packetData->appendRawData(encodedType);
|
|
|
|
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
|
|
// 1) if the edit is to an existing entity, the created time can not be changed
|
|
// 2) if the edit is to a new entity, the created time is the last edited time
|
|
|
|
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
|
|
bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta);
|
|
|
|
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
|
QByteArray encodedPropertyFlags = propertyFlags;
|
|
int oldPropertyFlagsLength = encodedPropertyFlags.length();
|
|
bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags);
|
|
int propertyCount = 0;
|
|
|
|
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
|
|
&& successLastUpdatedFits && successPropertyFlagsFits;
|
|
|
|
int startOfEntityItemData = packetData->getUncompressedByteOffset();
|
|
|
|
if (headerFits) {
|
|
bool successPropertyFits;
|
|
propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item
|
|
|
|
// These items would go here once supported....
|
|
// PROP_PAGED_PROPERTY,
|
|
// PROP_CUSTOM_PROPERTIES_INCLUDED,
|
|
|
|
APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition());
|
|
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
|
|
APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation());
|
|
APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity());
|
|
APPEND_ENTITY_PROPERTY(PROP_VELOCITY, properties.getVelocity());
|
|
APPEND_ENTITY_PROPERTY(PROP_GRAVITY, properties.getGravity());
|
|
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, properties.getAcceleration());
|
|
APPEND_ENTITY_PROPERTY(PROP_DAMPING, properties.getDamping());
|
|
APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, properties.getRestitution());
|
|
APPEND_ENTITY_PROPERTY(PROP_FRICTION, properties.getFriction());
|
|
APPEND_ENTITY_PROPERTY(PROP_LIFETIME, properties.getLifetime());
|
|
APPEND_ENTITY_PROPERTY(PROP_SCRIPT, properties.getScript());
|
|
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
|
|
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, properties.getRegistrationPoint());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping());
|
|
APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible());
|
|
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions());
|
|
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove());
|
|
APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked());
|
|
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData());
|
|
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID());
|
|
|
|
if (properties.getType() == EntityTypes::Web) {
|
|
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Text) {
|
|
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
|
|
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
|
|
APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, properties.getTextColor());
|
|
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor());
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Model) {
|
|
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL());
|
|
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, properties.getAnimationURL());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, properties.getAnimationFPS());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, properties.getAnimationFrameIndex());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, properties.getAnimationIsPlaying());
|
|
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings());
|
|
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType()));
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Light) {
|
|
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight());
|
|
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
|
|
APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity());
|
|
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent());
|
|
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff());
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::ParticleEffect) {
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, properties.getAnimationFPS());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, properties.getAnimationFrameIndex());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, properties.getAnimationIsPlaying());
|
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings());
|
|
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures());
|
|
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, properties.getMaxParticles());
|
|
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, properties.getLifespan());
|
|
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, properties.getEmitRate());
|
|
APPEND_ENTITY_PROPERTY(PROP_EMIT_DIRECTION, properties.getEmitDirection());
|
|
APPEND_ENTITY_PROPERTY(PROP_EMIT_STRENGTH, properties.getEmitStrength());
|
|
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, properties.getLocalGravity());
|
|
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Zone) {
|
|
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, properties.getKeyLightColor());
|
|
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, properties.getKeyLightIntensity());
|
|
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, properties.getKeyLightAmbientIntensity());
|
|
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, properties.getKeyLightDirection());
|
|
|
|
_staticStage.setProperties(properties);
|
|
_staticStage.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
|
|
|
|
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType());
|
|
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
|
|
|
|
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)properties.getBackgroundMode());
|
|
|
|
_staticAtmosphere.setProperties(properties);
|
|
_staticAtmosphere.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
|
|
|
|
_staticSkybox.setProperties(properties);
|
|
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::PolyVox) {
|
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, properties.getVoxelVolumeSize());
|
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData());
|
|
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
|
|
}
|
|
|
|
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
|
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
|
}
|
|
if (propertyCount > 0) {
|
|
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
|
|
|
encodedPropertyFlags = propertyFlags;
|
|
int newPropertyFlagsLength = encodedPropertyFlags.length();
|
|
packetData->updatePriorBytes(propertyFlagsOffset,
|
|
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
|
|
|
|
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
|
|
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
|
|
int oldSize = packetData->getUncompressedSize();
|
|
|
|
const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
|
|
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
|
|
int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
|
|
packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
|
|
|
|
int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
|
|
packetData->setUncompressedSize(newSize);
|
|
|
|
} else {
|
|
assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
|
|
}
|
|
|
|
packetData->endLevel(entityLevel);
|
|
} else {
|
|
packetData->discardLevel(entityLevel);
|
|
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
|
|
}
|
|
|
|
// If any part of the model items didn't fit, then the element is considered partial
|
|
if (appendState != OctreeElement::COMPLETED) {
|
|
|
|
// TODO: handle mechanism for handling partial fitting data!
|
|
// add this item into our list for the next appendElementData() pass
|
|
//modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
|
|
|
|
// for now, if it's not complete, it's not successful
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
packetData->endSubTree();
|
|
const unsigned char* finalizedData = packetData->getFinalizedData();
|
|
int finalizedSize = packetData->getFinalizedSize();
|
|
if (finalizedSize <= sizeIn) {
|
|
memcpy(bufferOut, finalizedData, finalizedSize);
|
|
sizeOut = finalizedSize;
|
|
} else {
|
|
qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer.";
|
|
sizeOut = 0;
|
|
success = false;
|
|
}
|
|
} else {
|
|
packetData->discardSubTree();
|
|
sizeOut = 0;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// TODO:
|
|
// how to handle lastEdited?
|
|
// how to handle lastUpdated?
|
|
// consider handling case where no properties are included... we should just ignore this packet...
|
|
//
|
|
// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer
|
|
// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties
|
|
//
|
|
// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property
|
|
// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that
|
|
// utilized the registration table to shorten up and simplify this code.
|
|
//
|
|
// TODO: Implement support for paged properties, spanning MTU, and custom properties
|
|
//
|
|
// TODO: Implement support for script and visible properties.
|
|
//
|
|
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
|
EntityItemID& entityID, EntityItemProperties& properties) {
|
|
bool valid = false;
|
|
|
|
const unsigned char* dataAt = data;
|
|
processedBytes = 0;
|
|
|
|
// the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
|
|
// actually use it, we do need to skip it and read to the actual data we care about.
|
|
int octets = numberOfThreeBitSectionsInCode(data);
|
|
int bytesToReadOfOctcode = bytesRequiredForCodeLength(octets);
|
|
|
|
// we don't actually do anything with this octcode...
|
|
dataAt += bytesToReadOfOctcode;
|
|
processedBytes += bytesToReadOfOctcode;
|
|
|
|
// Edit packets have a last edited time stamp immediately following the octcode.
|
|
// NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust
|
|
// these times for clock skew at this point.
|
|
quint64 lastEdited;
|
|
memcpy(&lastEdited, dataAt, sizeof(lastEdited));
|
|
dataAt += sizeof(lastEdited);
|
|
processedBytes += sizeof(lastEdited);
|
|
properties.setLastEdited(lastEdited);
|
|
|
|
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
|
|
// 1) if the edit is to an existing entity, the created time can not be changed
|
|
// 2) if the edit is to a new entity, the created time is the last edited time
|
|
|
|
// encoded id
|
|
QByteArray encodedID((const char*)dataAt, NUM_BYTES_RFC4122_UUID); // maximum possible size
|
|
QUuid editID = QUuid::fromRfc4122(encodedID);
|
|
dataAt += encodedID.size();
|
|
processedBytes += encodedID.size();
|
|
|
|
entityID = editID;
|
|
valid = true;
|
|
|
|
// Entity Type...
|
|
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
|
|
ByteCountCoded<quint32> typeCoder = encodedType;
|
|
quint32 entityTypeCode = typeCoder;
|
|
properties.setType((EntityTypes::EntityType)entityTypeCode);
|
|
encodedType = typeCoder; // determine true bytesToRead
|
|
dataAt += encodedType.size();
|
|
processedBytes += encodedType.size();
|
|
|
|
// Update Delta - when was this item updated relative to last edit... this really should be 0
|
|
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
|
|
// TODO: do properties need to handle lastupdated???
|
|
|
|
// last updated is stored as ByteCountCoded delta from lastEdited
|
|
QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes));
|
|
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
|
|
encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead
|
|
dataAt += encodedUpdateDelta.size();
|
|
processedBytes += encodedUpdateDelta.size();
|
|
|
|
// TODO: Do we need this lastUpdated?? We don't seem to use it.
|
|
//quint64 updateDelta = updateDeltaCoder;
|
|
//quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited
|
|
|
|
// Property Flags...
|
|
QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes));
|
|
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
|
dataAt += propertyFlags.getEncodedLength();
|
|
processedBytes += propertyFlags.getEncodedLength();
|
|
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, glm::vec3, setGravity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION, glm::vec3, setAcceleration);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RESTITUTION, float, setRestitution);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FRICTION, float, setFriction);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT,QString, setScript);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID);
|
|
|
|
if (properties.getType() == EntityTypes::Web) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Text) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_COLOR, xColor, setTextColor);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, xColor, setBackgroundColor);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Model) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_URL, QString, setAnimationURL);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Light) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, xColor, setColor);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::ParticleEffect) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
|
|
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_DIRECTION, glm::vec3, setEmitDirection);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_STRENGTH, float, setEmitStrength);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::Zone) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, xColor, setKeyLightColor);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection);
|
|
|
|
properties.getStage().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
|
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
|
|
properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
|
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
|
|
}
|
|
|
|
if (properties.getType() == EntityTypes::PolyVox) {
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
|
|
}
|
|
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
// NOTE: This version will only encode the portion of the edit message immediately following the
|
|
// header it does not include the send times and sequence number because that is handled by the
|
|
// edit packet sender...
|
|
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
|
|
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
|
|
|
|
unsigned char* copyAt = outputBuffer;
|
|
uint16_t numberOfIds = 1; // only one entity ID in this message
|
|
|
|
if (maxLength < sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID) {
|
|
qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!";
|
|
outputLength = 0;
|
|
return false;
|
|
}
|
|
memcpy(copyAt, &numberOfIds, sizeof(numberOfIds));
|
|
copyAt += sizeof(numberOfIds);
|
|
outputLength = sizeof(numberOfIds);
|
|
|
|
QUuid entityID = entityItemID;
|
|
QByteArray encodedEntityID = entityID.toRfc4122();
|
|
|
|
memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID);
|
|
copyAt += NUM_BYTES_RFC4122_UUID;
|
|
outputLength += NUM_BYTES_RFC4122_UUID;
|
|
|
|
return true;
|
|
}
|
|
|
|
void EntityItemProperties::markAllChanged() {
|
|
_positionChanged = true;
|
|
_dimensionsChanged = true;
|
|
_rotationChanged = true;
|
|
_densityChanged = true;
|
|
_velocityChanged = true;
|
|
_gravityChanged = true;
|
|
_accelerationChanged = true;
|
|
_dampingChanged = true;
|
|
_restitutionChanged = true;
|
|
_frictionChanged = true;
|
|
_lifetimeChanged = true;
|
|
_userDataChanged = true;
|
|
_simulatorIDChanged = true;
|
|
_scriptChanged = true;
|
|
_collisionSoundURLChanged = true;
|
|
_registrationPointChanged = true;
|
|
_angularVelocityChanged = true;
|
|
_angularDampingChanged = true;
|
|
_nameChanged = true;
|
|
_visibleChanged = true;
|
|
_colorChanged = true;
|
|
_modelURLChanged = true;
|
|
_compoundShapeURLChanged = true;
|
|
_animationURLChanged = true;
|
|
_animationIsPlayingChanged = true;
|
|
_animationFrameIndexChanged = true;
|
|
_animationFPSChanged = true;
|
|
_animationSettingsChanged = true;
|
|
_glowLevelChanged = true;
|
|
_localRenderAlphaChanged = true;
|
|
_isSpotlightChanged = true;
|
|
_ignoreForCollisionsChanged = true;
|
|
_collisionsWillMoveChanged = true;
|
|
|
|
_intensityChanged = true;
|
|
_exponentChanged = true;
|
|
_cutoffChanged = true;
|
|
_lockedChanged = true;
|
|
_texturesChanged = true;
|
|
|
|
_textChanged = true;
|
|
_lineHeightChanged = true;
|
|
_textColorChanged = true;
|
|
_backgroundColorChanged = true;
|
|
_shapeTypeChanged = true;
|
|
|
|
_maxParticlesChanged = true;
|
|
_lifespanChanged = true;
|
|
_emitRateChanged = true;
|
|
_emitDirectionChanged = true;
|
|
_emitStrengthChanged = true;
|
|
_localGravityChanged = true;
|
|
_particleRadiusChanged = true;
|
|
|
|
_marketplaceIDChanged = true;
|
|
|
|
_keyLightColorChanged = true;
|
|
_keyLightIntensityChanged = true;
|
|
_keyLightAmbientIntensityChanged = true;
|
|
_keyLightDirectionChanged = true;
|
|
|
|
_backgroundModeChanged = true;
|
|
_stage.markAllChanged();
|
|
_atmosphere.markAllChanged();
|
|
_skybox.markAllChanged();
|
|
|
|
_sourceUrlChanged = true;
|
|
|
|
_voxelVolumeSizeChanged = true;
|
|
_voxelDataChanged = true;
|
|
_voxelSurfaceStyleChanged = true;
|
|
}
|
|
|
|
/// The maximum bounding cube for the entity, independent of it's rotation.
|
|
/// This accounts for the registration point (upon which rotation occurs around).
|
|
///
|
|
AACube EntityItemProperties::getMaximumAACube() const {
|
|
// * we know that the position is the center of rotation
|
|
glm::vec3 centerOfRotation = _position; // also where _registration point is
|
|
|
|
// * we know that the registration point is the center of rotation
|
|
// * we can calculate the length of the furthest extent from the registration point
|
|
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
|
|
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
|
|
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
|
|
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
|
|
|
|
// * we know that if you rotate in any direction you would create a sphere
|
|
// that has a radius of the length of furthest extent from registration point
|
|
float radius = glm::length(furthestExtentFromRegistration);
|
|
|
|
// * we know that the minimum bounding cube of this maximum possible sphere is
|
|
// (center - radius) to (center + radius)
|
|
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
|
|
float diameter = radius * 2.0f;
|
|
|
|
return AACube(minimumCorner, diameter);
|
|
}
|
|
|
|
// The minimum bounding box for the entity.
|
|
AABox EntityItemProperties::getAABox() const {
|
|
|
|
// _position represents the position of the registration point.
|
|
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
|
|
|
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
|
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
|
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
|
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
|
|
|
// shift the extents to be relative to the position/registration point
|
|
rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position);
|
|
|
|
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
|
}
|
|
|
|
bool EntityItemProperties::hasTerseUpdateChanges() const {
|
|
// a TerseUpdate includes the transform and its derivatives
|
|
return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged;
|
|
}
|