diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 0ced0a632e..c8067ce81f 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -30,6 +30,8 @@ #include #include +#include // for EntityScriptServerServices + #include "EntityScriptServerLogging.h" #include "../entities/AssignmentParentFinder.h" @@ -68,6 +70,9 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig DependencyManager::set(); DependencyManager::set(ScriptEngine::ENTITY_SERVER_SCRIPT); + DependencyManager::set(); + + // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); @@ -583,6 +588,7 @@ void EntityScriptServer::aboutToFinish() { // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); // cleanup codec & encoder if (_codec && _encoder) { diff --git a/interface/src/ui/overlays/Billboardable.cpp b/interface/src/ui/overlays/Billboardable.cpp index 34a4ef6df5..892a9d998d 100644 --- a/interface/src/ui/overlays/Billboardable.cpp +++ b/interface/src/ui/overlays/Billboardable.cpp @@ -3,6 +3,7 @@ // interface/src/ui/overlays // // Created by Zander Otavka on 8/7/15. +// Modified by Daniela Fontes on 24/10/17. // Copyright 2014 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -13,6 +14,7 @@ #include #include +#include "avatar/AvatarManager.h" void Billboardable::setProperties(const QVariantMap& properties) { auto isFacingAvatar = properties["isFacingAvatar"]; @@ -32,10 +34,11 @@ bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offse if (isFacingAvatar()) { glm::vec3 billboardPos = transform.getTranslation(); glm::vec3 cameraPos = qApp->getCamera().getPosition(); - glm::vec3 look = cameraPos - billboardPos; - float elevation = -asinf(look.y / glm::length(look)); - float azimuth = atan2f(look.x, look.z); - glm::quat rotation(glm::vec3(elevation, azimuth, 0)); + // use the referencial from the avatar, y isn't always up + glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getOrientation()*Vectors::UP; + + glm::quat rotation(conjugate(toQuat(glm::lookAt(billboardPos, cameraPos, avatarUP)))); + transform.setRotation(rotation); transform.postRotate(offsetRotation); return true; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 07c5694a2a..f9e88b430f 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -50,7 +50,9 @@ void EntityRenderer::initEntityRenderers() { REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory) } - +const Transform& EntityRenderer::getModelTransform() const { + return _modelTransform; +} void EntityRenderer::makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters) { auto nodeList = DependencyManager::get(); diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 34dbceb643..d770e7c7aa 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -105,8 +105,10 @@ protected: template std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } + static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters); static std::function _entitiesShouldFadeFunction; + const Transform& getModelTransform() const; SharedSoundPointer _collisionSound; QUuid _changeHandlerId; @@ -114,7 +116,6 @@ protected: quint64 _fadeStartTime{ usecTimestampNow() }; bool _isFading{ _entitiesShouldFadeFunction() }; bool _prevIsTransparent { false }; - Transform _modelTransform; Item::Bound _bound; bool _visible { false }; bool _moving { false }; @@ -123,6 +124,10 @@ protected: private: + // The base class relies on comparing the model transform to the entity transform in order + // to trigger an update, so the member must not be visible to derived classes as a modifiable + // transform + Transform _modelTransform; // The rendering code only gets access to the entity in very specific circumstances // i.e. to see if the rendering code needs to update because of a change in state of the // entity. This forces all the rendering code itself to be independent of the entity diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index ca6ad5a32b..9ac7e9921f 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -49,9 +49,10 @@ void LineEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLineEntityItem::render"); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; + const auto& modelTransform = getModelTransform(); Transform transform = Transform(); - transform.setTranslation(_modelTransform.getTranslation()); - transform.setRotation(_modelTransform.getRotation()); + transform.setTranslation(modelTransform.getTranslation()); + transform.setRotation(modelTransform.getRotation()); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0f764d3a29..ff5bce4607 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1311,7 +1311,7 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { if (!model || (model && model->didVisualGeometryRequestFail())) { static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); gpu::Batch& batch = *args->_batch; - batch.setModelTransform(_modelTransform); // we want to include the scale as well + batch.setModelTransform(getModelTransform()); // we want to include the scale as well DependencyManager::get()->renderWireCubeInstance(args, batch, greenColor); return; } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 3328076911..facf762288 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -251,12 +251,13 @@ void ParticleEffectEntityRenderer::stepSimulation() { }); if (_emitting && particleProperties.emitting()) { + const auto& modelTransform = getModelTransform(); uint64_t emitInterval = particleProperties.emitIntervalUsecs(); if (emitInterval > 0 && interval >= _timeUntilNextEmit) { auto timeRemaining = interval; while (timeRemaining > _timeUntilNextEmit) { // emit particle - _cpuParticles.push_back(createParticle(now, _modelTransform, particleProperties)); + _cpuParticles.push_back(createParticle(now, modelTransform, particleProperties)); _timeUntilNextEmit = emitInterval; if (emitInterval < timeRemaining) { timeRemaining -= emitInterval; @@ -315,7 +316,7 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) { // In trail mode, the particles are created in world space. // so we only set a transform if they're not in trail mode if (!_particleProperties.emission.shouldTrail) { - transform = _modelTransform; + transform = getModelTransform(); transform.setScale(vec3(1)); } batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 4028f105c8..7d7de0c08f 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -76,6 +76,14 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin return true; } + if (_shape != entity->getShape()) { + return true; + } + + if (_dimensions != entity->getDimensions()) { + return true; + } + return false; } @@ -93,12 +101,13 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _position = entity->getPosition(); _dimensions = entity->getDimensions(); _orientation = entity->getOrientation(); + _renderTransform = getModelTransform(); if (_shape == entity::Sphere) { - _modelTransform.postScale(SPHERE_ENTITY_SCALE); + _renderTransform.postScale(SPHERE_ENTITY_SCALE); } - _modelTransform.postScale(_dimensions); + _renderTransform.postScale(_dimensions); }); } @@ -133,7 +142,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { glm::vec4 outColor; withReadLock([&] { geometryShape = MAPPING[_shape]; - batch.setModelTransform(_modelTransform); // use a transform with scale, rotation, registration point and translation + batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation outColor = _color; if (_procedural.isReady()) { _procedural.prepare(batch, _position, _dimensions, _orientation); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index f0af5b917a..433cb41ad2 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -32,6 +32,7 @@ private: Procedural _procedural; QString _lastUserData; + Transform _renderTransform; entity::Shape _shape { entity::Sphere }; glm::vec4 _color; glm::vec3 _position; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index b4c64aed6f..6c0f4447ae 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -93,10 +93,11 @@ void TextEntityRenderer::doRender(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; - auto transformToTopLeft = _modelTransform; + const auto& modelTransform = getModelTransform(); + auto transformToTopLeft = modelTransform; if (_faceCamera) { //rotate about vertical to face the camera - glm::vec3 dPosition = args->getViewFrustum().getPosition() - _modelTransform.getTranslation(); + glm::vec3 dPosition = args->getViewFrustum().getPosition() - modelTransform.getTranslation(); // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 4688ef5d2b..4699f2cd8f 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -139,8 +139,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene glm::vec2 windowSize = getWindowSize(entity); _webSurface->resize(QSize(windowSize.x, windowSize.y)); - - _modelTransform.postScale(entity->getDimensions()); + _renderTransform = getModelTransform(); + _renderTransform.postScale(entity->getDimensions()); }); } @@ -180,7 +180,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; withReadLock([&] { - batch.setModelTransform(_modelTransform); + batch.setModelTransform(_renderTransform); }); batch.setResourceTexture(0, _texture); float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 4b7e7e25a1..9c79001dc5 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -62,6 +62,7 @@ private: uint16_t _lastDPI; QTimer _timer; uint64_t _lastRenderTime { 0 }; + Transform _renderTransform; }; } } // namespace diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index f3b664f9b4..0235f1b7a3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -112,6 +112,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_sunIndex)) { _sunIndex = _stage->addLight(_sunLight); + _shadowIndex = _stage->addShadow(_sunIndex); } else { _stage->updateLightArrayBuffer(_sunIndex); } @@ -248,7 +249,8 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { if (entity->getShapeType() == SHAPE_TYPE_SPHERE) { - _modelTransform.postScale(SPHERE_ENTITY_SCALE); + _renderTransform = getModelTransform(); + _renderTransform.postScale(SPHERE_ENTITY_SCALE); } } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 30da96cd9d..050a8a4386 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -88,6 +88,7 @@ private: ComponentMode _hazeMode{ COMPONENT_MODE_INHERIT }; indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX }; + indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX }; indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX }; BackgroundStagePointer _backgroundStage; @@ -119,6 +120,7 @@ private: bool _validSkyboxTexture{ false }; QString _proceduralUserData; + Transform _renderTransform; }; } } // namespace diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 58b8dd22bf..a5586f03ce 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -355,14 +355,6 @@ int EntityItem::expectedBytes() { // clients use this method to unpack FULL updates from entity-server int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - - // NOTE: This shouldn't happen. The only versions of the bit stream that didn't support split mtu buffers should - // be handled by the model subclass and shouldn't call this routine. - qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... " - "ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU"; - return 0; - } setSourceUUID(args.sourceUUID); args.entitiesPerPacket++; @@ -588,34 +580,32 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // Newer bitstreams will have a last simulated and a last updated value quint64 lastSimulatedFromBufferAdjusted = now; - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) { - // last simulated is stored as ByteCountCoded delta from lastEdited - quint64 simulatedDelta; - parser.readCompressedCount(simulatedDelta); + // last simulated is stored as ByteCountCoded delta from lastEdited + quint64 simulatedDelta; + parser.readCompressedCount(simulatedDelta); #ifdef VALIDATE_ENTITY_ITEM_PARSER - { - QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size - ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; - quint64 simulatedDelta2 = simulatedDeltaCoder; - Q_ASSERT(simulatedDelta2 == simulatedDelta); - encodedSimulatedDelta = simulatedDeltaCoder; // determine true length - dataAt += encodedSimulatedDelta.size(); - bytesRead += encodedSimulatedDelta.size(); - Q_ASSERT(parser.offset() == (unsigned int) bytesRead); - } + { + QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size + ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; + quint64 simulatedDelta2 = simulatedDeltaCoder; + Q_ASSERT(simulatedDelta2 == simulatedDelta); + encodedSimulatedDelta = simulatedDeltaCoder; // determine true length + dataAt += encodedSimulatedDelta.size(); + bytesRead += encodedSimulatedDelta.size(); + Q_ASSERT(parser.offset() == (unsigned int) bytesRead); + } #endif - if (overwriteLocalData) { - lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that - if (lastSimulatedFromBufferAdjusted > now) { - lastSimulatedFromBufferAdjusted = now; - } - #ifdef WANT_DEBUG - qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now); - qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); - qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now); - #endif + if (overwriteLocalData) { + lastSimulatedFromBufferAdjusted = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that + if (lastSimulatedFromBufferAdjusted > now) { + lastSimulatedFromBufferAdjusted = now; } + #ifdef WANT_DEBUG + qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now); + qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); + qCDebug(entities) << " lastSimulatedFromBufferAdjusted:" << debugTime(lastSimulatedFromBufferAdjusted, now); + #endif } #ifdef WANT_DEBUG @@ -817,20 +807,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, updateLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) { - READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - } - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName); - READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription); - READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories); - READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist); - READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense); - READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun); - READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber); - READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); - READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID); - } + READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); + READ_ENTITY_PROPERTY(PROP_ITEM_NAME, QString, setItemName); + READ_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString, setItemDescription); + READ_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString, setItemCategories); + READ_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString, setItemArtist); + READ_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString, setItemLicense); + READ_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32, setLimitedRun); + READ_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32, setEditionNumber); + READ_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32, setEntityInstanceNumber); + READ_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString, setCertificateID); READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); @@ -858,10 +844,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover // by doing this parsing here... but it's not likely going to fully recover the content. // - // TODO: Remove this code once we've sufficiently migrated content past this damaged version - if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) { - READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); - } if (overwriteLocalData && (getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES))) { // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 39f19323e3..d34c1e923f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -50,6 +50,10 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership connect(nodeList.data(), &NodeList::canRezCertifiedChanged, this, &EntityScriptingInterface::canRezCertifiedChanged); connect(nodeList.data(), &NodeList::canRezTmpCertifiedChanged, this, &EntityScriptingInterface::canRezTmpCertifiedChanged); connect(nodeList.data(), &NodeList::canWriteAssetsChanged, this, &EntityScriptingInterface::canWriteAssetsChanged); + + + auto& packetReceiver = nodeList->getPacketReceiver(); + packetReceiver.registerListener(PacketType::EntityScriptCallMethod, this, "handleEntityScriptCallMethodPacket"); } void EntityScriptingInterface::queueEntityMessage(PacketType packetType, @@ -571,6 +575,48 @@ void EntityScriptingInterface::callEntityServerMethod(QUuid id, const QString& m DependencyManager::get()->callEntityServerMethod(id, method, params); } +void EntityScriptingInterface::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) { + PROFILE_RANGE(script_entities, __FUNCTION__); + auto scriptServerServices = DependencyManager::get(); + + // this won't be available on clients + if (scriptServerServices) { + scriptServerServices->callEntityClientMethod(clientSessionID, entityID, method, params); + } else { + qWarning() << "Entities.callEntityClientMethod() not allowed in client"; + } +} + + +void EntityScriptingInterface::handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + auto nodeList = DependencyManager::get(); + SharedNodePointer entityScriptServer = nodeList->soloNodeOfType(NodeType::EntityScriptServer); + + if (entityScriptServer == senderNode) { + auto entityID = QUuid::fromRfc4122(receivedMessage->read(NUM_BYTES_RFC4122_UUID)); + + auto method = receivedMessage->readString(); + + quint16 paramCount; + receivedMessage->readPrimitive(¶mCount); + + QStringList params; + for (int param = 0; param < paramCount; param++) { + auto paramString = receivedMessage->readString(); + params << paramString; + } + + std::lock_guard lock(_entitiesScriptEngineLock); + if (_entitiesScriptEngine) { + _entitiesScriptEngine->callEntityScriptMethod(entityID, method, params, senderNode->getUUID()); + } + } +} + + + QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { PROFILE_RANGE(script_entities, __FUNCTION__); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index ee5011e99d..a6d754cf9e 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -189,12 +189,15 @@ public slots: Q_INVOKABLE void deleteEntity(QUuid entityID); /**jsdoc - * Call a method on an entity. Allows a script to call a method on an entity's script. - * The method will execute in the entity script engine. If the entity does not have an - * entity script or the method does not exist, this call will have no effect. - * If it is running an entity script (specified by the `script` property) + * Call a method on an entity in the same context as this function is called. Allows a script + * to call a method on an entity's script. The method will execute in the entity script engine. + * If the entity does not have an entity script or the method does not exist, this call will + * have no effect. If it is running an entity script (specified by the `script` property) * and it exposes a property with the specified name `method`, it will be called - * using `params` as the list of arguments. + * using `params` as the list of arguments. If this is called within an entity script, the + * method will be executed on the client in the entity script engine in which it was called. If + * this is called in an entity server script, the method will be executed on the entity server + * script engine. * * @function Entities.callEntityMethod * @param {EntityID} entityID The ID of the entity to call the method on. @@ -218,6 +221,21 @@ public slots: */ Q_INVOKABLE void callEntityServerMethod(QUuid entityID, const QString& method, const QStringList& params = QStringList()); + /**jsdoc + * Call a client method on an entity on a specific client node. Allows a server entity script to call a + * method on an entity's client script for a particular client. The method will execute in the entity script + * engine on that single client. If the entity does not have an entity script or the method does not exist, or + * the client is not connected to the domain, or you attempt to make this call outside of the entity server + * script, this call will have no effect. + * + * @function Entities.callEntityClientMethod + * @param {SessionID} clientSessionID The session ID of the client to call the method on. + * @param {EntityID} entityID The ID of the entity to call the method on. + * @param {string} method The name of the method to call. + * @param {string[]} params The list of parameters to call the specified method with. + */ + Q_INVOKABLE void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params = QStringList()); + /**jsdoc * finds the closest model to the center point, within the radius * will return a EntityItemID.isKnownID = false if no models are in the radius @@ -447,6 +465,10 @@ protected: std::lock_guard lock(_entitiesScriptEngineLock); function(_entitiesScriptEngine); }; + +private slots: + void handleEntityScriptCallMethodPacket(QSharedPointer receivedMessage, SharedNodePointer senderNode); + private: bool actionWorker(const QUuid& entityID, std::function actor); bool polyVoxWorker(QUuid entityID, std::function actor); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 53e36bc7c7..25e36c8ffb 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -89,8 +89,6 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const override { return true; } virtual PacketType expectedDataPacketType() const override { return PacketType::EntityData; } - virtual bool canProcessVersion(PacketVersion thisVersion) const override - { return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; } virtual bool handlesEditPacketType(PacketType packetType) const override; void fixupTerseEditLogging(EntityItemProperties& properties, QList& changedProperties); virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, @@ -111,9 +109,6 @@ public: virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const override; virtual bool mustIncludeAllChildData() const override { return false; } - virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const override - { return thisVersion >= VERSION_ENTITIES_HAS_FILE_BREAKS; } - virtual void update() override { update(true); } void update(bool simulate); diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 4ba4ad5676..cb17c28fd7 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -102,12 +102,6 @@ EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemPointer EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - EntityItemID tempEntityID; - EntityItemProperties tempProperties; - return constructEntityItem(Model, tempEntityID, tempProperties); - } - // Header bytes // object ID [16 bytes] // ByteCountCoded(type code) [~1 byte] diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index e1ccf8556b..f4944603f1 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -175,35 +175,12 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - if (args.bitstreamVersion < VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - - // _diffuseColor has been renamed to _color - READ_ENTITY_PROPERTY(PROP_DIFFUSE_COLOR, rgbColor, setColor); - - // Ambient and specular color are from an older format and are no longer supported. - // Their values will be ignored. - READ_ENTITY_PROPERTY(PROP_AMBIENT_COLOR_UNUSED, rgbColor, setIgnoredColor); - READ_ENTITY_PROPERTY(PROP_SPECULAR_COLOR_UNUSED, rgbColor, setIgnoredColor); - - // _constantAttenuation has been renamed to _intensity - READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); - - // Linear and quadratic attenuation are from an older format and are no longer supported. - // Their values will be ignored. - READ_ENTITY_PROPERTY(PROP_LINEAR_ATTENUATION_UNUSED, float, setIgnoredAttenuation); - READ_ENTITY_PROPERTY(PROP_QUADRATIC_ATTENUATION_UNUSED, float, setIgnoredAttenuation); - - READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); - } else { - READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); - READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); - READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius); - } + READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); + READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); + READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); + READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); + READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); + READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius); return bytesRead; } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index a5d259ea87..26f063f7cc 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -111,38 +111,19 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); - if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { - setCompoundShapeURL(""); - } else { - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - } - - // Because we're using AnimationLoop which will reset the frame index if you change it's running state - // we want to read these values in the order they appear in the buffer, but call our setters in an - // order that allows AnimationLoop to preserve the correct frame rate. - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setAnimationURL); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setAnimationFPS); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setAnimationCurrentFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); - } - + READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - READ_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings); - } else { - int bytesFromAnimation; - withWriteLock([&] { - // Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer() - // will automatically read into the animation loop - bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, animationPropertiesChanged); - }); + int bytesFromAnimation; + withWriteLock([&] { + // Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer() + // will automatically read into the animation loop + bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData, animationPropertiesChanged); + }); - bytesRead += bytesFromAnimation; - dataAt += bytesFromAnimation; - } + bytesRead += bytesFromAnimation; + dataAt += bytesFromAnimation; READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 1a815de632..b216144ded 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -464,76 +464,40 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch const unsigned char* dataAt = data; READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); - // Because we're using AnimationLoop which will reset the frame index if you change it's running state - // we want to read these values in the order they appear in the buffer, but call our setters in an - // order that allows AnimationLoop to preserve the correct frame rate. - if (args.bitstreamVersion < VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP) { - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool); - SKIP_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, QString); - } else { - READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); - } - + READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); - if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - // OLD PROP_EMIT_VELOCITY FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_EMIT_SPEED, glm::vec3); - } - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_MODIFICATIONS) { - READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); - READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion < VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - // OLD PROP_VELOCITY_SPREAD FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_SPEED_SPREAD, glm::vec3); - } - } else { - // OLD PROP_EMIT_ACCELERATION FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float); - // OLD PROP_ACCELERATION_SPREAD FAKEOUT - SKIP_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float); - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - } + READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); + READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); + READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); + READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); - READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); - READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - } + READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); + READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); + READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) { - READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); - READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart); - READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); - READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); - READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - } + READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread); + READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart); + READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish); + READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); + READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); + READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); + READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER) { - READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); - READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); - READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation); - READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); - READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); - READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); - READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - } + READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); + READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); + READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, glm::quat, setEmitOrientation); + READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); + READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); + READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); + READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); + READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); + READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) { - READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); - } + READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); return bytesRead; } diff --git a/libraries/networking/src/EntityScriptClient.cpp b/libraries/networking/src/EntityScriptClient.cpp index 399cb80bfa..75ae7369fb 100644 --- a/libraries/networking/src/EntityScriptClient.cpp +++ b/libraries/networking/src/EntityScriptClient.cpp @@ -92,6 +92,28 @@ void EntityScriptClient::callEntityServerMethod(QUuid entityID, const QString& m } } +void EntityScriptServerServices::callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params) { + // only valid to call this function if you are the entity script server + auto nodeList = DependencyManager::get(); + SharedNodePointer targetClient = nodeList->nodeWithUUID(clientSessionID); + + if (nodeList->getOwnerType() == NodeType::EntityScriptServer && targetClient) { + auto packetList = NLPacketList::create(PacketType::EntityScriptCallMethod, QByteArray(), true, true); + + packetList->write(entityID.toRfc4122()); + + packetList->writeString(method); + + quint16 paramCount = params.length(); + packetList->writePrimitive(paramCount); + + foreach(const QString& param, params) { + packetList->writeString(param); + } + + nodeList->sendPacketList(std::move(packetList), *targetClient); + } +} MessageID EntityScriptClient::getEntityServerScriptStatus(QUuid entityID, GetScriptStatusCallback callback) { auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/EntityScriptClient.h b/libraries/networking/src/EntityScriptClient.h index 6f1a0376ea..4cfb03dca7 100644 --- a/libraries/networking/src/EntityScriptClient.h +++ b/libraries/networking/src/EntityScriptClient.h @@ -74,4 +74,11 @@ private: void forceFailureOfPendingRequests(SharedNodePointer node); }; + +class EntityScriptServerServices : public QObject, public Dependency { + Q_OBJECT +public: + void callEntityClientMethod(QUuid clientSessionID, QUuid entityID, const QString& method, const QStringList& params); +}; + #endif diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index efb38eede1..ef2768b0af 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -29,9 +29,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_STROKE_COLOR_PROPERTY; case PacketType::EntityPhysics: - return VERSION_ENTITIES_HAZE; + return static_cast(EntityVersion::StrokeColorProperty); + case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::JSONFilterWithFamilyTree); case PacketType::AvatarIdentity: @@ -62,6 +62,9 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::DomainServerAddedNode: return static_cast(DomainServerAddedNodeVersion::PermissionsGrid); + case PacketType::EntityScriptCallMethod: + return static_cast(EntityScriptCallMethodVersion::ClientCallable); + case PacketType::MixedAudio: case PacketType::SilentAudioFrame: case PacketType::InjectAudio: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 9e2eb51fdd..9443ee570d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -194,85 +194,14 @@ void sendWrongProtocolVersionsSignature(bool sendWrongVersion); /// for debuggin uint qHash(const PacketType& key, uint seed); QDebug operator<<(QDebug debug, const PacketType& type); -const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; -const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1; -const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; -const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; -const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; -const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; -const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; -const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6; -const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8; -const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9; -const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10; -const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11; -const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; -const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13; -const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; -const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15; -const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18; -const PacketVersion VERSION_ENTITIES_HAVE_NAMES = 19; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE = 20; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21; -const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_STAGE_HAS_AUTOMATIC_HOURDAY = 22; -const PacketVersion VERSION_ENTITIES_PARTICLE_ENTITIES_HAVE_TEXTURES = 23; -const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24; -const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25; -const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26; -const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27; -const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28; -const PacketVersion VERSION_ENTITIES_LINE_POINTS = 29; -const PacketVersion VERSION_ENTITIES_FACE_CAMERA = 30; -const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP = 31; -const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; -const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33; -const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; -const PacketVersion VERSION_POLYVOX_TEXTURES = 36; -const PacketVersion VERSION_ENTITIES_POLYLINE = 37; -const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38; -const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39; -const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40; -const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41; -const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42; -const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 43; -const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44; -const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45; -const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; -const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; -const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; -const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; -const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; -const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; -const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; -const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53; -const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54; -const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55; -const PacketVersion VERSION_ATMOSPHERE_REMOVED = 56; -const PacketVersion VERSION_LIGHT_HAS_FALLOFF_RADIUS = 57; -const PacketVersion VERSION_ENTITIES_NO_FLY_ZONES = 58; -const PacketVersion VERSION_ENTITIES_MORE_SHAPES = 59; -const PacketVersion VERSION_ENTITIES_PROPERLY_ENCODE_SHAPE_EDITS = 60; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_STATIC_MESH = 61; -const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62; -const PacketVersion VERSION_WEB_ENTITIES_SUPPORT_DPI = 63; -const PacketVersion VERSION_ENTITIES_ARROW_ACTION = 64; -const PacketVersion VERSION_ENTITIES_LAST_EDITED_BY = 65; -const PacketVersion VERSION_ENTITIES_SERVER_SCRIPTS = 66; -const PacketVersion VERSION_ENTITIES_PHYSICS_PACKET = 67; -const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68; -const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69; -const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70; -const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71; -const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72; -const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73; -const PacketVersion VERSION_ENTITIES_HAS_CERTIFICATE_PROPERTIES = 74; -const PacketVersion VERSION_ENTITIES_HAZE = 75; -const PacketVersion VERSION_ENTITIES_UV_MODE_PROPERTY = 76; -const PacketVersion VERSION_ENTITIES_STROKE_COLOR_PROPERTY = 77; +enum class EntityVersion : PacketVersion { + StrokeColorProperty = 77 +}; +enum class EntityScriptCallMethodVersion : PacketVersion { + ServerCallable = 18, + ClientCallable = 19 +}; enum class EntityQueryPacketVersion: PacketVersion { JSONFilter = 18, diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index ad16a97bf6..7563122290 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1721,8 +1721,8 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con device->ungetChar(firstChar); if (firstChar == (char) PacketType::EntityData) { - qCDebug(octree) << "Reading from binary SVO Stream length:" << streamLength; - return readSVOFromStream(streamLength, inputStream); + qCWarning(octree) << "Reading from binary SVO no longer supported"; + return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; return readJSONFromStream(streamLength, inputStream, marketplaceID); @@ -1730,137 +1730,6 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con } -bool Octree::readSVOFromStream(uint64_t streamLength, QDataStream& inputStream) { - qWarning() << "SVO file format depricated. Support for reading SVO files is no longer support and will be removed soon."; - - bool fileOk = false; - - PacketVersion gotVersion = 0; - - uint64_t headerLength = 0; // bytes in the header - - bool wantImportProgress = true; - - PacketType expectedType = expectedDataPacketType(); - PacketVersion expectedVersion = versionForPacketType(expectedType); - bool hasBufferBreaks = versionHasSVOfileBreaks(expectedVersion); - - // before reading the file, check to see if this version of the Octree supports file versions - if (getWantSVOfileVersions()) { - - // read just enough of the file to parse the header... - const uint64_t HEADER_LENGTH = sizeof(int) + sizeof(PacketVersion); - unsigned char fileHeader[HEADER_LENGTH]; - inputStream.readRawData((char*)&fileHeader, HEADER_LENGTH); - - headerLength = HEADER_LENGTH; // we need this later to skip to the data - - unsigned char* dataAt = (unsigned char*)&fileHeader; - uint64_t dataLength = HEADER_LENGTH; - - // if so, read the first byte of the file and see if it matches the expected version code - int intPacketType; - memcpy(&intPacketType, dataAt, sizeof(intPacketType)); - PacketType gotType = (PacketType) intPacketType; - - dataAt += sizeof(expectedType); - dataLength -= sizeof(expectedType); - gotVersion = *dataAt; - - if (gotType == expectedType) { - if (canProcessVersion(gotVersion)) { - dataAt += sizeof(gotVersion); - dataLength -= sizeof(gotVersion); - fileOk = true; - qCDebug(octree, "SVO file version match. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - - hasBufferBreaks = versionHasSVOfileBreaks(gotVersion); - } else { - qCDebug(octree, "SVO file version mismatch. Expected: %d Got: %d", - versionForPacketType(expectedDataPacketType()), gotVersion); - } - } else { - qCDebug(octree) << "SVO file type mismatch. Expected: " << expectedType - << " Got: " << gotType; - } - - } else { - qCDebug(octree) << " NOTE: this file type does not include type and version information."; - fileOk = true; // assume the file is ok - } - - if (hasBufferBreaks) { - qCDebug(octree) << " this version includes buffer breaks"; - } else { - qCDebug(octree) << " this version does not include buffer breaks"; - } - - if (fileOk) { - - // if this version of the file does not include buffer breaks, then we need to load the entire file at once - if (!hasBufferBreaks) { - - // read the entire file into a buffer, WHAT!? Why not. - uint64_t dataLength = streamLength - headerLength; - unsigned char* entireFileDataSection = new unsigned char[dataLength]; - inputStream.readRawData((char*)entireFileDataSection, dataLength); - - unsigned char* dataAt = entireFileDataSection; - - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), wantImportProgress, gotVersion); - - readBitstreamToTree(dataAt, dataLength, args); - delete[] entireFileDataSection; - - } else { - - - uint64_t dataLength = streamLength - headerLength; - uint64_t remainingLength = dataLength; - const uint64_t MAX_CHUNK_LENGTH = MAX_OCTREE_PACKET_SIZE * 2; - unsigned char* fileChunk = new unsigned char[MAX_CHUNK_LENGTH]; - - while (remainingLength > 0) { - quint16 chunkLength = 0; - - inputStream.readRawData((char*)&chunkLength, sizeof(chunkLength)); - remainingLength -= sizeof(chunkLength); - - if (chunkLength > remainingLength) { - qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength - << "greater than remaining length:" << remainingLength; - break; - } - - if (chunkLength > MAX_CHUNK_LENGTH) { - qCDebug(octree) << "UNEXPECTED chunk size of:" << chunkLength - << "greater than MAX_CHUNK_LENGTH:" << MAX_CHUNK_LENGTH; - break; - } - - inputStream.readRawData((char*)fileChunk, chunkLength); - - remainingLength -= chunkLength; - - unsigned char* dataAt = fileChunk; - uint64_t dataLength = chunkLength; - - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, - SharedNodePointer(), wantImportProgress, gotVersion); - - readBitstreamToTree(dataAt, dataLength, args); - } - - delete[] fileChunk; - } - } - - - return fileOk; -} - // hack to get the marketplace id into the entities. We will create a way to get this from a hash of // the entity later, but this helps us move things along for now QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QString& marketplaceID) { diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a2df5f44e5..a252011ba0 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -208,8 +208,6 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return false; } virtual PacketType expectedDataPacketType() const { return PacketType::Unknown; } - virtual bool canProcessVersion(PacketVersion thisVersion) const { - return thisVersion == versionForPacketType(expectedDataPacketType()); } virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } virtual bool handlesEditPacketType(PacketType packetType) const { return false; } virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, @@ -222,11 +220,6 @@ public: virtual void releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { } virtual bool mustIncludeAllChildData() const { return true; } - /// some versions of the SVO file will include breaks with buffer lengths between each buffer chunk in the SVO - /// file. If the Octree subclass expects this for this particular version of the file, it should override this - /// method and return true. - virtual bool versionHasSVOfileBreaks(PacketVersion thisVersion) const { return false; } - virtual void update() { } // nothing to do by default OctreeElementPointer getRoot() { return _rootElement; } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 44e2bd290b..d334a53fa1 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -435,7 +435,7 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I auto lightStage = renderContext->_scene->getStage(); assert(lightStage); assert(lightStage->getNumLights() > 0); - auto lightAndShadow = lightStage->getLightAndShadow(0); + auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { batch.setResourceTexture(Shadow, globalShadow->map); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index e6a33a9911..b6a91888a1 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -498,7 +498,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto lightStage = renderContext->_scene->getStage(); assert(lightStage); assert(lightStage->getNumLights() > 0); - auto lightAndShadow = lightStage->getLightAndShadow(0); + auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; // Bind the shadow buffer @@ -509,7 +509,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, auto& program = deferredLightingEffect->_directionalSkyboxLight; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations; - auto keyLight = lightStage->getLight(0); + auto keyLight = lightAndShadow.first; // Setup the global directional pass pipeline { diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index f9eca755f2..bf46037fd5 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -138,7 +138,8 @@ void main(void) { } // Mix with background at far range - if (distance > 32000.0) { + const float BLEND_DISTANCE = 30000.0; + if (distance > BLEND_DISTANCE) { outFragColor = mix(potentialFragColor, fragColor, hazeParams.backgroundBlendValue); } else { outFragColor = potentialFragColor; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index d0e9f2467e..079c63f367 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -142,6 +142,11 @@ LightStage::LightPointer LightStage::removeLight(Index index) { LightPointer removed = _lights.freeElement(index); if (removed) { + auto shadowId = _descs[index].shadowId; + // Remove shadow if one exists for this light + if (shadowId != INVALID_INDEX) { + _shadows.freeElement(shadowId); + } _lightMap.erase(removed); _descs[index] = Desc(); } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index f946cf699e..66d73c9a6e 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -116,6 +116,30 @@ public: return LightAndShadow(getLight(lightId), getShadow(lightId)); } + LightPointer getCurrentKeyLight() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return _lights.get(keyLightId); + } + + ShadowPointer getCurrentKeyShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return getShadow(keyLightId); + } + + LightAndShadow getCurrentKeyLightAndShadow() const { + Index keyLightId{ 0 }; + if (!_currentFrame._sunLights.empty()) { + keyLightId = _currentFrame._sunLights.front(); + } + return LightAndShadow(getLight(keyLightId), getShadow(keyLightId)); + } + LightStage(); Lights _lights; LightMap _lightMap; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d32857bc65..7171543abc 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -33,10 +33,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - LightStage::Index globalLightIndex { 0 }; - const auto globalLight = lightStage->getLight(globalLightIndex); - const auto shadow = lightStage->getShadow(globalLightIndex); + const auto shadow = lightStage->getCurrentKeyShadow(); if (!shadow) return; const auto& fbo = shadow->framebuffer; @@ -128,20 +126,22 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); - const auto globalShadow = lightStage->getShadow(0); - // Cache old render args - RenderArgs* args = renderContext->args; - output = args->_renderMode; + const auto globalShadow = lightStage->getCurrentKeyShadow(); + if (globalShadow) { + // Cache old render args + RenderArgs* args = renderContext->args; + output = args->_renderMode; - auto nearClip = args->getViewFrustum().getNearClip(); - float nearDepth = -args->_boomOffset.z; - const int SHADOW_FAR_DEPTH = 20; - globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); + auto nearClip = args->getViewFrustum().getNearClip(); + float nearDepth = -args->_boomOffset.z; + const int SHADOW_FAR_DEPTH = 20; + globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_FAR_DEPTH); - // Set the keylight render args - args->pushViewFrustum(*(globalShadow->getFrustum())); - args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + // Set the keylight render args + args->pushViewFrustum(*(globalShadow->getFrustum())); + args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + } } void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) { diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 88d1e627c3..3a422bcb8a 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -3,7 +3,7 @@ // examples // // Created by Brad hefta-Gaub on 10/1/14. -// Modified by Daniela Fontes @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017 +// Modified by Daniela Fontes * @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017 // Copyright 2014 High Fidelity, Inc. // // This script implements a class useful for building tools for editing entities. @@ -203,6 +203,7 @@ SelectionManager = (function() { print("ERROR: entitySelectionTool.update got exception: " + JSON.stringify(e)); } } + }; return that; @@ -1422,11 +1423,11 @@ SelectionDisplay = (function() { Overlays.editOverlay(rollHandle, { scale: handleSize }); - var pos = Vec3.sum(grabberMoveUpPosition, { - x: 0, - y: Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3, - z: 0 - }); + var upDiff = Vec3.multiply(( + Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO * 3), + Quat.getUp(MyAvatar.orientation) + ); + var pos = Vec3.sum(grabberMoveUpPosition, upDiff); Overlays.editOverlay(grabberMoveUp, { position: pos, scale: handleSize / 1.25 @@ -2099,10 +2100,11 @@ SelectionDisplay = (function() { }); var grabberMoveUpOffset = 0.1; + var upVec = Quat.getUp(MyAvatar.orientation); grabberMoveUpPosition = { - x: position.x, - y: position.y + worldTop + grabberMoveUpOffset, - z: position.z + x: position.x + (grabberMoveUpOffset + worldTop) * upVec.x , + y: position.y+ (grabberMoveUpOffset + worldTop) * upVec.y, + z: position.z + (grabberMoveUpOffset + worldTop) * upVec.z }; Overlays.editOverlay(grabberMoveUp, { visible: (!activeTool) || isActiveTool(grabberMoveUp) @@ -2416,9 +2418,6 @@ SelectionDisplay = (function() { mode: "TRANSLATE_UP_DOWN", onBegin: function(event, pickRay, pickResult) { upDownPickNormal = Quat.getForward(lastCameraOrientation); - // Remove y component so the y-axis lies along the plane we're picking on - this will - // give movements that follow the mouse. - upDownPickNormal.y = 0; lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); SelectionManager.saveProperties(); @@ -2455,11 +2454,17 @@ SelectionDisplay = (function() { var newIntersection = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, upDownPickNormal); var vector = Vec3.subtract(newIntersection, lastXYPick); + + // project vector onto avatar up vector + // we want the avatar referential not the camera. + var avatarUpVector = Quat.getUp(MyAvatar.orientation); + var dotVectorUp = Vec3.dot(vector, avatarUpVector); + vector = Vec3.multiply(dotVectorUp, avatarUpVector); + + vector = grid.snapToGrid(vector); - // we only care about the Y axis - vector.x = 0; - vector.z = 0; + var wantDebug = false; if (wantDebug) {