From d4abdcb6c8e1df93e9286a7a62458feb2bf31ebc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Mar 2017 14:09:10 -0800 Subject: [PATCH 01/33] comments, namechange, and temporary debug code --- interface/src/Application.cpp | 4 +- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/AvatarManager.h | 2 +- libraries/entities/src/EntityItem.cpp | 21 ++++-- libraries/physics/src/EntityMotionState.cpp | 67 +++++++++++++++++-- .../physics/src/PhysicalEntitySimulation.cpp | 5 +- .../physics/src/PhysicalEntitySimulation.h | 4 +- .../physics/src/ThreadSafeDynamicsWorld.cpp | 3 + 8 files changed, 92 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f870bd9f83..4894ae55ec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4440,8 +4440,8 @@ void Application::update(float deltaTime) { getEntities()->getTree()->withWriteLock([&] { PerformanceTimer perfTimer("handleOutgoingChanges"); const VectorOfMotionStates& outgoingChanges = _physicsEngine->getOutgoingChanges(); - _entitySimulation->handleOutgoingChanges(outgoingChanges); - avatarManager->handleOutgoingChanges(outgoingChanges); + _entitySimulation->handleChangedMotionStates(outgoingChanges); + avatarManager->handleChangedMotionStates(outgoingChanges); }); if (!_aboutToQuit) { diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 94ce444416..6152148887 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -424,7 +424,7 @@ void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) { } } -void AvatarManager::handleOutgoingChanges(const VectorOfMotionStates& motionStates) { +void AvatarManager::handleChangedMotionStates(const VectorOfMotionStates& motionStates) { // TODO: extract the MyAvatar results once we use a MotionState for it. } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index e1f5a3b411..b94f9e6a96 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,7 +70,7 @@ public: void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates); void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates); void getObjectsToChange(VectorOfMotionStates& motionStates); - void handleOutgoingChanges(const VectorOfMotionStates& motionStates); + void handleChangedMotionStates(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")) const; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3ef1648fae..db253b639f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -655,13 +655,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // pack SimulationOwner and terse update properties near each other - // NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data // even when we would otherwise ignore the rest of the packet. bool filterRejection = false; if (propertyFlags.getHasProperty(PROP_SIMULATION_OWNER)) { - QByteArray simOwnerData; int bytes = OctreePacketData::unpackDataFromBytes(dataAt, simOwnerData); SimulationOwner newSimOwner; @@ -676,6 +674,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // or rejects a set of properties, it clears this. In such cases, we don't want those custom // setters to ignore what the server says. filterRejection = newSimOwner.getID().isNull(); + bool verbose = getName() == "fubar"; // adebug + if (verbose && _simulationOwner != newSimOwner) { + std::cout << (void*)(this) << " adebug ownership changed " + << _simulationOwner.getID().toString().toStdString() << "." << (int)_simulationOwner.getPriority() << "-->" + << newSimOwner.getID().toString().toStdString() << "." << (int)newSimOwner.getPriority() + << std::endl; // adebug + } if (weOwnSimulation) { if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) { // entity-server is trying to clear our ownership (probably at our own request) @@ -1879,12 +1884,16 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) { } void EntityItem::updateSimulationOwner(const SimulationOwner& owner) { + // NOTE: this method only used by EntityServer. The Interface uses special code in readEntityDataFromBuffer(). if (wantTerseEditLogging() && _simulationOwner != owner) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner; } if (_simulationOwner.set(owner)) { _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; + if (getName() == "fubar") { + std::cout << "debug updateSimulationOwner() " << _simulationOwner.getID().toString().toStdString() << "." << (int)(_simulationOwner.getPriority()) << std::endl; // adebug + } } } @@ -1892,10 +1901,14 @@ void EntityItem::clearSimulationOwnership() { if (wantTerseEditLogging() && !_simulationOwner.isNull()) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now null"; } + if (getName() == "fubar") { + std::cout << "debug clearSimulationOwnership()" << std::endl; // adebug + } _simulationOwner.clear(); - // don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulationOwnership() - // is only ever called on the entity-server and the flags are only used client-side + // don't bother setting the DIRTY_SIMULATOR_ID flag because: + // (a) when entity-server calls clearSimulationOwnership() the dirty-flags are meaningless (only used by interface) + // (b) the interface only calls clearSimulationOwnership() in a context that already knows best about dirty flags //_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c175a836cc..77c5a4f697 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -27,6 +27,18 @@ #include "EntityTree.h" #endif +// adebug TODO BOOKMARK: +// The problem is that userB may deactivate and disown and object before userA deactivates +// userA will sometimes insert non-zero velocities (and position errors) into the Entity before it is deactivated locally +// +// It would be nice to prevent data export from Bullet to Entity for unowned objects except in cases where it is really needed (?) +// Maybe can recycle _serverPosition and friends to store the "before simulationStep" data to more efficiently figure out +// if data should be used for non-owned objects. +// +// If we do that, we should convert _serverPosition and friends to use Bullet data types for efficiency. +// +// adebug + const uint8_t LOOPS_FOR_SIMULATION_ORPHAN = 50; const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; @@ -111,6 +123,10 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION; _body->setActivationState(WANTS_DEACTIVATION); _outgoingPriority = 0; + bool verbose = _entity->getName() == "fubar"; // adebug + if (verbose) { + std::cout << (void*)(this) << " adebug flag for deactivation" << std::endl; // adebug + } } else { // disowned object is still moving --> start timer for ownership bid // TODO? put a delay in here proportional to distance from object? @@ -118,6 +134,13 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; } _loopsWithoutOwner = 0; + + // adebug BOOKMARK: the problem is that userB may deactivate and disown the Object + // but it may still be active for userA... who will store slightly non-zero velocities into EntityItem in the meantime + // + // It would be nice if we could ignore slight outgoing changes for unowned objects that WANT_DEACTIVATION until... + // (a) the changes exceed some threshold (--> bid for ownership) or... + // (b) they actually get deactivated (--> slam RigidBody positions to agree with EntityItem) } else if (_entity->getSimulatorID() == Physics::getSessionUUID()) { // we just inherited ownership, make sure our desired priority matches what we have upgradeOutgoingPriority(_entity->getSimulationPriority()); @@ -223,11 +246,19 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { // This callback is invoked by the physics simulation at the end of each simulation step... // iff the corresponding RigidBody is DYNAMIC and has moved. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { - if (!_entity) { - return; - } - + assert(_entity); assert(entityTreeIsLocked()); + bool verbose = _entity->getName() == "fubar"; // adebug + // adebug BOOKMARK: the problem is that userB may deactivate and disown the Object + // but it may still be active for userA... who will store slightly non-zero velocities into EntityItem in the meantime + // so what we need to do is ignore setWorldTransform() events for unowned objects when the bullet data is not helpful + // until either the data passes some threshold (bid for it) or + // it goes inactive (at which point we should slam bullet to agree with entity) + if (_body->getActivationState() == WANTS_DEACTIVATION && !_entity->isMoving()) { + if (verbose) { + std::cout << (void*)(this) << " adebug v = " << _body->getLinearVelocity().length() << " w = " << _body->getAngularVelocity().length() << std::endl; // adebug + } + } measureBodyAcceleration(); bool positionSuccess; _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); @@ -245,6 +276,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { "setOrientation failed.*"); qCDebug(physics) << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); } + if (verbose + && (glm::length(getBodyLinearVelocity()) > 0.0f || glm::length(getBodyAngularVelocity()) > 0.0f) + && _entity->getSimulationOwner().getID().isNull()) { + std::cout << (void*)(this) << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug + + } _entity->setVelocity(getBodyLinearVelocity()); _entity->setAngularVelocity(getBodyAngularVelocity()); _entity->setLastSimulated(usecTimestampNow()); @@ -293,6 +330,18 @@ bool EntityMotionState::isCandidateForOwnership() const { assert(_body); assert(_entity); assert(entityTreeIsLocked()); + + /* adebug + bool verbose = _entity->getName() == "fubar"; // adebug + if (verbose) { + bool isCandidate = _outgoingPriority != 0 + || Physics::getSessionUUID() == _entity->getSimulatorID() + || _entity->actionDataNeedsTransmit(); + if (!isCandidate) { + std::cout << (void*)(this) << " adebug not candidate --> erase" << std::endl; // adebug + } + } + */ return _outgoingPriority != 0 || Physics::getSessionUUID() == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit(); @@ -491,6 +540,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) { void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) { assert(_entity); assert(entityTreeIsLocked()); + bool verbose = _entity->getName() == "fubar"; // adebug if (!_body->isActive()) { // make sure all derivatives are zero @@ -576,6 +626,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.clearSimulationOwner(); _outgoingPriority = 0; _entity->setPendingOwnershipPriority(_outgoingPriority, now); + if (verbose) { + std::cout << (void*)(this) << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug + } } else if (Physics::getSessionUUID() != _entity->getSimulatorID()) { // we don't own the simulation for this entity yet, but we're sending a bid for it quint8 bidPriority = glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY); @@ -586,6 +639,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // don't forget to remember that we have made a bid _entity->rememberHasSimulationOwnershipBid(); // ...then reset _outgoingPriority in preparation for the next frame + if (verbose) { + std::cout << (void*)(this) << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug + } _outgoingPriority = 0; } else if (_outgoingPriority != _entity->getSimulationPriority()) { // we own the simulation but our desired priority has changed @@ -597,6 +653,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setSimulationOwner(Physics::getSessionUUID(), _outgoingPriority); } _entity->setPendingOwnershipPriority(_outgoingPriority, now); + if (verbose) { + std::cout << (void*)(this) << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug + } } EntityItemID id(_entity->getID()); diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 903b160a5e..0b0bbcb6fc 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -259,13 +259,14 @@ void PhysicalEntitySimulation::getObjectsToChange(VectorOfMotionStates& result) _pendingChanges.clear(); } -void PhysicalEntitySimulation::handleOutgoingChanges(const VectorOfMotionStates& motionStates) { +void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionStates& motionStates) { QMutexLocker lock(&_mutex); // walk the motionStates looking for those that correspond to entities for (auto stateItr : motionStates) { ObjectMotionState* state = &(*stateItr); - if (state && state->getType() == MOTIONSTATE_TYPE_ENTITY) { + assert(state); + if (state->getType() == MOTIONSTATE_TYPE_ENTITY) { EntityMotionState* entityState = static_cast(state); EntityItemPointer entity = entityState->getEntity(); assert(entity.get()); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index af5def9775..9035308741 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -56,7 +56,7 @@ public: void setObjectsToChange(const VectorOfMotionStates& objectsToChange); void getObjectsToChange(VectorOfMotionStates& result); - void handleOutgoingChanges(const VectorOfMotionStates& motionStates); + void handleChangedMotionStates(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); EntityEditPacketSender* getPacketSender() { return _entityPacketSender; } @@ -67,7 +67,7 @@ private: SetOfEntities _entitiesToAddToPhysics; SetOfEntityMotionStates _pendingChanges; // EntityMotionStates already in PhysicsEngine that need their physics changed - SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we need to send updates to entity-server + SetOfEntityMotionStates _outgoingChanges; // EntityMotionStates for which we may need to send updates to entity-server SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 5fe99f137c..c9cbc6a2be 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -120,6 +120,9 @@ void ThreadSafeDynamicsWorld::synchronizeMotionState(btRigidBody* body) { void ThreadSafeDynamicsWorld::synchronizeMotionStates() { BT_PROFILE("synchronizeMotionStates"); _changedMotionStates.clear(); + + // NOTE: m_synchronizeAllMotionStates is 'false' by default for optimization. + // See PhysicsEngine::init() where we call _dynamicsWorld->setForceUpdateAllAabbs(false) if (m_synchronizeAllMotionStates) { //iterate over all collision objects for (int i=0;i Date: Thu, 9 Mar 2017 17:25:22 -0800 Subject: [PATCH 02/33] restore transform of deactivated entities --- interface/src/Application.cpp | 5 ++- libraries/entities/src/EntityItem.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 39 +++++++++++++++---- libraries/physics/src/EntityMotionState.h | 1 + .../physics/src/PhysicalEntitySimulation.cpp | 13 +++++++ .../physics/src/PhysicalEntitySimulation.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 2 +- libraries/physics/src/PhysicsEngine.h | 3 +- .../physics/src/ThreadSafeDynamicsWorld.cpp | 27 +++++++++---- .../physics/src/ThreadSafeDynamicsWorld.h | 4 ++ 10 files changed, 77 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4894ae55ec..368541490a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4439,7 +4439,10 @@ void Application::update(float deltaTime) { getEntities()->getTree()->withWriteLock([&] { PerformanceTimer perfTimer("handleOutgoingChanges"); - const VectorOfMotionStates& outgoingChanges = _physicsEngine->getOutgoingChanges(); + const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates(); + _entitySimulation->handleDeactivatedMotionStates(deactivations); + + const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates(); _entitySimulation->handleChangedMotionStates(outgoingChanges); avatarManager->handleChangedMotionStates(outgoingChanges); }); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index db253b639f..888de44505 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -676,7 +676,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef filterRejection = newSimOwner.getID().isNull(); bool verbose = getName() == "fubar"; // adebug if (verbose && _simulationOwner != newSimOwner) { - std::cout << (void*)(this) << " adebug ownership changed " + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug ownership changed " << _simulationOwner.getID().toString().toStdString() << "." << (int)_simulationOwner.getPriority() << "-->" << newSimOwner.getID().toString().toStdString() << "." << (int)newSimOwner.getPriority() << std::endl; // adebug diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 77c5a4f697..5da9d52169 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -10,6 +10,7 @@ // #include +#include // adebug #include #include @@ -28,7 +29,8 @@ #endif // adebug TODO BOOKMARK: -// The problem is that userB may deactivate and disown and object before userA deactivates +// Consider an object near deactivation owned by userB and in view of userA... +// The problem is that userB may deactivate and disown the object before userA deactivates // userA will sometimes insert non-zero velocities (and position errors) into the Entity before it is deactivated locally // // It would be nice to prevent data export from Bullet to Entity for unowned objects except in cases where it is really needed (?) @@ -109,6 +111,24 @@ void EntityMotionState::updateServerPhysicsVariables() { _serverActionData = _entity->getActionData(); } +void EntityMotionState::handleDeactivation() { + // adebug + glm::vec3 pos = _entity->getPosition(); + float dx = glm::distance(pos, _serverPosition); + glm::vec3 v = _entity->getVelocity(); + float dv = glm::distance(v, _serverVelocity); + std::cout << "adebug deactivate '" << _entity->getName().toStdString() + << "' dx = " << dx << " dv = " << dv << std::endl; // adebug + // adebug + + // copy _server data to entity + bool success; + _entity->setPosition(_serverPosition, success, false); + _entity->setOrientation(_serverRotation, success, false); + _entity->setVelocity(ENTITY_ITEM_ZERO_VEC3); + _entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); +} + // virtual void EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); @@ -125,7 +145,7 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _outgoingPriority = 0; bool verbose = _entity->getName() == "fubar"; // adebug if (verbose) { - std::cout << (void*)(this) << " adebug flag for deactivation" << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug flag for deactivation" << std::endl; // adebug } } else { // disowned object is still moving --> start timer for ownership bid @@ -244,7 +264,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { } // This callback is invoked by the physics simulation at the end of each simulation step... -// iff the corresponding RigidBody is DYNAMIC and has moved. +// iff the corresponding RigidBody is DYNAMIC and ACTIVE. void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(_entity); assert(entityTreeIsLocked()); @@ -256,7 +276,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { // it goes inactive (at which point we should slam bullet to agree with entity) if (_body->getActivationState() == WANTS_DEACTIVATION && !_entity->isMoving()) { if (verbose) { - std::cout << (void*)(this) << " adebug v = " << _body->getLinearVelocity().length() << " w = " << _body->getAngularVelocity().length() << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug entity at rest but physics is not?" + << " v = " << _body->getLinearVelocity().length() + << " w = " << _body->getAngularVelocity().length() + << std::endl; // adebug } } measureBodyAcceleration(); @@ -279,7 +302,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { if (verbose && (glm::length(getBodyLinearVelocity()) > 0.0f || glm::length(getBodyAngularVelocity()) > 0.0f) && _entity->getSimulationOwner().getID().isNull()) { - std::cout << (void*)(this) << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug } _entity->setVelocity(getBodyLinearVelocity()); @@ -627,7 +650,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _outgoingPriority = 0; _entity->setPendingOwnershipPriority(_outgoingPriority, now); if (verbose) { - std::cout << (void*)(this) << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug } } else if (Physics::getSessionUUID() != _entity->getSimulatorID()) { // we don't own the simulation for this entity yet, but we're sending a bid for it @@ -640,7 +663,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ _entity->rememberHasSimulationOwnershipBid(); // ...then reset _outgoingPriority in preparation for the next frame if (verbose) { - std::cout << (void*)(this) << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug } _outgoingPriority = 0; } else if (_outgoingPriority != _entity->getSimulationPriority()) { @@ -654,7 +677,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ } _entity->setPendingOwnershipPriority(_outgoingPriority, now); if (verbose) { - std::cout << (void*)(this) << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug + std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index feac47d8ec..380edf3927 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -29,6 +29,7 @@ public: virtual ~EntityMotionState(); void updateServerPhysicsVariables(); + void handleDeactivation(); virtual void handleEasyChanges(uint32_t& flags) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 0b0bbcb6fc..bd76b2d70f 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -259,6 +259,19 @@ void PhysicalEntitySimulation::getObjectsToChange(VectorOfMotionStates& result) _pendingChanges.clear(); } +void PhysicalEntitySimulation::handleDeactivatedMotionStates(const VectorOfMotionStates& motionStates) { + for (auto stateItr : motionStates) { + ObjectMotionState* state = &(*stateItr); + assert(state); + if (state->getType() == MOTIONSTATE_TYPE_ENTITY) { + EntityMotionState* entityState = static_cast(state); + entityState->handleDeactivation(); + EntityItemPointer entity = entityState->getEntity(); + _entitiesToSort.insert(entity); + } + } +} + void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionStates& motionStates) { QMutexLocker lock(&_mutex); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 9035308741..5f6185add3 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -56,6 +56,7 @@ public: void setObjectsToChange(const VectorOfMotionStates& objectsToChange); void getObjectsToChange(VectorOfMotionStates& result); + void handleDeactivatedMotionStates(const VectorOfMotionStates& motionStates); void handleChangedMotionStates(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index f57be4eab3..7d97d25135 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -449,7 +449,7 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() { return _collisionEvents; } -const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() { +const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() { BT_PROFILE("copyOutgoingChanges"); // Bullet will not deactivate static objects (it doesn't expect them to be active) // so we must deactivate them ourselves diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index bbafbb06b6..b2ebe58f08 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -65,7 +65,8 @@ public: bool hasOutgoingChanges() const { return _hasOutgoingChanges; } /// \return reference to list of changed MotionStates. The list is only valid until beginning of next simulation loop. - const VectorOfMotionStates& getOutgoingChanges(); + const VectorOfMotionStates& getChangedMotionStates(); + const VectorOfMotionStates& getDeactivatedMotionStates() const { return _dynamicsWorld->getDeactivatedMotionStates(); } /// \return reference to list of Collision events. The list is only valid until beginning of next simulation loop. const CollisionEvents& getCollisionEvents(); diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index c9cbc6a2be..3c05257fc5 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -128,25 +128,36 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { for (int i=0;igetMotionState()) { - synchronizeMotionState(body); - _changedMotionStates.push_back(static_cast(body->getMotionState())); - } + if (body && body->getMotionState()) { + synchronizeMotionState(body); + _changedMotionStates.push_back(static_cast(body->getMotionState())); } } } else { //iterate over all active rigid bodies + // TODO? if this becomes a performance bottleneck we could derive our own SimulationIslandManager + // that remembers a list of objects it recently deactivated + _activeStates.clear(); + _deactivatedStates.clear(); for (int i=0;iisActive()) { - if (body->getMotionState()) { + ObjectMotionState* motionState = static_cast(body->getMotionState()); + if (motionState) { + if (body->isActive()) { synchronizeMotionState(body); - _changedMotionStates.push_back(static_cast(body->getMotionState())); + _changedMotionStates.push_back(motionState); + _activeStates.insert(motionState); + } else if (_lastActiveStates.find(motionState) != _lastActiveStates.end()) { + // this object was active last frame but is no longer + _deactivatedStates.push_back(motionState); } } } } + if (_deactivatedStates.size() > 0) { + std::cout << secTimestampNow() << " adebug num deactivated = " << _deactivatedStates.size() << std::endl; // adebug + } + _activeStates.swap(_lastActiveStates); } void ThreadSafeDynamicsWorld::saveKinematicState(btScalar timeStep) { diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.h b/libraries/physics/src/ThreadSafeDynamicsWorld.h index 68062d8d29..b4fcca8cdb 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.h +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.h @@ -49,12 +49,16 @@ public: float getLocalTimeAccumulation() const { return m_localTime; } const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; } + const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; } private: // call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState() void synchronizeMotionState(btRigidBody* body); VectorOfMotionStates _changedMotionStates; + VectorOfMotionStates _deactivatedStates; + SetOfMotionStates _activeStates; + SetOfMotionStates _lastActiveStates; }; #endif // hifi_ThreadSafeDynamicsWorld_h From be3012181fee72dcdefaa39c189f5447b82b3058 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Mar 2017 17:53:17 -0800 Subject: [PATCH 03/33] force local deactivation on remote deactivation --- libraries/physics/src/EntityMotionState.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 5da9d52169..03bcc43362 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -143,6 +143,8 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION; _body->setActivationState(WANTS_DEACTIVATION); _outgoingPriority = 0; + const float ACTIVATION_EXPIRY = 3.0f; // something larger than the 2.0 hard coded in Bullet + _body->setDeactivationTime(ACTIVATION_EXPIRY); bool verbose = _entity->getName() == "fubar"; // adebug if (verbose) { std::cout << (void*)(this) << " " << secTimestampNow() << " adebug flag for deactivation" << std::endl; // adebug From a16760278e5f84844604a8eda1e76dc379b19cfc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 9 Mar 2017 17:58:53 -0800 Subject: [PATCH 04/33] remove debug code --- libraries/entities/src/EntityItem.cpp | 13 ---- libraries/physics/src/EntityMotionState.cpp | 76 ------------------- .../physics/src/ThreadSafeDynamicsWorld.cpp | 5 +- 3 files changed, 1 insertion(+), 93 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 888de44505..0bb085459e 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -674,13 +674,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // or rejects a set of properties, it clears this. In such cases, we don't want those custom // setters to ignore what the server says. filterRejection = newSimOwner.getID().isNull(); - bool verbose = getName() == "fubar"; // adebug - if (verbose && _simulationOwner != newSimOwner) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug ownership changed " - << _simulationOwner.getID().toString().toStdString() << "." << (int)_simulationOwner.getPriority() << "-->" - << newSimOwner.getID().toString().toStdString() << "." << (int)newSimOwner.getPriority() - << std::endl; // adebug - } if (weOwnSimulation) { if (newSimOwner.getID().isNull() && !_simulationOwner.pendingRelease(lastEditedFromBufferAdjusted)) { // entity-server is trying to clear our ownership (probably at our own request) @@ -1891,9 +1884,6 @@ void EntityItem::updateSimulationOwner(const SimulationOwner& owner) { if (_simulationOwner.set(owner)) { _dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID; - if (getName() == "fubar") { - std::cout << "debug updateSimulationOwner() " << _simulationOwner.getID().toString().toStdString() << "." << (int)(_simulationOwner.getPriority()) << std::endl; // adebug - } } } @@ -1901,9 +1891,6 @@ void EntityItem::clearSimulationOwnership() { if (wantTerseEditLogging() && !_simulationOwner.isNull()) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now null"; } - if (getName() == "fubar") { - std::cout << "debug clearSimulationOwnership()" << std::endl; // adebug - } _simulationOwner.clear(); // don't bother setting the DIRTY_SIMULATOR_ID flag because: diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 03bcc43362..d80615e2c6 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -10,7 +10,6 @@ // #include -#include // adebug #include #include @@ -28,19 +27,6 @@ #include "EntityTree.h" #endif -// adebug TODO BOOKMARK: -// Consider an object near deactivation owned by userB and in view of userA... -// The problem is that userB may deactivate and disown the object before userA deactivates -// userA will sometimes insert non-zero velocities (and position errors) into the Entity before it is deactivated locally -// -// It would be nice to prevent data export from Bullet to Entity for unowned objects except in cases where it is really needed (?) -// Maybe can recycle _serverPosition and friends to store the "before simulationStep" data to more efficiently figure out -// if data should be used for non-owned objects. -// -// If we do that, we should convert _serverPosition and friends to use Bullet data types for efficiency. -// -// adebug - const uint8_t LOOPS_FOR_SIMULATION_ORPHAN = 50; const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; @@ -112,15 +98,6 @@ void EntityMotionState::updateServerPhysicsVariables() { } void EntityMotionState::handleDeactivation() { - // adebug - glm::vec3 pos = _entity->getPosition(); - float dx = glm::distance(pos, _serverPosition); - glm::vec3 v = _entity->getVelocity(); - float dv = glm::distance(v, _serverVelocity); - std::cout << "adebug deactivate '" << _entity->getName().toStdString() - << "' dx = " << dx << " dv = " << dv << std::endl; // adebug - // adebug - // copy _server data to entity bool success; _entity->setPosition(_serverPosition, success, false); @@ -145,10 +122,6 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _outgoingPriority = 0; const float ACTIVATION_EXPIRY = 3.0f; // something larger than the 2.0 hard coded in Bullet _body->setDeactivationTime(ACTIVATION_EXPIRY); - bool verbose = _entity->getName() == "fubar"; // adebug - if (verbose) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug flag for deactivation" << std::endl; // adebug - } } else { // disowned object is still moving --> start timer for ownership bid // TODO? put a delay in here proportional to distance from object? @@ -156,13 +129,6 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; } _loopsWithoutOwner = 0; - - // adebug BOOKMARK: the problem is that userB may deactivate and disown the Object - // but it may still be active for userA... who will store slightly non-zero velocities into EntityItem in the meantime - // - // It would be nice if we could ignore slight outgoing changes for unowned objects that WANT_DEACTIVATION until... - // (a) the changes exceed some threshold (--> bid for ownership) or... - // (b) they actually get deactivated (--> slam RigidBody positions to agree with EntityItem) } else if (_entity->getSimulatorID() == Physics::getSessionUUID()) { // we just inherited ownership, make sure our desired priority matches what we have upgradeOutgoingPriority(_entity->getSimulationPriority()); @@ -270,20 +236,6 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(_entity); assert(entityTreeIsLocked()); - bool verbose = _entity->getName() == "fubar"; // adebug - // adebug BOOKMARK: the problem is that userB may deactivate and disown the Object - // but it may still be active for userA... who will store slightly non-zero velocities into EntityItem in the meantime - // so what we need to do is ignore setWorldTransform() events for unowned objects when the bullet data is not helpful - // until either the data passes some threshold (bid for it) or - // it goes inactive (at which point we should slam bullet to agree with entity) - if (_body->getActivationState() == WANTS_DEACTIVATION && !_entity->isMoving()) { - if (verbose) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug entity at rest but physics is not?" - << " v = " << _body->getLinearVelocity().length() - << " w = " << _body->getAngularVelocity().length() - << std::endl; // adebug - } - } measureBodyAcceleration(); bool positionSuccess; _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); @@ -301,12 +253,6 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { "setOrientation failed.*"); qCDebug(physics) << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); } - if (verbose - && (glm::length(getBodyLinearVelocity()) > 0.0f || glm::length(getBodyAngularVelocity()) > 0.0f) - && _entity->getSimulationOwner().getID().isNull()) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug - - } _entity->setVelocity(getBodyLinearVelocity()); _entity->setAngularVelocity(getBodyAngularVelocity()); _entity->setLastSimulated(usecTimestampNow()); @@ -355,18 +301,6 @@ bool EntityMotionState::isCandidateForOwnership() const { assert(_body); assert(_entity); assert(entityTreeIsLocked()); - - /* adebug - bool verbose = _entity->getName() == "fubar"; // adebug - if (verbose) { - bool isCandidate = _outgoingPriority != 0 - || Physics::getSessionUUID() == _entity->getSimulatorID() - || _entity->actionDataNeedsTransmit(); - if (!isCandidate) { - std::cout << (void*)(this) << " adebug not candidate --> erase" << std::endl; // adebug - } - } - */ return _outgoingPriority != 0 || Physics::getSessionUUID() == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit(); @@ -565,7 +499,6 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) { void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step) { assert(_entity); assert(entityTreeIsLocked()); - bool verbose = _entity->getName() == "fubar"; // adebug if (!_body->isActive()) { // make sure all derivatives are zero @@ -651,9 +584,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.clearSimulationOwner(); _outgoingPriority = 0; _entity->setPendingOwnershipPriority(_outgoingPriority, now); - if (verbose) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug - } } else if (Physics::getSessionUUID() != _entity->getSimulatorID()) { // we don't own the simulation for this entity yet, but we're sending a bid for it quint8 bidPriority = glm::max(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY); @@ -664,9 +594,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // don't forget to remember that we have made a bid _entity->rememberHasSimulationOwnershipBid(); // ...then reset _outgoingPriority in preparation for the next frame - if (verbose) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug - } _outgoingPriority = 0; } else if (_outgoingPriority != _entity->getSimulationPriority()) { // we own the simulation but our desired priority has changed @@ -678,9 +605,6 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setSimulationOwner(Physics::getSessionUUID(), _outgoingPriority); } _entity->setPendingOwnershipPriority(_outgoingPriority, now); - if (verbose) { - std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug - } } EntityItemID id(_entity->getID()); diff --git a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp index 3c05257fc5..24cfbc2609 100644 --- a/libraries/physics/src/ThreadSafeDynamicsWorld.cpp +++ b/libraries/physics/src/ThreadSafeDynamicsWorld.cpp @@ -136,7 +136,7 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() { } else { //iterate over all active rigid bodies // TODO? if this becomes a performance bottleneck we could derive our own SimulationIslandManager - // that remembers a list of objects it recently deactivated + // that remembers a list of objects deactivated last step _activeStates.clear(); _deactivatedStates.clear(); for (int i=0;i 0) { - std::cout << secTimestampNow() << " adebug num deactivated = " << _deactivatedStates.size() << std::endl; // adebug - } _activeStates.swap(_lastActiveStates); } From 9c9eb879255d3136b321622d0b221196a27e96d9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Mar 2017 12:55:16 -0800 Subject: [PATCH 05/33] sync RigidBody on deactivation --- libraries/physics/src/EntityMotionState.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d80615e2c6..bfa15537fc 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -104,6 +104,11 @@ void EntityMotionState::handleDeactivation() { _entity->setOrientation(_serverRotation, success, false); _entity->setVelocity(ENTITY_ITEM_ZERO_VEC3); _entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); + // and also to RigidBody + btTransform worldTrans; + worldTrans.setOrigin(glmToBullet(_serverPosition)); + worldTrans.setRotation(glmToBullet(_serverRotation)); + // no need to update velocities... should already be zero } // virtual From bde2222dfd758292f8ac0ca6c3e26ec3dd6c492b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 10 Mar 2017 18:30:56 -0800 Subject: [PATCH 06/33] actually use worldTrans --- libraries/physics/src/EntityMotionState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index bfa15537fc..d383f4c199 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -108,6 +108,7 @@ void EntityMotionState::handleDeactivation() { btTransform worldTrans; worldTrans.setOrigin(glmToBullet(_serverPosition)); worldTrans.setRotation(glmToBullet(_serverRotation)); + _body->setWorldTransform(worldTrans); // no need to update velocities... should already be zero } From 0926b2df2a1b1c880d44f33a3d0ce0004d2697f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 13 Mar 2017 15:14:20 -0700 Subject: [PATCH 07/33] add LX snap turn to standard mapping --- interface/resources/controllers/standard.json | 32 ++++++++++++------- ...oggleAdvancedMovementForHandControllers.js | 1 - 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index 04a3f560b6..b0654daaa7 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -2,6 +2,18 @@ "name": "Standard to Action", "channels": [ { "from": "Standard.LY", "to": "Actions.TranslateZ" }, + + { "from": "Standard.LX", + "when": [ "Application.InHMD", "Application.SnapTurn" ], + "to": "Actions.StepYaw", + "filters": + [ + { "type": "deadZone", "min": 0.15 }, + "constrainToInteger", + { "type": "pulse", "interval": 0.25 }, + { "type": "scale", "scale": 22.5 } + ] + }, { "from": "Standard.LX", "to": "Actions.TranslateX" }, { "from": "Standard.RX", @@ -15,29 +27,27 @@ { "type": "scale", "scale": 22.5 } ] }, - { "from": "Standard.RX", "to": "Actions.Yaw" }, - { "from": "Standard.RY", - "when": "Application.Grounded", - "to": "Actions.Up", - "filters": + + { "from": "Standard.RY", + "when": "Application.Grounded", + "to": "Actions.Up", + "filters": [ { "type": "deadZone", "min": 0.6 }, "invert" ] - }, + }, - { "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"}, + { "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"}, { "from": "Standard.Back", "to": "Actions.CycleCamera" }, { "from": "Standard.Start", "to": "Actions.ContextMenu" }, - { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, + { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" }, - { "from": "Standard.LeftHand", "to": "Actions.LeftHand" }, + { "from": "Standard.LeftHand", "to": "Actions.LeftHand" }, { "from": "Standard.RightHand", "to": "Actions.RightHand" } ] } - - diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 46464dc2e1..61d2df5d9e 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -72,7 +72,6 @@ function registerBasicMapping() { } return; }); - basicMapping.from(Controller.Standard.LX).to(Controller.Standard.RX); basicMapping.from(Controller.Standard.RY).to(function(value) { if (isDisabled) { return; From 1fe02477b0457945d4d8da808e666e3166f391a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 14 Mar 2017 14:21:21 -0700 Subject: [PATCH 08/33] fix LX behaviour in snap/advanced/basic --- interface/resources/controllers/standard.json | 18 ++++++++++++++---- interface/src/Application.cpp | 7 ++++++- interface/src/avatar/MyAvatar.cpp | 1 + interface/src/avatar/MyAvatar.h | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index b0654daaa7..9e3b2f4d13 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -4,7 +4,10 @@ { "from": "Standard.LY", "to": "Actions.TranslateZ" }, { "from": "Standard.LX", - "when": [ "Application.InHMD", "Application.SnapTurn" ], + "when": [ + "Application.InHMD", "!Application.AdvancedMovement", + "Application.SnapTurn", "!Standard.RX" + ], "to": "Actions.StepYaw", "filters": [ @@ -14,7 +17,12 @@ { "type": "scale", "scale": 22.5 } ] }, - { "from": "Standard.LX", "to": "Actions.TranslateX" }, + { "from": "Standard.LX", "to": "Actions.TranslateX", + "when": [ "Application.AdvancedMovement" ] + }, + { "from": "Standard.LX", "to": "Actions.Yaw", + "when": [ "!Application.AdvancedMovement", "!Application.SnapTurn" ] + }, { "from": "Standard.RX", "when": [ "Application.InHMD", "Application.SnapTurn" ], @@ -27,8 +35,10 @@ { "type": "scale", "scale": 22.5 } ] }, - { "from": "Standard.RX", "to": "Actions.Yaw" }, - + { "from": "Standard.RX", "to": "Actions.Yaw", + "when": [ "!Application.SnapTurn" ] + }, + { "from": "Standard.RY", "when": "Application.Grounded", "to": "Actions.Up", diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4bebc80bd1..706fd424fd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -423,6 +423,7 @@ static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson"; static const QString STATE_CAMERA_ENTITY = "CameraEntity"; static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent"; static const QString STATE_SNAP_TURN = "SnapTurn"; +static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement"; static const QString STATE_GROUNDED = "Grounded"; static const QString STATE_NAV_FOCUSED = "NavigationFocused"; @@ -513,7 +514,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, - STATE_SNAP_TURN, STATE_GROUNDED, STATE_NAV_FOCUSED } }); + STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED } }); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -1127,6 +1128,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_SNAP_TURN, []() -> float { return qApp->getMyAvatar()->getSnapTurn() ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_ADVANCED_MOVEMENT_CONTROLS, []() -> float { + return qApp->getMyAvatar()->useAdvancedMovementControls() ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_GROUNDED, []() -> float { return qApp->getMyAvatar()->getCharacterController()->onGround() ? 1 : 0; }); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 969268c549..b045d2c005 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -104,6 +104,7 @@ MyAvatar::MyAvatar(RigPointer rig) : _eyeContactTarget(LEFT_EYE), _realWorldFieldOfView("realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), + _useAdvancedMovementControls("advancedMovementForHandControllersIsChecked", false), _hmdSensorMatrix(), _hmdSensorOrientation(), _hmdSensorPosition(), diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3cc665b533..1a5883edca 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -171,6 +171,8 @@ public: Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; } Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } + bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } + // get/set avatar data void saveData(); void loadData(); @@ -423,6 +425,7 @@ private: glm::vec3 _trackedHeadPosition; Setting::Handle _realWorldFieldOfView; + Setting::Handle _useAdvancedMovementControls; // private methods void updateOrientation(float deltaTime); From 490cb834899c80edd94ad143b0bfc6df0acd606d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 14 Mar 2017 15:03:01 -0700 Subject: [PATCH 09/33] move advanced movement control changes to MyAvatar --- interface/src/avatar/MyAvatar.h | 3 +++ .../toggleAdvancedMovementForHandControllers.js | 14 ++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1a5883edca..f892a8d8b7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -86,6 +86,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) + Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) public: explicit MyAvatar(RigPointer rig); @@ -172,6 +173,8 @@ public: Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } + void setUseAdvancedMovementControls(bool useAdvancedMovementControls) + { _useAdvancedMovementControls.set(useAdvancedMovementControls); } // get/set avatar data void saveData(); diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 61d2df5d9e..a453e50d1b 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -17,15 +17,14 @@ var mappingName, basicMapping, isChecked; var TURN_RATE = 1000; var MENU_ITEM_NAME = "Advanced Movement For Hand Controllers"; -var SETTINGS_KEY = 'advancedMovementForHandControllersIsChecked'; var isDisabled = false; -var previousSetting = Settings.getValue(SETTINGS_KEY); -if (previousSetting === '' || previousSetting === false || previousSetting === 'false') { +var previousSetting = MyAvatar.useAdvancedMovementControls; +if (previousSetting === false) { previousSetting = false; isChecked = false; } -if (previousSetting === true || previousSetting === 'true') { +if (previousSetting === true) { previousSetting = true; isChecked = true; } @@ -37,7 +36,6 @@ function addAdvancedMovementItemToSettingsMenu() { isCheckable: true, isChecked: previousSetting }); - } function rotate180() { @@ -111,10 +109,10 @@ function menuItemEvent(menuItem) { if (menuItem == MENU_ITEM_NAME) { isChecked = Menu.isOptionChecked(MENU_ITEM_NAME); if (isChecked === true) { - Settings.setValue(SETTINGS_KEY, true); + MyAvatar.setUseAdvancedMovementControls(true); disableMappings(); - } else if (isChecked === false) { - Settings.setValue(SETTINGS_KEY, false); + } else if (isChecked === false) + MyAvatar.setUseAdvancedMovementControls(true); enableMappings(); } } From 188530590a18ebe8efc02b94b1f5e60a1304aafc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 14 Mar 2017 17:16:49 -0700 Subject: [PATCH 10/33] add missing curly brace to script --- .../controllers/toggleAdvancedMovementForHandControllers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index a453e50d1b..8371259915 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -111,7 +111,7 @@ function menuItemEvent(menuItem) { if (isChecked === true) { MyAvatar.setUseAdvancedMovementControls(true); disableMappings(); - } else if (isChecked === false) + } else if (isChecked === false) { MyAvatar.setUseAdvancedMovementControls(true); enableMappings(); } From 7ddb5ff7707318083f69ef94faff43524b8f801d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 14 Mar 2017 18:09:17 -0700 Subject: [PATCH 11/33] use correct boolean when changing AMC --- .../controllers/toggleAdvancedMovementForHandControllers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 8371259915..5cf27a0ec5 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -112,7 +112,7 @@ function menuItemEvent(menuItem) { MyAvatar.setUseAdvancedMovementControls(true); disableMappings(); } else if (isChecked === false) { - MyAvatar.setUseAdvancedMovementControls(true); + MyAvatar.setUseAdvancedMovementControls(false); enableMappings(); } } From bfc51d8222f1bd85a5014c557f9bfdcf9322b07e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 14 Mar 2017 18:10:44 -0700 Subject: [PATCH 12/33] use property not function for advanced movement controls --- .../controllers/toggleAdvancedMovementForHandControllers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 5cf27a0ec5..8f8f5c2d3e 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -109,10 +109,10 @@ function menuItemEvent(menuItem) { if (menuItem == MENU_ITEM_NAME) { isChecked = Menu.isOptionChecked(MENU_ITEM_NAME); if (isChecked === true) { - MyAvatar.setUseAdvancedMovementControls(true); + MyAvatar.advancedMovementControls = true; disableMappings(); } else if (isChecked === false) { - MyAvatar.setUseAdvancedMovementControls(false); + MyAvatar.advancedMovementControls = false; enableMappings(); } } From 2d0e11e2d1a54e9b330889dc66d163534458fd2b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 13 Mar 2017 19:22:33 -0400 Subject: [PATCH 13/33] add AudioNoiseGate to recording --- libraries/audio-client/src/AudioClient.cpp | 197 +++++++++------------ libraries/audio-client/src/AudioClient.h | 15 +- 2 files changed, 93 insertions(+), 119 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c32b5600d9..4f8f4c9766 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -184,7 +184,6 @@ AudioClient::AudioClient() : _outgoingAvatarAudioSequenceNumber(0), _audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this), _stats(&_receivedAudioStream), - _inputGate(), _positionGetter(DEFAULT_POSITION_GETTER), _orientationGetter(DEFAULT_ORIENTATION_GETTER) { // avoid putting a lock in the device callback @@ -971,14 +970,87 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { } } -void AudioClient::handleAudioInput() { +void AudioClient::handleAudioInput(QByteArray& audioBuffer) { + if (_muted) { + _lastInputLoudness = 0.0f; + _timeSinceLastClip = 0.0f; + } else { + int16_t* samples = reinterpret_cast(audioBuffer.data()); + int numSamples = audioBuffer.size() / sizeof(AudioConstants::SAMPLE_SIZE); + bool didClip = false; + + bool shouldRemoveDCOffset = !_isPlayingBackRecording && !_isStereoInput; + if (shouldRemoveDCOffset) { + _noiseGate.removeDCOffset(samples, numSamples); + } + + bool shouldNoiseGate = (_isPlayingBackRecording || !_isStereoInput) && _isNoiseGateEnabled; + if (shouldNoiseGate) { + _noiseGate.gateSamples(samples, numSamples); + _lastInputLoudness = _noiseGate.getLastLoudness(); + didClip = _noiseGate.clippedInLastBlock(); + } else { + float loudness = 0.0f; + for (int i = 0; i < numSamples; ++i) { + int16_t sample = std::abs(samples[i]); + loudness += (float)sample; + didClip = didClip || + (sample > (AudioConstants::MAX_SAMPLE_VALUE * AudioNoiseGate::CLIPPING_THRESHOLD)); + } + _lastInputLoudness = fabs(loudness / numSamples); + } + + if (didClip) { + _timeSinceLastClip = 0.0f; + } else if (_timeSinceLastClip >= 0.0f) { + _timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE; + } + + emit inputReceived({ audioBuffer.data(), numSamples }); + + if (_noiseGate.openedInLastBlock()) { + emit noiseGateOpened(); + } else if (_noiseGate.closedInLastBlock()) { + emit noiseGateClosed(); + } + } + + // the codec needs a flush frame before sending silent packets, so + // do not send one if the gate closed in this block (eventually this can be crossfaded). + auto packetType = _shouldEchoToServer ? + PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho; + if (_lastInputLoudness == 0.0f && !_noiseGate.closedInLastBlock()) { + packetType = PacketType::SilentAudioFrame; + _silentOutbound.increment(); + } else { + _audioOutbound.increment(); + } + + Transform audioTransform; + audioTransform.setTranslation(_positionGetter()); + audioTransform.setRotation(_orientationGetter()); + + QByteArray encodedBuffer; + if (_encoder) { + _encoder->encode(audioBuffer, encodedBuffer); + } else { + encodedBuffer = audioBuffer; + } + + emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, + audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, + packetType, _selectedCodecName); + _stats.sentPacket(); +} + +void AudioClient::handleMicAudioInput() { if (!_inputDevice || _isPlayingBackRecording) { return; } // input samples required to produce exactly NETWORK_FRAME_SAMPLES of output - const int inputSamplesRequired = (_inputToNetworkResampler ? - _inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) : + const int inputSamplesRequired = (_inputToNetworkResampler ? + _inputToNetworkResampler->getMinInput(AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) : AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL) * _inputFormat.channelCount(); const auto inputAudioSamples = std::unique_ptr(new int16_t[inputSamplesRequired]); @@ -1001,126 +1073,27 @@ void AudioClient::handleAudioInput() { static int16_t networkAudioSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; while (_inputRingBuffer.samplesAvailable() >= inputSamplesRequired) { - - if (!_muted) { - - - // Increment the time since the last clip - if (_timeSinceLastClip >= 0.0f) { - _timeSinceLastClip += (float)numNetworkSamples / (float)AudioConstants::SAMPLE_RATE; - } - + if (_muted) { + _inputRingBuffer.shiftReadPosition(inputSamplesRequired); + } else { _inputRingBuffer.readSamples(inputAudioSamples.get(), inputSamplesRequired); possibleResampling(_inputToNetworkResampler, inputAudioSamples.get(), networkAudioSamples, inputSamplesRequired, numNetworkSamples, _inputFormat.channelCount(), _desiredInputFormat.channelCount()); - - // Remove DC offset - if (!_isStereoInput) { - _inputGate.removeDCOffset(networkAudioSamples, numNetworkSamples); - } - - // only impose the noise gate and perform tone injection if we are sending mono audio - if (!_isStereoInput && _isNoiseGateEnabled) { - _inputGate.gateSamples(networkAudioSamples, numNetworkSamples); - - // if we performed the noise gate we can get values from it instead of enumerating the samples again - _lastInputLoudness = _inputGate.getLastLoudness(); - - if (_inputGate.clippedInLastBlock()) { - _timeSinceLastClip = 0.0f; - } - - } else { - float loudness = 0.0f; - - for (int i = 0; i < numNetworkSamples; i++) { - int thisSample = std::abs(networkAudioSamples[i]); - loudness += (float)thisSample; - - if (thisSample > (AudioConstants::MAX_SAMPLE_VALUE * AudioNoiseGate::CLIPPING_THRESHOLD)) { - _timeSinceLastClip = 0.0f; - } - } - - _lastInputLoudness = fabs(loudness / numNetworkSamples); - } - - emit inputReceived({ reinterpret_cast(networkAudioSamples), numNetworkBytes }); - - if (_inputGate.openedInLastBlock()) { - emit noiseGateOpened(); - } else if (_inputGate.closedInLastBlock()) { - emit noiseGateClosed(); - } - - } else { - // our input loudness is 0, since we're muted - _lastInputLoudness = 0; - _timeSinceLastClip = 0.0f; - - _inputRingBuffer.shiftReadPosition(inputSamplesRequired); } - - auto packetType = _shouldEchoToServer ? - PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho; - - // if the _inputGate closed in this last frame, then we don't actually want - // to send a silent packet, instead, we want to go ahead and encode and send - // the output from the input gate (eventually, this could be crossfaded) - // and allow the codec to properly encode down to silent/zero. If we still - // have _lastInputLoudness of 0 in our NEXT frame, we will send a silent packet - if (_lastInputLoudness == 0 && !_inputGate.closedInLastBlock()) { - packetType = PacketType::SilentAudioFrame; - _silentOutbound.increment(); - } else { - _micAudioOutbound.increment(); - } - - Transform audioTransform; - audioTransform.setTranslation(_positionGetter()); - audioTransform.setRotation(_orientationGetter()); - // FIXME find a way to properly handle both playback audio and user audio concurrently - - QByteArray decodedBuffer(reinterpret_cast(networkAudioSamples), numNetworkBytes); - QByteArray encodedBuffer; - if (_encoder) { - _encoder->encode(decodedBuffer, encodedBuffer); - } else { - encodedBuffer = decodedBuffer; - } - - emitAudioPacket(encodedBuffer.constData(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, - audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, - packetType, _selectedCodecName); - _stats.sentPacket(); - int bytesInInputRingBuffer = _inputRingBuffer.samplesAvailable() * AudioConstants::SAMPLE_SIZE; float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC)); _stats.updateInputMsUnplayed(msecsInInputRingBuffer); + + QByteArray audioBuffer(reinterpret_cast(networkAudioSamples), numNetworkBytes); + handleAudioInput(audioBuffer); } } -// FIXME - should this go through the noise gate and honor mute and echo? void AudioClient::handleRecordedAudioInput(const QByteArray& audio) { - Transform audioTransform; - audioTransform.setTranslation(_positionGetter()); - audioTransform.setRotation(_orientationGetter()); - - QByteArray encodedBuffer; - if (_encoder) { - _encoder->encode(audio, encodedBuffer); - } else { - encodedBuffer = audio; - } - - _micAudioOutbound.increment(); - - // FIXME check a flag to see if we should echo audio? - emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, - audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale, - PacketType::MicrophoneAudioWithEcho, _selectedCodecName); + QByteArray audioBuffer(audio); + handleAudioInput(audioBuffer); } void AudioClient::prepareLocalAudioInjectors() { @@ -1434,7 +1407,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn lock.unlock(); if (_inputDevice) { - connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleAudioInput())); + connect(_inputDevice, SIGNAL(readyRead()), this, SLOT(handleMicAudioInput())); supportedFormat = true; } else { qCDebug(audioclient) << "Error starting audio input -" << _audioInput->error(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 7e9acc0586..5ed88aa63a 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -124,16 +124,16 @@ public: void selectAudioFormat(const QString& selectedCodecName); Q_INVOKABLE QString getSelectedAudioFormat() const { return _selectedCodecName; } - Q_INVOKABLE bool getNoiseGateOpen() const { return _inputGate.isOpen(); } - Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); } - Q_INVOKABLE float getMicAudioOutboundPPS() const { return _micAudioOutbound.rate(); } + Q_INVOKABLE bool getNoiseGateOpen() const { return _noiseGate.isOpen(); } Q_INVOKABLE float getSilentInboundPPS() const { return _silentInbound.rate(); } Q_INVOKABLE float getAudioInboundPPS() const { return _audioInbound.rate(); } + Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); } + Q_INVOKABLE float getMicAudioOutboundPPS() const { return _audioOutbound.rate(); } const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; } MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; } - float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _inputGate.getMeasuredFloor(), 0.0f); } + float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGate.getMeasuredFloor(), 0.0f); } float getTimeSinceLastClip() const { return _timeSinceLastClip; } float getAudioAverageInputLoudness() const { return _lastInputLoudness; } @@ -180,7 +180,7 @@ public slots: void handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec); void sendDownstreamAudioStatsPacket() { _stats.publish(); } - void handleAudioInput(); + void handleMicAudioInput(); void handleRecordedAudioInput(const QByteArray& audio); void reset(); void audioMixerKilled(); @@ -250,6 +250,7 @@ protected: private: void outputFormatChanged(); + void handleAudioInput(QByteArray& audioBuffer); bool mixLocalAudioInjectors(float* mixBuffer); float azimuthForSource(const glm::vec3& relativePosition); float gainForSource(float distance, float volume); @@ -371,7 +372,7 @@ private: AudioIOStats _stats; - AudioNoiseGate _inputGate; + AudioNoiseGate _noiseGate; AudioPositionGetter _positionGetter; AudioOrientationGetter _orientationGetter; @@ -395,7 +396,7 @@ private: QThread* _checkDevicesThread { nullptr }; RateCounter<> _silentOutbound; - RateCounter<> _micAudioOutbound; + RateCounter<> _audioOutbound; RateCounter<> _silentInbound; RateCounter<> _audioInbound; }; From 789bb7c8550d439748d894d54b7f8e896d319dce Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 14 Mar 2017 19:07:48 +0000 Subject: [PATCH 14/33] rename audio(Mic)OutboundPPS --- interface/resources/qml/Stats.qml | 2 +- interface/src/ui/Stats.cpp | 6 +++--- interface/src/ui/Stats.h | 4 ++-- libraries/audio-client/src/AudioClient.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 564c74b526..6f131d0473 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -198,7 +198,7 @@ Item { } StatText { visible: root.expanded; - text: "Audio Out Mic: " + root.audioMicOutboundPPS + " pps, " + + text: "Audio Out Mic: " + root.audioOutboundPPS + " pps, " + "Silent: " + root.audioSilentOutboundPPS + " pps"; } StatText { diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 923d9f642d..e8cd5409f0 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -220,10 +220,10 @@ void Stats::updateStats(bool force) { STAT_UPDATE(audioMixerInPps, roundf(bandwidthRecorder->getAverageInputPacketsPerSecond(NodeType::AudioMixer))); STAT_UPDATE(audioMixerOutKbps, roundf(bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AudioMixer))); STAT_UPDATE(audioMixerOutPps, roundf(bandwidthRecorder->getAverageOutputPacketsPerSecond(NodeType::AudioMixer))); - STAT_UPDATE(audioMicOutboundPPS, audioClient->getMicAudioOutboundPPS()); - STAT_UPDATE(audioSilentOutboundPPS, audioClient->getSilentOutboundPPS()); STAT_UPDATE(audioAudioInboundPPS, audioClient->getAudioInboundPPS()); STAT_UPDATE(audioSilentInboundPPS, audioClient->getSilentInboundPPS()); + STAT_UPDATE(audioOutboundPPS, audioClient->getAudioOutboundPPS()); + STAT_UPDATE(audioSilentOutboundPPS, audioClient->getSilentOutboundPPS()); } else { STAT_UPDATE(audioMixerKbps, -1); STAT_UPDATE(audioMixerPps, -1); @@ -231,7 +231,7 @@ void Stats::updateStats(bool force) { STAT_UPDATE(audioMixerInPps, -1); STAT_UPDATE(audioMixerOutKbps, -1); STAT_UPDATE(audioMixerOutPps, -1); - STAT_UPDATE(audioMicOutboundPPS, -1); + STAT_UPDATE(audioOutboundPPS, -1); STAT_UPDATE(audioSilentOutboundPPS, -1); STAT_UPDATE(audioAudioInboundPPS, -1); STAT_UPDATE(audioSilentInboundPPS, -1); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 0ce113e0a0..964c94cd4d 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -77,7 +77,7 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, audioMixerOutPps, 0) STATS_PROPERTY(int, audioMixerKbps, 0) STATS_PROPERTY(int, audioMixerPps, 0) - STATS_PROPERTY(int, audioMicOutboundPPS, 0) + STATS_PROPERTY(int, audioOutboundPPS, 0) STATS_PROPERTY(int, audioSilentOutboundPPS, 0) STATS_PROPERTY(int, audioAudioInboundPPS, 0) STATS_PROPERTY(int, audioSilentInboundPPS, 0) @@ -198,7 +198,7 @@ signals: void audioMixerOutPpsChanged(); void audioMixerKbpsChanged(); void audioMixerPpsChanged(); - void audioMicOutboundPPSChanged(); + void audioOutboundPPSChanged(); void audioSilentOutboundPPSChanged(); void audioAudioInboundPPSChanged(); void audioSilentInboundPPSChanged(); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 5ed88aa63a..0d180c0f5c 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -128,7 +128,7 @@ public: Q_INVOKABLE float getSilentInboundPPS() const { return _silentInbound.rate(); } Q_INVOKABLE float getAudioInboundPPS() const { return _audioInbound.rate(); } Q_INVOKABLE float getSilentOutboundPPS() const { return _silentOutbound.rate(); } - Q_INVOKABLE float getMicAudioOutboundPPS() const { return _audioOutbound.rate(); } + Q_INVOKABLE float getAudioOutboundPPS() const { return _audioOutbound.rate(); } const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; } MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; } From d13752a7c6971e15bc2f4c377192a6adf1e1acd9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 15 Mar 2017 10:34:43 -0700 Subject: [PATCH 15/33] use the correct property name for useAdvancedMovementControls --- .../controllers/toggleAdvancedMovementForHandControllers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js index 8f8f5c2d3e..e6c9b0aee0 100644 --- a/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js +++ b/scripts/system/controllers/toggleAdvancedMovementForHandControllers.js @@ -109,10 +109,10 @@ function menuItemEvent(menuItem) { if (menuItem == MENU_ITEM_NAME) { isChecked = Menu.isOptionChecked(MENU_ITEM_NAME); if (isChecked === true) { - MyAvatar.advancedMovementControls = true; + MyAvatar.useAdvancedMovementControls = true; disableMappings(); } else if (isChecked === false) { - MyAvatar.advancedMovementControls = false; + MyAvatar.useAdvancedMovementControls = false; enableMappings(); } } From e265a0a1f88709bb201f0029bcb4c91e44edf422 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Mar 2017 13:12:30 -0700 Subject: [PATCH 16/33] Fix possible crash in Menu::removeSeparator --- libraries/ui/src/ui/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index f68fff0204..a793942056 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -470,8 +470,8 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName if (menu) { int textAt = findPositionOfMenuItem(menu, separatorName); QList menuActions = menu->actions(); - QAction* separatorText = menuActions[textAt]; if (textAt > 0 && textAt < menuActions.size()) { + QAction* separatorText = menuActions[textAt]; QAction* separatorLine = menuActions[textAt - 1]; if (separatorLine) { if (separatorLine->isSeparator()) { From 200550aba98205629014d268c24fb4d749b243ce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Mar 2017 15:22:34 -0700 Subject: [PATCH 17/33] ModelScriptingInterface::appendMeshes --- .../src/RenderablePolyVoxEntityItem.cpp | 1 - libraries/gpu/src/gpu/Buffer.h | 2 +- .../src/ModelScriptingInterface.cpp | 89 ++++++++++++++++++- .../src/ModelScriptingInterface.h | 5 ++ 4 files changed, 94 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 88a0d25b7f..dd62122633 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1574,7 +1574,6 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { bool success = false; MeshProxy* meshProxy = nullptr; - model::MeshPointer mesh = nullptr; withReadLock([&] { if (_meshInitialized) { success = true; diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h index 2507e8e0a6..290b84bef0 100644 --- a/libraries/gpu/src/gpu/Buffer.h +++ b/libraries/gpu/src/gpu/Buffer.h @@ -198,7 +198,7 @@ public: BufferView(const BufferPointer& buffer, Size offset, Size size, const Element& element = DEFAULT_ELEMENT); BufferView(const BufferPointer& buffer, Size offset, Size size, uint16 stride, const Element& element = DEFAULT_ELEMENT); - Size getNumElements() const { return _size / _element.getSize(); } + Size getNumElements() const { return (_size - _offset) / _stride; } //Template iterator with random access on the buffer sysmem template diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 4ba82edf7d..b725548c96 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -12,11 +12,12 @@ #include #include #include +#include "ScriptEngine.h" #include "ModelScriptingInterface.h" #include "OBJWriter.h" - ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) { + _modelScriptEngine = qobject_cast(parent); } QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) { @@ -51,3 +52,89 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { return writeOBJToString(meshes); } + + +QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { + model::MeshPointer result(new model::Mesh()); + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + + size_t totalVertexCount { 0 }; + size_t totalAttributeCount { 0 }; + size_t totalIndexCount { 0 }; + foreach (const MeshProxy* meshProxy, in) { + MeshPointer mesh = meshProxy->getMeshPointer(); + totalVertexCount += mesh->getNumVertices(); + totalAttributeCount += mesh->getNumAttributes(); + totalIndexCount += mesh->getNumIndices(); + } + + gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3); + unsigned char* combinedVertexData = new unsigned char[combinedVertexSize]; + unsigned char* combinedVertexDataCursor = combinedVertexData; + + gpu::Resource::Size combinedNormalSize = totalVertexCount * sizeof(glm::vec3); + unsigned char* combinedNormalData = new unsigned char[combinedNormalSize]; + unsigned char* combinedNormalDataCursor = combinedNormalData; + + gpu::Resource::Size combinedIndexSize = totalVertexCount * sizeof(uint32_t); + unsigned char* combinedIndexData = new unsigned char[combinedIndexSize]; + unsigned char* combinedIndexDataCursor = combinedIndexData; + + uint32_t indexStartOffset { 0 }; + + foreach (const MeshProxy* meshProxy, in) { + MeshPointer mesh = meshProxy->getMeshPointer(); + + // vertex data + const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + glm::vec3 pos = vertexBufferView.get(i); + memcpy(combinedVertexDataCursor, &pos, sizeof(pos)); + combinedVertexDataCursor += sizeof(pos); + } + + // normal data + const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + glm::vec3 normal = normalsBufferView.get(i); + memcpy(combinedNormalDataCursor, &normal, sizeof(normal)); + combinedNormalDataCursor += sizeof(normal); + } + // TODO -- other attributes + + // face data + const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + uint32_t index = indexBufferView.get(i); + index += indexStartOffset; + memcpy(combinedIndexDataCursor, &index, sizeof(index)); + combinedIndexDataCursor += sizeof(index); + } + + indexStartOffset += numVertices; + } + + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData); + gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer); + gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement); + result->setVertexBuffer(combinedVertexBufferView); + + gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData); + gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer); + gpu::BufferView combinedNormalsBufferView(combinedNormalsBufferPointer, normalElement); + result->addAttribute(attributeTypeNormal, combinedNormalsBufferView); + + gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); + gpu::Buffer* combinedIndexesBuffer = new gpu::Buffer(combinedIndexSize, combinedIndexData); + gpu::BufferPointer combinedIndexesBufferPointer(combinedIndexesBuffer); + gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement); + result->setIndexBuffer(combinedIndexesBufferView); + + MeshProxy* resultProxy = new MeshProxy(result); + return meshToScriptValue(_modelScriptEngine, resultProxy); +} diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 94b7338ae2..7ec8ab46ef 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -20,6 +20,7 @@ #include "MeshProxy.h" using MeshPointer = std::shared_ptr; +class ScriptEngine; class ModelScriptingInterface : public QObject { Q_OBJECT @@ -28,6 +29,10 @@ public: ModelScriptingInterface(QObject* parent); Q_INVOKABLE QString meshToOBJ(MeshProxyList in); + Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in); + +private: + ScriptEngine* _modelScriptEngine { nullptr }; }; QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in); From bbad6a0eb7cb1c6ee32f2ea77dbed6dc7564bc71 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 16 Mar 2017 17:26:07 -0700 Subject: [PATCH 18/33] mesh-append works, mesh-transform doesn't? --- .../entities/src/EntityScriptingInterface.cpp | 13 +++ .../entities/src/EntityScriptingInterface.h | 1 + .../src/ModelScriptingInterface.cpp | 104 +++++++++++++++++- .../src/ModelScriptingInterface.h | 1 + 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ae34024bbc..7eae5b2dc4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1550,3 +1550,16 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons AABox aaBox(low, dimensions); return aaBox.findCapsulePenetration(start, end, radius, penetration); } + +glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { + glm::mat4 result; + if (_entityTree) { + _entityTree->withReadLock([&] { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); + if (entity) { + result = entity->getEntityToWorldMatrix(); + } + }); + } + return result; +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index b0c137ef77..be34317cd5 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -294,6 +294,7 @@ public slots: Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius); + Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID); signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index b725548c96..86a651b6b2 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -55,7 +55,6 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { - model::MeshPointer result(new model::Mesh()); int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h size_t totalVertexCount { 0 }; @@ -72,11 +71,11 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { unsigned char* combinedVertexData = new unsigned char[combinedVertexSize]; unsigned char* combinedVertexDataCursor = combinedVertexData; - gpu::Resource::Size combinedNormalSize = totalVertexCount * sizeof(glm::vec3); + gpu::Resource::Size combinedNormalSize = totalAttributeCount * sizeof(glm::vec3); unsigned char* combinedNormalData = new unsigned char[combinedNormalSize]; unsigned char* combinedNormalDataCursor = combinedNormalData; - gpu::Resource::Size combinedIndexSize = totalVertexCount * sizeof(uint32_t); + gpu::Resource::Size combinedIndexSize = totalIndexCount * sizeof(uint32_t); unsigned char* combinedIndexData = new unsigned char[combinedIndexSize]; unsigned char* combinedIndexDataCursor = combinedIndexData; @@ -96,7 +95,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { // normal data const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { glm::vec3 normal = normalsBufferView.get(i); memcpy(combinedNormalDataCursor, &normal, sizeof(normal)); @@ -106,7 +105,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { // face data const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumAttributes(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { uint32_t index = indexBufferView.get(i); index += indexStartOffset; @@ -117,6 +116,8 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { indexStartOffset += numVertices; } + model::MeshPointer result(new model::Mesh()); + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); gpu::Buffer* combinedVertexBuffer = new gpu::Buffer(combinedVertexSize, combinedVertexData); gpu::BufferPointer combinedVertexBufferPointer(combinedVertexBuffer); @@ -135,6 +136,99 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement); result->setIndexBuffer(combinedIndexesBufferView); + + std::vector parts; + parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex + (model::Index)result->getNumIndices(), // numIndices + (model::Index)0, // baseVertex + model::Mesh::TRIANGLES)); // topology + result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + + MeshProxy* resultProxy = new MeshProxy(result); + return meshToScriptValue(_modelScriptEngine, resultProxy); +} + + +QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + + MeshPointer mesh = meshProxy->getMeshPointer(); + + gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); + unsigned char* resultVertexData = new unsigned char[vertexSize]; + unsigned char* vertexDataCursor = resultVertexData; + + gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); + unsigned char* resultNormalData = new unsigned char[normalSize]; + unsigned char* normalDataCursor = resultNormalData; + + gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); + unsigned char* resultIndexData = new unsigned char[indexSize]; + unsigned char* indexDataCursor = resultIndexData; + + // vertex data + const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + glm::vec3 pos = vertexBufferView.get(i); + pos = glm::vec3(transform * glm::vec4(pos, 0.0f)); + memcpy(vertexDataCursor, &pos, sizeof(pos)); + vertexDataCursor += sizeof(pos); + } + + // normal data + const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + glm::vec3 normal = normalsBufferView.get(i); + normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); + memcpy(normalDataCursor, &normal, sizeof(normal)); + normalDataCursor += sizeof(normal); + } + // TODO -- other attributes + + // face data + const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); + for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + uint32_t index = indexBufferView.get(i); + memcpy(indexDataCursor, &index, sizeof(index)); + indexDataCursor += sizeof(index); + } + + model::MeshPointer result(new model::Mesh()); + + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); + gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); + gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); + result->setVertexBuffer(resultVertexBufferView); + + gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); + gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); + gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); + result->addAttribute(attributeTypeNormal, resultNormalsBufferView); + + gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); + gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); + gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); + gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); + result->setIndexBuffer(resultIndexesBufferView); + + + std::vector parts; + parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex + (model::Index)result->getNumIndices(), // numIndices + (model::Index)0, // baseVertex + model::Mesh::TRIANGLES)); // topology + result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + + MeshProxy* resultProxy = new MeshProxy(result); return meshToScriptValue(_modelScriptEngine, resultProxy); } diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h index 7ec8ab46ef..14789943e3 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.h +++ b/libraries/script-engine/src/ModelScriptingInterface.h @@ -30,6 +30,7 @@ public: Q_INVOKABLE QString meshToOBJ(MeshProxyList in); Q_INVOKABLE QScriptValue appendMeshes(MeshProxyList in); + Q_INVOKABLE QScriptValue transformMesh(glm::mat4 transform, MeshProxy* meshProxy); private: ScriptEngine* _modelScriptEngine { nullptr }; From eba6c8de5e64721c95083d15a0245d0074ef8147 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Fri, 17 Mar 2017 17:37:19 +0000 Subject: [PATCH 19/33] remove About Interface from File menu --- interface/resources/html/img/devices.png | Bin 7492 -> 0 bytes interface/resources/html/img/models.png | Bin 8664 -> 0 bytes interface/resources/html/img/move.png | Bin 6121 -> 0 bytes interface/resources/html/img/run-script.png | Bin 4873 -> 0 bytes interface/resources/html/img/talk.png | Bin 2611 -> 0 bytes interface/resources/html/img/write-script.png | Bin 2006 -> 0 bytes .../resources/html/interface-welcome.html | 187 ------------------ interface/src/Application.cpp | 5 - interface/src/Application.h | 1 - interface/src/Menu.cpp | 3 - interface/src/Menu.h | 1 - 11 files changed, 197 deletions(-) delete mode 100644 interface/resources/html/img/devices.png delete mode 100644 interface/resources/html/img/models.png delete mode 100644 interface/resources/html/img/move.png delete mode 100644 interface/resources/html/img/run-script.png delete mode 100644 interface/resources/html/img/talk.png delete mode 100644 interface/resources/html/img/write-script.png delete mode 100644 interface/resources/html/interface-welcome.html diff --git a/interface/resources/html/img/devices.png b/interface/resources/html/img/devices.png deleted file mode 100644 index fc4231e96e25732a0659c911e7c15ded5b54911b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7492 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 diff --git a/interface/resources/html/img/models.png b/interface/resources/html/img/models.png deleted file mode 100644 index b09c36011d540759da5326ed70bda97592e9636b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8664 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 diff --git a/interface/resources/html/img/run-script.png b/interface/resources/html/img/run-script.png deleted file mode 100644 index 941b8ee9f13664fc2b2ec51a75273ba3e553d3a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4873 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 diff --git a/interface/resources/html/img/write-script.png b/interface/resources/html/img/write-script.png deleted file mode 100644 index dae97e59b14bae50013b583cd9cb3b5bdf6ad464..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2006 zcmb`HX*Ao38pi)h(Ww^WC~;|$Yo=Oy6}h!H%2>+{#aNnJBh9EKC6-vKrnL4lqlR8f z+CxLd)*4blsO1QWsHU;S(vqMgmZY&S_c%TCW#-;9=gheuo-gltK0NP--!H=jVRz~) zwXXmGIOSk(?Fs;Z5CDKBS!n`!Um!t4q*Wpv@1Fw zC@!KOZ4Ll3cn51scl-o@sspQp0s1~_21*qu6P+5Qx8)(@64A${yN;nQG-&a!vK46|YxiCC+UCW# z?78c1pDn_!(s`qA{2QK}Osh^O6w)&nq|Y#8K%!6GZ2QSKTb`%$ z3fZ>{+WbzhbKE8?t5!s}?(f#PZ^l`Cy89ua>7VGH@y;Zlu%JU%-FpS2``0zP)S?M~ zYMcE+3MG7Uj=OMBeYTuBMD$bP8*mLO*t0C(S41!!jdI!=H4CS}wHew%@uOnH0Z!6q zos_8@nng~FU`KAV#e8;03_6sDa8IZg`}c(Z%?KG9_pr}Qda$=!#5pMW2uHg4cCb2Rtjhd*rqmR@Ph0qaA_#**$5H#z#5Q?MJ=)Ym$FZY9?% zS|;<*8MQ}Nr2o58>dbfJE24Op%Qi~X%CMlTv`)|WljBXHaM;DiJZ4^&B916Q8tH`B z-RQPdyR4W#97+6;nfFACb8g?Ma&$S41a8QYlLaXlK!T2Pm6n`mNlVU?fJ$0PA0<^z z7IYK^1HETh;ov5s#Q3_pMbh3JFLrfW89PH2b8Kmi@!LWkWApCXhc|bgSl5s0FiXum zOH6P?>2-|Y#)3HGd^xH%B$d%Dc>UAX!Tv6x z))ph)9&g0hbj*MckS!%+&ZVZ86Ki7DK>eB|4uq?38_etv!)W7hRZ-DI{NAdSd0U7JdT(r6szh|#Qp-YgZ1M|+?autgHT9)N;V z*=+WZE+#tuUAJQfygZURO})$U1FYaQ#g_IR^PIiC=Z=LB^;7cX?RSkMaK*8%=h7iu z$&u;eD}s+&3PSZCR;TJP(Ld&?*l!q;$yn^<>-AoQo`O)_u}9EtJ04EOEg&L9^MlNm z5eV1hasGwKu@{1_2Pb>;wVWSXVm4G{EX(7_nALToi@caH&RYn`95W@l$;-i zzxg}V%;`a%N@yzc?8*kM#E35mz2wCZcn2UTS7|4!+U+>gA*tq?>zzglk-I){VpB1! zv@IRN)o`N7;Ek}O`C$`Ii$&tzr`v{YKBS2?pR^Js(v*Jz`me?trK~fp%{Z8;)?)BvYwS>KaG-Vg!;)==52-4{=z4A@{ucqO zr$jL4JyU49Nq10&i%vjed#)3d+T8q2FnBT)9piD=py#!GLdYRlBx)gCVJAACE-2@9 z_|1WtF~PR8^M)a_FACc|?wxgSmv$j-rr)dWLl4yybP%YO0g=3!ZBa!thC}mtHPA*# zi(Yc}ks^)!S2T~f{lcyUH02Assd8V~RWSGh_g^XeM*g3w;SU8j - - - - - Welcome to Interface - - - - - -
-
-

Move around

- Move around -

- Move around with WASD & fly
- up or down with E & C.
- Cmnd/Ctrl+G will send you
- home. Hitting Enter will let you
- teleport to a user or location. -

-
-
-

Listen & talk

- Talk -

- Use your best headphones
- and microphone for high
- fidelity audio. -

-
-
-

Connect devices

- Connect devices -

- Have an Oculus Rift, a Razer
- Hydra, or a PrimeSense 3D
- camera? We support them all. -

-
-
-

Run a script

- Run a script -

- Cmnd/Cntrl+J will launch a
- Running Scripts dialog to help
- manage your scripts and search
- for new ones to run. -

-
-
-

Script something

- Write a script -

- Write a script; we're always
- adding new features.
- Cmnd/Cntrl+J will launch a
- Running Scripts dialog to help
- manage your scripts. -

-
-
-

Import models

- Import models -

- Use the edit.js script to
- add FBX models in-world. You
- can use grids and fine tune
- placement-related parameters
- with ease. -

-
-
-
-

Read the docs

-

- We are writing documentation on
- just about everything. Please,
- devour all we've written and make
- suggestions where necessary.
- Documentation is always at
- docs.highfidelity.com -

-
-
-
- - - - - diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1bb4c64884..6d779c81bc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -224,7 +224,6 @@ static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; -static const QString INFO_WELCOME_PATH = "html/interface-welcome.html"; static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; static const QString INFO_HELP_PATH = "html/help.html"; @@ -2381,10 +2380,6 @@ void Application::setSettingConstrainToolbarPosition(bool setting) { DependencyManager::get()->setConstrainToolbarToCenterX(setting); } -void Application::aboutApp() { - InfoView::show(INFO_WELCOME_PATH); -} - void Application::showHelp() { static const QString HAND_CONTROLLER_NAME_VIVE = "vive"; static const QString HAND_CONTROLLER_NAME_OCULUS_TOUCH = "oculus"; diff --git a/interface/src/Application.h b/interface/src/Application.h index 98080783a6..73b2c399e6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -368,7 +368,6 @@ public slots: void calibrateEyeTracker5Points(); #endif - void aboutApp(); static void showHelp(); void cycleCamera(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8e124d27c7..0e22c05787 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -74,9 +74,6 @@ Menu::Menu() { // File > Help addActionToQMenuAndActionHash(fileMenu, MenuOption::Help, 0, qApp, SLOT(showHelp())); - // File > About - addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole); - // File > Quit addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp, SLOT(quit()), QAction::QuitRole); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e0ac340edc..a51419aa73 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -26,7 +26,6 @@ public: }; namespace MenuOption { - const QString AboutApp = "About Interface"; const QString AddRemoveFriends = "Add/Remove Friends..."; const QString AddressBar = "Show Address Bar"; const QString Animations = "Animations..."; From a68146e7d9e3e4d899de607751b7e5c4d9f057f1 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Mar 2017 15:07:02 -0400 Subject: [PATCH 20/33] mv audio output init to output thread --- libraries/audio-client/src/AudioClient.cpp | 45 ++++++++++++++-------- libraries/audio-client/src/AudioClient.h | 1 + 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index fa5d0d24d5..854697d809 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1540,12 +1540,39 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); - int osDefaultBufferSize = _audioOutput->bufferSize(); int deviceChannelCount = _outputFormat.channelCount(); - int deviceFrameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) / _desiredOutputFormat.sampleRate(); - int requestedSize = _sessionOutputBufferSizeFrames * deviceFrameSize * AudioConstants::SAMPLE_SIZE; + int frameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * deviceChannelCount * _outputFormat.sampleRate()) / _desiredOutputFormat.sampleRate(); + int requestedSize = _sessionOutputBufferSizeFrames * frameSize * AudioConstants::SAMPLE_SIZE; _audioOutput->setBufferSize(requestedSize); + // initialize mix buffers on the _audioOutput thread to avoid races + connect(_audioOutput, &QAudioOutput::stateChanged, [&, frameSize, requestedSize](QAudio::State state) { + if (state == QAudio::ActiveState) { + // restrict device callback to _outputPeriod samples + _outputPeriod = (_audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE) * 2; + _outputMixBuffer = new float[_outputPeriod]; + _outputScratchBuffer = new int16_t[_outputPeriod]; + + // size local output mix buffer based on resampled network frame size + _networkPeriod = _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO); + _localOutputMixBuffer = new float[_networkPeriod]; + int localPeriod = _outputPeriod * 2; + _localInjectorsStream.resizeForFrameSize(localPeriod); + + int bufferSize = _audioOutput->bufferSize(); + int bufferSamples = bufferSize / AudioConstants::SAMPLE_SIZE; + int bufferFrames = bufferSamples / (float)frameSize; + qCDebug(audioclient) << "frame (samples):" << frameSize; + qCDebug(audioclient) << "buffer (frames):" << bufferFrames; + qCDebug(audioclient) << "buffer (samples):" << bufferSamples; + qCDebug(audioclient) << "buffer (bytes):" << bufferSize; + qCDebug(audioclient) << "requested (bytes):" << requestedSize; + qCDebug(audioclient) << "period (samples):" << _outputPeriod; + qCDebug(audioclient) << "local buffer (samples):" << localPeriod; + + disconnect(_audioOutput, &QAudioOutput::stateChanged, 0, 0); + } + }); connect(_audioOutput, &QAudioOutput::notify, this, &AudioClient::outputNotify); _audioOutputIODevice.start(); @@ -1555,18 +1582,6 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice _audioOutput->start(&_audioOutputIODevice); lock.unlock(); - int periodSampleSize = _audioOutput->periodSize() / AudioConstants::SAMPLE_SIZE; - // device callback is not restricted to periodSampleSize, so double the mix/scratch buffer sizes - _outputPeriod = periodSampleSize * 2; - _outputMixBuffer = new float[_outputPeriod]; - _outputScratchBuffer = new int16_t[_outputPeriod]; - _localOutputMixBuffer = new float[_outputPeriod]; - _localInjectorsStream.resizeForFrameSize(_outputPeriod * 2); - - qCDebug(audioclient) << "Output Buffer capacity in frames: " << _audioOutput->bufferSize() / AudioConstants::SAMPLE_SIZE / (float)deviceFrameSize << - "requested bytes:" << requestedSize << "actual bytes:" << _audioOutput->bufferSize() << - "os default:" << osDefaultBufferSize << "period size:" << _audioOutput->periodSize(); - // setup a loopback audio output device _loopbackAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 7e9acc0586..820e8ac260 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -339,6 +339,7 @@ private: int16_t _networkScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC]; // for local audio (used by audio injectors thread) + int _networkPeriod { 0 }; float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO]; int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC]; float* _localOutputMixBuffer { NULL }; From b3603ce8b3331b1e3ad3c37270c74c61ca833713 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 17 Mar 2017 16:52:56 -0700 Subject: [PATCH 21/33] Entities.voxelsToMesh, Model.transformMesh, Model.appendMeshes, Model.meshToOBJ appear to work now --- .../src/RenderablePolyVoxEntityItem.cpp | 29 ++- .../src/RenderablePolyVoxEntityItem.h | 3 +- .../entities/src/EntityScriptingInterface.cpp | 23 ++- .../entities/src/EntityScriptingInterface.h | 8 + libraries/entities/src/PolyVoxEntityItem.cpp | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/model/src/model/Geometry.cpp | 84 ++++++++- libraries/model/src/model/Geometry.h | 10 +- .../src/ModelScriptingInterface.cpp | 169 ++++++++++-------- 9 files changed, 238 insertions(+), 92 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index dd62122633..6f9310a36e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -664,11 +664,8 @@ void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) { } } -void RenderablePolyVoxEntityItem::render(RenderArgs* args) { - PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); - assert(getType() == EntityTypes::PolyVox); - Q_ASSERT(args->_batch); +bool RenderablePolyVoxEntityItem::updateDependents() { bool voxelDataDirty; bool volDataDirty; withWriteLock([&] { @@ -686,6 +683,17 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { recomputeMesh(); } + return !volDataDirty; +} + + +void RenderablePolyVoxEntityItem::render(RenderArgs* args) { + PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); + assert(getType() == EntityTypes::PolyVox); + Q_ASSERT(args->_batch); + + updateDependents(); + model::MeshPointer mesh; glm::vec3 voxelVolumeSize; withReadLock([&] { @@ -1571,13 +1579,22 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) { scene->enqueuePendingChanges(pendingChanges); } -bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { +bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { + if (!updateDependents()) { + return false; + } + bool success = false; MeshProxy* meshProxy = nullptr; + glm::mat4 transform = voxelToLocalMatrix(); withReadLock([&] { if (_meshInitialized) { success = true; - meshProxy = new MeshProxy(_mesh); + // the mesh will be in voxel-space. transform it into object-space + meshProxy = new MeshProxy( + _mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, + [=](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); }, + [](uint32_t index){ return index; })); } }); result = meshToScriptValue(engine, meshProxy); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 7fe45f8d99..5eaf93e3ae 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -133,7 +133,7 @@ public: QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); - bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const override; + bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) override; void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } @@ -192,6 +192,7 @@ private: void cacheNeighbors(); void copyUpperEdgesFromNeighbors(); void bonkNeighbors(); + bool updateDependents(); }; bool inUserBounds(const PolyVox::SimpleVolume* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7eae5b2dc4..37e9e940b1 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -8,6 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include +#include + #include "EntityScriptingInterface.h" #include "EntityItemID.h" @@ -926,13 +930,16 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) { PROFILE_RANGE(script_entities, __FUNCTION__); - polyVoxWorker(entityID, [callback](PolyVoxEntityItem& polyVoxEntity) mutable { - QScriptValue mesh; - polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); - QScriptValueList args { mesh }; - callback.call(QScriptValue(), args); + bool success; + QScriptValue mesh; + + polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable { + success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); return true; }); + + QScriptValueList args { mesh, success }; + callback.call(QScriptValue(), args); } bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector& points) { @@ -1557,7 +1564,11 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { - result = entity->getEntityToWorldMatrix(); + glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - + entity->getRegistrationPoint()); + result = translation * rotation * registration; } }); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index be34317cd5..fa727aaa7a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -294,6 +294,14 @@ public slots: Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius); + + /**jsdoc + * Returns object to world transform, excluding scale + * + * @function Entities.getEntityTransform + * @param {EntityID} entityID The ID of the entity whose transform is to be returned + * @return {Mat4} Entity's object to world transform, excluding scale + */ Q_INVOKABLE glm::mat4 getEntityTransform(const QUuid& entityID); signals: diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a827a9903d..90344d6c4b 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -243,6 +243,6 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const { return voxelDataCopy; } -bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const { +bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) { return false; } diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index ae722b2add..943d273452 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -133,7 +133,7 @@ class PolyVoxEntityItem : public EntityItem { void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } virtual void recomputeMesh() {}; - virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) const; + virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result); protected: glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 2bb6cfa436..4e5134a7d7 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -117,7 +117,7 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { auto partItEnd = _partBuffer.cbegin() + partEnd; for (;part != partItEnd; part++) { - + Box partBound; auto index = _indexBuffer.cbegin() + (*part)._startIndex; auto endIndex = index + (*part)._numIndices; @@ -134,6 +134,87 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { return totalBound; } + +model::MeshPointer Mesh::map(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc) { + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + + gpu::Resource::Size vertexSize = getNumVertices() * sizeof(glm::vec3); + unsigned char* resultVertexData = new unsigned char[vertexSize]; + unsigned char* vertexDataCursor = resultVertexData; + + gpu::Resource::Size normalSize = getNumAttributes() * sizeof(glm::vec3); + unsigned char* resultNormalData = new unsigned char[normalSize]; + unsigned char* normalDataCursor = resultNormalData; + + gpu::Resource::Size indexSize = getNumIndices() * sizeof(uint32_t); + unsigned char* resultIndexData = new unsigned char[indexSize]; + unsigned char* indexDataCursor = resultIndexData; + + // vertex data + const gpu::BufferView& vertexBufferView = getVertexBuffer(); + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + glm::vec3 pos = vertexFunc(vertexBufferView.get(i)); + memcpy(vertexDataCursor, &pos, sizeof(pos)); + vertexDataCursor += sizeof(pos); + } + + // normal data + const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + glm::vec3 normal = normalFunc(normalsBufferView.get(i)); + memcpy(normalDataCursor, &normal, sizeof(normal)); + normalDataCursor += sizeof(normal); + } + // TODO -- other attributes + + // face data + const gpu::BufferView& indexBufferView = getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); + for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + uint32_t index = indexFunc(indexBufferView.get(i)); + memcpy(indexDataCursor, &index, sizeof(index)); + indexDataCursor += sizeof(index); + } + + model::MeshPointer result(new model::Mesh()); + + gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); + gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); + gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); + result->setVertexBuffer(resultVertexBufferView); + + gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); + gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); + gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); + result->addAttribute(attributeTypeNormal, resultNormalsBufferView); + + gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); + gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); + gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); + gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); + result->setIndexBuffer(resultIndexesBufferView); + + + // TODO -- shouldn't assume just one part + + std::vector parts; + parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex + (model::Index)result->getNumIndices(), // numIndices + (model::Index)0, // baseVertex + model::Mesh::TRIANGLES)); // topology + result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), + (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + return result; +} + + Geometry::Geometry() { } @@ -148,4 +229,3 @@ Geometry::~Geometry() { void Geometry::setMesh(const MeshPointer& mesh) { _mesh = mesh; } - diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index 4256f0be03..9a20861ea7 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -25,6 +25,10 @@ typedef AABox Box; typedef std::vector< Box > Boxes; typedef glm::vec3 Vec3; +class Mesh; +using MeshPointer = std::shared_ptr< Mesh >; + + class Mesh { public: const static Index PRIMITIVE_RESTART_INDEX = -1; @@ -114,6 +118,11 @@ public: static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast(topo); } + // create a copy of this mesh after passing its vertices, normals, and indexes though the provided functions + MeshPointer map(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc); + protected: gpu::Stream::FormatPointer _vertexFormat; @@ -130,7 +139,6 @@ protected: void evalVertexStream(); }; -using MeshPointer = std::shared_ptr< Mesh >; class Geometry { diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 86a651b6b2..71b82a2d60 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -151,84 +151,105 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { } +// QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { +// int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + +// if (!meshProxy) { +// return QScriptValue(false); +// } + +// MeshPointer mesh = meshProxy->getMeshPointer(); + +// gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); +// unsigned char* resultVertexData = new unsigned char[vertexSize]; +// unsigned char* vertexDataCursor = resultVertexData; + +// gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); +// unsigned char* resultNormalData = new unsigned char[normalSize]; +// unsigned char* normalDataCursor = resultNormalData; + +// gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); +// unsigned char* resultIndexData = new unsigned char[indexSize]; +// unsigned char* indexDataCursor = resultIndexData; + +// // vertex data +// const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); +// gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); +// for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { +// glm::vec3 pos = vertexBufferView.get(i); +// pos = glm::vec3(transform * glm::vec4(pos, 1.0f)); +// memcpy(vertexDataCursor, &pos, sizeof(pos)); +// vertexDataCursor += sizeof(pos); +// } + +// // normal data +// const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); +// gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); +// for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { +// glm::vec3 normal = normalsBufferView.get(i); +// normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); +// memcpy(normalDataCursor, &normal, sizeof(normal)); +// normalDataCursor += sizeof(normal); +// } +// // TODO -- other attributes + +// // face data +// const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); +// gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); +// for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { +// uint32_t index = indexBufferView.get(i); +// memcpy(indexDataCursor, &index, sizeof(index)); +// indexDataCursor += sizeof(index); +// } + +// model::MeshPointer result(new model::Mesh()); + +// gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); +// gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); +// gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); +// gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); +// result->setVertexBuffer(resultVertexBufferView); + +// gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); +// gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); +// gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); +// gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); +// result->addAttribute(attributeTypeNormal, resultNormalsBufferView); + +// gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); +// gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); +// gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); +// gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); +// result->setIndexBuffer(resultIndexesBufferView); + + +// std::vector parts; +// parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex +// (model::Index)result->getNumIndices(), // numIndices +// (model::Index)0, // baseVertex +// model::Mesh::TRIANGLES)); // topology +// result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), +// (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); + + + +// MeshProxy* resultProxy = new MeshProxy(result); +// return meshToScriptValue(_modelScriptEngine, resultProxy); +// } + + QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { - int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - + if (!meshProxy) { + return QScriptValue(false); + } MeshPointer mesh = meshProxy->getMeshPointer(); - - gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); - unsigned char* resultVertexData = new unsigned char[vertexSize]; - unsigned char* vertexDataCursor = resultVertexData; - - gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); - unsigned char* resultNormalData = new unsigned char[normalSize]; - unsigned char* normalDataCursor = resultNormalData; - - gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); - unsigned char* resultIndexData = new unsigned char[indexSize]; - unsigned char* indexDataCursor = resultIndexData; - - // vertex data - const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); - gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); - for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { - glm::vec3 pos = vertexBufferView.get(i); - pos = glm::vec3(transform * glm::vec4(pos, 0.0f)); - memcpy(vertexDataCursor, &pos, sizeof(pos)); - vertexDataCursor += sizeof(pos); + if (!mesh) { + return QScriptValue(false); } - // normal data - const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); - for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { - glm::vec3 normal = normalsBufferView.get(i); - normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); - memcpy(normalDataCursor, &normal, sizeof(normal)); - normalDataCursor += sizeof(normal); - } - // TODO -- other attributes - - // face data - const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); - for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { - uint32_t index = indexBufferView.get(i); - memcpy(indexDataCursor, &index, sizeof(index)); - indexDataCursor += sizeof(index); - } - - model::MeshPointer result(new model::Mesh()); - - gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); - gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); - gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); - gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); - result->setVertexBuffer(resultVertexBufferView); - - gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); - gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); - gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); - gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); - result->addAttribute(attributeTypeNormal, resultNormalsBufferView); - - gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); - gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); - gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); - gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); - result->setIndexBuffer(resultIndexesBufferView); - - - std::vector parts; - parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex - (model::Index)result->getNumIndices(), // numIndices - (model::Index)0, // baseVertex - model::Mesh::TRIANGLES)); // topology - result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), - (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); - - - + model::MeshPointer result = mesh->map([&](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); }, + [&](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); }, + [&](uint32_t index){ return index; }); MeshProxy* resultProxy = new MeshProxy(result); return meshToScriptValue(_modelScriptEngine, resultProxy); } From a9b1a3866587ecb01a33577faa1a1d9ad92e0485 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Sat, 18 Mar 2017 00:53:13 +0000 Subject: [PATCH 22/33] remove Mini Mirror from View menu Avatar inputs only contains the audio meter now. --- interface/resources/qml/AvatarInputs.qml | 57 +------ interface/src/Application.cpp | 153 +++++------------- interface/src/Application.h | 4 - interface/src/Menu.cpp | 3 - interface/src/Menu.h | 1 - interface/src/ui/ApplicationOverlay.cpp | 43 ----- interface/src/ui/ApplicationOverlay.h | 3 - interface/src/ui/AvatarInputs.cpp | 20 --- interface/src/ui/AvatarInputs.h | 6 - .../render-utils/src/FramebufferCache.cpp | 12 -- libraries/render-utils/src/FramebufferCache.h | 5 - 11 files changed, 41 insertions(+), 266 deletions(-) diff --git a/interface/resources/qml/AvatarInputs.qml b/interface/resources/qml/AvatarInputs.qml index 384504aaa0..28f3c0c7b9 100644 --- a/interface/resources/qml/AvatarInputs.qml +++ b/interface/resources/qml/AvatarInputs.qml @@ -15,12 +15,11 @@ import Qt.labs.settings 1.0 Hifi.AvatarInputs { id: root objectName: "AvatarInputs" - width: mirrorWidth - height: controls.height + mirror.height + width: rootWidth + height: controls.height x: 10; y: 5 - readonly property int mirrorHeight: 215 - readonly property int mirrorWidth: 265 + readonly property int rootWidth: 265 readonly property int iconSize: 24 readonly property int iconPadding: 5 @@ -39,61 +38,15 @@ Hifi.AvatarInputs { anchors.fill: parent } - Item { - id: mirror - width: root.mirrorWidth - height: root.mirrorVisible ? root.mirrorHeight : 0 - visible: root.mirrorVisible - anchors.left: parent.left - clip: true - - Image { - id: closeMirror - visible: hover.containsMouse - width: root.iconSize - height: root.iconSize - anchors.top: parent.top - anchors.topMargin: root.iconPadding - anchors.left: parent.left - anchors.leftMargin: root.iconPadding - source: "../images/close.svg" - MouseArea { - anchors.fill: parent - onClicked: { - root.closeMirror(); - } - } - } - - Image { - id: zoomIn - visible: hover.containsMouse - width: root.iconSize - height: root.iconSize - anchors.bottom: parent.bottom - anchors.bottomMargin: root.iconPadding - anchors.left: parent.left - anchors.leftMargin: root.iconPadding - source: root.mirrorZoomed ? "../images/minus.svg" : "../images/plus.svg" - MouseArea { - anchors.fill: parent - onClicked: { - root.toggleZoom(); - } - } - } - } - Item { id: controls - width: root.mirrorWidth + width: root.rootWidth height: 44 visible: root.showAudioTools - anchors.top: mirror.bottom Rectangle { anchors.fill: parent - color: root.mirrorVisible ? (root.audioClipping ? "red" : "#696969") : "#00000000" + color: "#00000000" Item { id: audioMeter diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8cd5a9564a..d6516db8f0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -213,14 +213,7 @@ static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; -static const int MIRROR_VIEW_TOP_PADDING = 5; -static const int MIRROR_VIEW_LEFT_PADDING = 10; -static const int MIRROR_VIEW_WIDTH = 265; -static const int MIRROR_VIEW_HEIGHT = 215; static const float MIRROR_FULLSCREEN_DISTANCE = 0.389f; -static const float MIRROR_REARVIEW_DISTANCE = 0.722f; -static const float MIRROR_REARVIEW_BODY_DISTANCE = 2.56f; -static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; @@ -565,7 +558,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _entityClipboardRenderer(false, this, this), _entityClipboard(new EntityTree()), _lastQueriedTime(usecTimestampNow()), - _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), @@ -2119,21 +2111,6 @@ void Application::paintGL() { batch.resetStages(); }); - auto inputs = AvatarInputs::getInstance(); - if (inputs->mirrorVisible()) { - PerformanceTimer perfTimer("Mirror"); - - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - renderArgs._blitFramebuffer = DependencyManager::get()->getSelfieFramebuffer(); - - _mirrorViewRect.moveTo(inputs->x(), inputs->y()); - - renderRearViewMirror(&renderArgs, _mirrorViewRect, inputs->mirrorZoomed()); - - renderArgs._blitFramebuffer.reset(); - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - } - { PerformanceTimer perfTimer("renderOverlay"); // NOTE: There is no batch associated with this renderArgs @@ -2887,49 +2864,45 @@ void Application::keyPressEvent(QKeyEvent* event) { #endif case Qt::Key_H: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::MiniMirror); - } else { - // whenever switching to/from full screen mirror from the keyboard, remember - // the state you were in before full screen mirror, and return to that. - auto previousMode = _myCamera.getMode(); - if (previousMode != CAMERA_MODE_MIRROR) { - switch (previousMode) { - case CAMERA_MODE_FIRST_PERSON: - _returnFromFullScreenMirrorTo = MenuOption::FirstPerson; - break; - case CAMERA_MODE_THIRD_PERSON: - _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; - break; - - // FIXME - it's not clear that these modes make sense to return to... - case CAMERA_MODE_INDEPENDENT: - _returnFromFullScreenMirrorTo = MenuOption::IndependentMode; - break; - case CAMERA_MODE_ENTITY: - _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; - break; - - default: - _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; - break; - } - } - - bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); - Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); - if (isMirrorChecked) { - - // if we got here without coming in from a non-Full Screen mirror case, then our - // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old - // behavior of returning to ThirdPerson - if (_returnFromFullScreenMirrorTo.isEmpty()) { + // whenever switching to/from full screen mirror from the keyboard, remember + // the state you were in before full screen mirror, and return to that. + auto previousMode = _myCamera.getMode(); + if (previousMode != CAMERA_MODE_MIRROR) { + switch (previousMode) { + case CAMERA_MODE_FIRST_PERSON: + _returnFromFullScreenMirrorTo = MenuOption::FirstPerson; + break; + case CAMERA_MODE_THIRD_PERSON: _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; - } - Menu::getInstance()->setIsOptionChecked(_returnFromFullScreenMirrorTo, true); + break; + + // FIXME - it's not clear that these modes make sense to return to... + case CAMERA_MODE_INDEPENDENT: + _returnFromFullScreenMirrorTo = MenuOption::IndependentMode; + break; + case CAMERA_MODE_ENTITY: + _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; + break; + + default: + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + break; } - cameraMenuChanged(); } + + bool isMirrorChecked = Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); + Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !isMirrorChecked); + if (isMirrorChecked) { + + // if we got here without coming in from a non-Full Screen mirror case, then our + // _returnFromFullScreenMirrorTo is unknown. In that case we'll go to the old + // behavior of returning to ThirdPerson + if (_returnFromFullScreenMirrorTo.isEmpty()) { + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + } + Menu::getInstance()->setIsOptionChecked(_returnFromFullScreenMirrorTo, true); + } + cameraMenuChanged(); break; case Qt::Key_P: { if (!(isShifted || isMeta || isOption)) { @@ -3845,8 +3818,6 @@ void Application::init() { DependencyManager::get()->init(); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _mirrorCamera.setMode(CAMERA_MODE_MIRROR); - _timerStart.start(); _lastTimeUpdated.start(); @@ -5122,58 +5093,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se activeRenderingThread = nullptr; } -void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed) { - auto originalViewport = renderArgs->_viewport; - // Grab current viewport to reset it at the end - - float aspect = (float)region.width() / region.height(); - float fov = MIRROR_FIELD_OF_VIEW; - - auto myAvatar = getMyAvatar(); - - // bool eyeRelativeCamera = false; - if (!isZoomed) { - _mirrorCamera.setPosition(myAvatar->getChestPosition() + - myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * myAvatar->getScale()); - - } else { // HEAD zoom level - // FIXME note that the positioning of the camera relative to the avatar can suffer limited - // precision as the user's position moves further away from the origin. Thus at - // /1e7,1e7,1e7 (well outside the buildable volume) the mirror camera veers and sways - // wildly as you rotate your avatar because the floating point values are becoming - // larger, squeezing out the available digits of precision you have available at the - // human scale for camera positioning. - - // Previously there was a hack to correct this using the mechanism of repositioning - // the avatar at the origin of the world for the purposes of rendering the mirror, - // but it resulted in failing to render the avatar's head model in the mirror view - // when in first person mode. Presumably this was because of some missed culling logic - // that was not accounted for in the hack. - - // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further - // investigated in order to adapt the technique while fixing the head rendering issue, - // but the complexity of the hack suggests that a better approach - _mirrorCamera.setPosition(myAvatar->getDefaultEyePosition() + - myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * myAvatar->getScale()); - } - _mirrorCamera.setProjection(glm::perspective(glm::radians(fov), aspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); - _mirrorCamera.setOrientation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); - - - // set the bounds of rear mirror view - // the region is in device independent coordinates; must convert to device - float ratio = (float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale(); - int width = region.width() * ratio; - int height = region.height() * ratio; - gpu::Vec4i viewport = gpu::Vec4i(0, 0, width, height); - renderArgs->_viewport = viewport; - - // render rear mirror view - displaySide(renderArgs, _mirrorCamera, true); - - renderArgs->_viewport = originalViewport; -} - void Application::resetSensors(bool andReload) { DependencyManager::get()->reset(); DependencyManager::get()->reset(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 98080783a6..da815db4cd 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -276,8 +276,6 @@ public: virtual void pushPostUpdateLambda(void* key, std::function func) override; - const QRect& getMirrorViewRect() const { return _mirrorViewRect; } - void updateMyAvatarLookAtPosition(); float getAvatarSimrate() const { return _avatarSimCounter.rate(); } @@ -557,8 +555,6 @@ private: int _avatarSimsPerSecondReport {0}; quint64 _lastAvatarSimsPerSecondUpdate {0}; Camera _myCamera; // My view onto the world - Camera _mirrorCamera; // Camera for mirror view - QRect _mirrorViewRect; Setting::Handle _previousScriptLocation; Setting::Handle _fieldOfView; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8e124d27c7..893b23839d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -249,9 +249,6 @@ Menu::Menu() { viewMenu->addSeparator(); - // View > Mini Mirror - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MiniMirror, 0, false); - // View > Center Player In View addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, 0, true, qApp, SLOT(rotationModeChanged()), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e0ac340edc..4a990254ad 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -123,7 +123,6 @@ namespace MenuOption { const QString LogExtraTimings = "Log Extra Timing Details"; const QString LowVelocityFilter = "Low Velocity Filter"; const QString MeshVisible = "Draw Mesh"; - const QString MiniMirror = "Mini Mirror"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString MuteFaceTracking = "Mute Face Tracking"; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 364dff52a3..b9d7fadc97 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -42,7 +41,6 @@ ApplicationOverlay::ApplicationOverlay() _domainStatusBorder = geometryCache->allocateID(); _magnifierBorder = geometryCache->allocateID(); _qmlGeometryId = geometryCache->allocateID(); - _rearViewGeometryId = geometryCache->allocateID(); } ApplicationOverlay::~ApplicationOverlay() { @@ -51,7 +49,6 @@ ApplicationOverlay::~ApplicationOverlay() { geometryCache->releaseID(_domainStatusBorder); geometryCache->releaseID(_magnifierBorder); geometryCache->releaseID(_qmlGeometryId); - geometryCache->releaseID(_rearViewGeometryId); } } @@ -86,7 +83,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { // Now render the overlay components together into a single texture renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line renderAudioScope(renderArgs); // audio scope in the very back - NOTE: this is the debug audio scope, not the VU meter - renderRearView(renderArgs); // renders the mirror view selfie renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts renderStatsAndLogs(renderArgs); // currently renders nothing @@ -163,45 +159,6 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { qApp->getOverlays().renderHUD(renderArgs); } -void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { -} - -void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) { - if (!qApp->isHMDMode() && Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror) && - !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { - gpu::Batch& batch = *renderArgs->_batch; - - auto geometryCache = DependencyManager::get(); - - auto framebuffer = DependencyManager::get(); - auto selfieTexture = framebuffer->getSelfieFramebuffer()->getRenderBuffer(0); - - int width = renderArgs->_viewport.z; - int height = renderArgs->_viewport.w; - mat4 legacyProjection = glm::ortho(0, width, height, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); - batch.setProjectionTransform(legacyProjection); - batch.setModelTransform(Transform()); - batch.resetViewTransform(); - - float screenRatio = ((float)qApp->getDevicePixelRatio()); - float renderRatio = ((float)qApp->getRenderResolutionScale()); - - auto viewport = qApp->getMirrorViewRect(); - glm::vec2 bottomLeft(viewport.left(), viewport.top() + viewport.height()); - glm::vec2 topRight(viewport.left() + viewport.width(), viewport.top()); - bottomLeft *= screenRatio; - topRight *= screenRatio; - glm::vec2 texCoordMinCorner(0.0f, 0.0f); - glm::vec2 texCoordMaxCorner(viewport.width() * renderRatio / float(selfieTexture->getWidth()), viewport.height() * renderRatio / float(selfieTexture->getHeight())); - - batch.setResourceTexture(0, selfieTexture); - float alpha = DependencyManager::get()->getDesktop()->property("unpinnedAlpha").toFloat(); - geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, alpha), _rearViewGeometryId); - - batch.setResourceTexture(0, renderArgs->_whiteTexture); - } -} - void ApplicationOverlay::renderStatsAndLogs(RenderArgs* renderArgs) { // Display stats and log text onscreen diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 7ace5ee885..af4d8779d4 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -31,8 +31,6 @@ public: private: void renderStatsAndLogs(RenderArgs* renderArgs); void renderDomainConnectionStatusBorder(RenderArgs* renderArgs); - void renderRearViewToFbo(RenderArgs* renderArgs); - void renderRearView(RenderArgs* renderArgs); void renderQmlUi(RenderArgs* renderArgs); void renderAudioScope(RenderArgs* renderArgs); void renderOverlays(RenderArgs* renderArgs); @@ -51,7 +49,6 @@ private: gpu::TexturePointer _overlayColorTexture; gpu::FramebufferPointer _overlayFramebuffer; int _qmlGeometryId { 0 }; - int _rearViewGeometryId { 0 }; }; #endif // hifi_ApplicationOverlay_h diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index b09289c78a..944be4bf9e 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -20,10 +20,6 @@ HIFI_QML_DEF(AvatarInputs) static AvatarInputs* INSTANCE{ nullptr }; -static const char SETTINGS_GROUP_NAME[] = "Rear View Tools"; -static const char ZOOM_LEVEL_SETTINGS[] = "ZoomLevel"; - -static Setting::Handle rearViewZoomLevel(QStringList() << SETTINGS_GROUP_NAME << ZOOM_LEVEL_SETTINGS, 0); AvatarInputs* AvatarInputs::getInstance() { if (!INSTANCE) { @@ -36,8 +32,6 @@ AvatarInputs* AvatarInputs::getInstance() { AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { INSTANCE = this; - int zoomSetting = rearViewZoomLevel.get(); - _mirrorZoomed = zoomSetting == 0; } #define AI_UPDATE(name, src) \ @@ -62,8 +56,6 @@ void AvatarInputs::update() { if (!Menu::getInstance()) { return; } - AI_UPDATE(mirrorVisible, Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror) && !qApp->isHMDMode() - && !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); AI_UPDATE(cameraEnabled, !Menu::getInstance()->isOptionChecked(MenuOption::NoFaceTracking)); AI_UPDATE(cameraMuted, Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking)); AI_UPDATE(isHMD, qApp->isHMDMode()); @@ -122,15 +114,3 @@ void AvatarInputs::toggleAudioMute() { void AvatarInputs::resetSensors() { qApp->resetSensors(); } - -void AvatarInputs::toggleZoom() { - _mirrorZoomed = !_mirrorZoomed; - rearViewZoomLevel.set(_mirrorZoomed ? 0 : 1); - emit mirrorZoomedChanged(); -} - -void AvatarInputs::closeMirror() { - if (Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) { - Menu::getInstance()->triggerOption(MenuOption::MiniMirror); - } -} diff --git a/interface/src/ui/AvatarInputs.h b/interface/src/ui/AvatarInputs.h index 85570ecd3c..5535469445 100644 --- a/interface/src/ui/AvatarInputs.h +++ b/interface/src/ui/AvatarInputs.h @@ -28,8 +28,6 @@ class AvatarInputs : public QQuickItem { AI_PROPERTY(bool, audioMuted, false) AI_PROPERTY(bool, audioClipping, false) AI_PROPERTY(float, audioLevel, 0) - AI_PROPERTY(bool, mirrorVisible, false) - AI_PROPERTY(bool, mirrorZoomed, true) AI_PROPERTY(bool, isHMD, false) AI_PROPERTY(bool, showAudioTools, true) @@ -44,8 +42,6 @@ signals: void audioMutedChanged(); void audioClippingChanged(); void audioLevelChanged(); - void mirrorVisibleChanged(); - void mirrorZoomedChanged(); void isHMDChanged(); void showAudioToolsChanged(); @@ -53,8 +49,6 @@ protected: Q_INVOKABLE void resetSensors(); Q_INVOKABLE void toggleCameraMute(); Q_INVOKABLE void toggleAudioMute(); - Q_INVOKABLE void toggleZoom(); - Q_INVOKABLE void closeMirror(); private: float _trailingAudioLoudness{ 0 }; diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 27429595b4..31b345fa9f 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -21,7 +21,6 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { //If the size changed, we need to delete our FBOs if (_frameBufferSize != frameBufferSize) { _frameBufferSize = frameBufferSize; - _selfieFramebuffer.reset(); { std::unique_lock lock(_mutex); _cachedFramebuffers.clear(); @@ -36,10 +35,6 @@ void FramebufferCache::createPrimaryFramebuffer() { auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("selfie")); - auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler)); - _selfieFramebuffer->setRenderBuffer(0, tex); - auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); } @@ -60,10 +55,3 @@ void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebu _cachedFramebuffers.push_back(framebuffer); } } - -gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() { - if (!_selfieFramebuffer) { - createPrimaryFramebuffer(); - } - return _selfieFramebuffer; -} diff --git a/libraries/render-utils/src/FramebufferCache.h b/libraries/render-utils/src/FramebufferCache.h index f74d224a61..8065357615 100644 --- a/libraries/render-utils/src/FramebufferCache.h +++ b/libraries/render-utils/src/FramebufferCache.h @@ -27,9 +27,6 @@ public: void setFrameBufferSize(QSize frameBufferSize); const QSize& getFrameBufferSize() const { return _frameBufferSize; } - /// Returns the framebuffer object used to render selfie maps; - gpu::FramebufferPointer getSelfieFramebuffer(); - /// Returns a free framebuffer with a single color attachment for temp or intra-frame operations gpu::FramebufferPointer getFramebuffer(); @@ -42,8 +39,6 @@ private: gpu::FramebufferPointer _shadowFramebuffer; - gpu::FramebufferPointer _selfieFramebuffer; - QSize _frameBufferSize{ 100, 100 }; std::mutex _mutex; From 8e086a8fc8b20c78f185b0065e8446ea8dfffcd7 Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Sat, 18 Mar 2017 03:51:55 +0000 Subject: [PATCH 23/33] fix build error --- interface/src/Application.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d6516db8f0..4a8ffe702f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2863,30 +2863,30 @@ void Application::keyPressEvent(QKeyEvent* event) { break; #endif - case Qt::Key_H: + case Qt::Key_H: { // whenever switching to/from full screen mirror from the keyboard, remember // the state you were in before full screen mirror, and return to that. auto previousMode = _myCamera.getMode(); if (previousMode != CAMERA_MODE_MIRROR) { switch (previousMode) { - case CAMERA_MODE_FIRST_PERSON: - _returnFromFullScreenMirrorTo = MenuOption::FirstPerson; - break; - case CAMERA_MODE_THIRD_PERSON: - _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; - break; + case CAMERA_MODE_FIRST_PERSON: + _returnFromFullScreenMirrorTo = MenuOption::FirstPerson; + break; + case CAMERA_MODE_THIRD_PERSON: + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + break; // FIXME - it's not clear that these modes make sense to return to... - case CAMERA_MODE_INDEPENDENT: - _returnFromFullScreenMirrorTo = MenuOption::IndependentMode; - break; - case CAMERA_MODE_ENTITY: - _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; - break; + case CAMERA_MODE_INDEPENDENT: + _returnFromFullScreenMirrorTo = MenuOption::IndependentMode; + break; + case CAMERA_MODE_ENTITY: + _returnFromFullScreenMirrorTo = MenuOption::CameraEntityMode; + break; - default: - _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; - break; + default: + _returnFromFullScreenMirrorTo = MenuOption::ThirdPerson; + break; } } @@ -2904,6 +2904,8 @@ void Application::keyPressEvent(QKeyEvent* event) { } cameraMenuChanged(); break; + } + case Qt::Key_P: { if (!(isShifted || isMeta || isOption)) { bool isFirstPersonChecked = Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson); From 8b845658e2418cf147bb43f88a338bc696ff467a Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Sat, 18 Mar 2017 05:00:05 +0000 Subject: [PATCH 24/33] remove redundant declarations --- libraries/render-utils/src/FramebufferCache.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/render-utils/src/FramebufferCache.cpp b/libraries/render-utils/src/FramebufferCache.cpp index 31b345fa9f..72b3c2ceb4 100644 --- a/libraries/render-utils/src/FramebufferCache.cpp +++ b/libraries/render-utils/src/FramebufferCache.cpp @@ -29,10 +29,6 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) { } void FramebufferCache::createPrimaryFramebuffer() { - auto colorFormat = gpu::Element::COLOR_SRGBA_32; - auto width = _frameBufferSize.width(); - auto height = _frameBufferSize.height(); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); From 488ed081ddcd9b14e7e5b75470df3aaeba65e4cc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 18 Mar 2017 10:18:04 -0700 Subject: [PATCH 25/33] Mesh::forEach and Mesh::map --- libraries/model/src/model/Geometry.cpp | 47 ++++-- libraries/model/src/model/Geometry.h | 4 + .../src/ModelScriptingInterface.cpp | 135 +++--------------- 3 files changed, 59 insertions(+), 127 deletions(-) diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index 4e5134a7d7..d511ae6cb9 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -140,19 +140,11 @@ model::MeshPointer Mesh::map(std::function vertexFunc, std::function indexFunc) { int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + // vertex data gpu::Resource::Size vertexSize = getNumVertices() * sizeof(glm::vec3); unsigned char* resultVertexData = new unsigned char[vertexSize]; unsigned char* vertexDataCursor = resultVertexData; - gpu::Resource::Size normalSize = getNumAttributes() * sizeof(glm::vec3); - unsigned char* resultNormalData = new unsigned char[normalSize]; - unsigned char* normalDataCursor = resultNormalData; - - gpu::Resource::Size indexSize = getNumIndices() * sizeof(uint32_t); - unsigned char* resultIndexData = new unsigned char[indexSize]; - unsigned char* indexDataCursor = resultIndexData; - - // vertex data const gpu::BufferView& vertexBufferView = getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { @@ -162,6 +154,10 @@ model::MeshPointer Mesh::map(std::function vertexFunc, } // normal data + gpu::Resource::Size normalSize = getNumAttributes() * sizeof(glm::vec3); + unsigned char* resultNormalData = new unsigned char[normalSize]; + unsigned char* normalDataCursor = resultNormalData; + const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { @@ -172,6 +168,10 @@ model::MeshPointer Mesh::map(std::function vertexFunc, // TODO -- other attributes // face data + gpu::Resource::Size indexSize = getNumIndices() * sizeof(uint32_t); + unsigned char* resultIndexData = new unsigned char[indexSize]; + unsigned char* indexDataCursor = resultIndexData; + const gpu::BufferView& indexBufferView = getIndexBuffer(); gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { @@ -215,6 +215,35 @@ model::MeshPointer Mesh::map(std::function vertexFunc, } +void Mesh::forEach(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc) { + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + + // vertex data + const gpu::BufferView& vertexBufferView = getVertexBuffer(); + gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { + vertexFunc(vertexBufferView.get(i)); + } + + // normal data + const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); + for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { + normalFunc(normalsBufferView.get(i)); + } + // TODO -- other attributes + + // face data + const gpu::BufferView& indexBufferView = getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); + for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { + indexFunc(indexBufferView.get(i)); + } +} + + Geometry::Geometry() { } diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index 9a20861ea7..7ba3e83407 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -123,6 +123,10 @@ public: std::function normalFunc, std::function indexFunc); + void forEach(std::function vertexFunc, + std::function normalFunc, + std::function indexFunc); + protected: gpu::Stream::FormatPointer _vertexFormat; diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index 71b82a2d60..cfcb6da0dc 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -53,10 +53,8 @@ QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) { return writeOBJToString(meshes); } - QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { - int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - + // figure out the size of the resulting mesh size_t totalVertexCount { 0 }; size_t totalAttributeCount { 0 }; size_t totalIndexCount { 0 }; @@ -67,6 +65,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { totalIndexCount += mesh->getNumIndices(); } + // alloc the resulting mesh gpu::Resource::Size combinedVertexSize = totalVertexCount * sizeof(glm::vec3); unsigned char* combinedVertexData = new unsigned char[combinedVertexSize]; unsigned char* combinedVertexDataCursor = combinedVertexData; @@ -83,36 +82,22 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { foreach (const MeshProxy* meshProxy, in) { MeshPointer mesh = meshProxy->getMeshPointer(); + mesh->forEach( + [&](glm::vec3 position){ + memcpy(combinedVertexDataCursor, &position, sizeof(position)); + combinedVertexDataCursor += sizeof(position); + }, + [&](glm::vec3 normal){ + memcpy(combinedNormalDataCursor, &normal, sizeof(normal)); + combinedNormalDataCursor += sizeof(normal); + }, + [&](uint32_t index){ + index += indexStartOffset; + memcpy(combinedIndexDataCursor, &index, sizeof(index)); + combinedIndexDataCursor += sizeof(index); + }); - // vertex data - const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); - for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { - glm::vec3 pos = vertexBufferView.get(i); - memcpy(combinedVertexDataCursor, &pos, sizeof(pos)); - combinedVertexDataCursor += sizeof(pos); - } - - // normal data - const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); - for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { - glm::vec3 normal = normalsBufferView.get(i); - memcpy(combinedNormalDataCursor, &normal, sizeof(normal)); - combinedNormalDataCursor += sizeof(normal); - } - // TODO -- other attributes - - // face data - const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); - for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { - uint32_t index = indexBufferView.get(i); - index += indexStartOffset; - memcpy(combinedIndexDataCursor, &index, sizeof(index)); - combinedIndexDataCursor += sizeof(index); - } - indexStartOffset += numVertices; } @@ -124,6 +109,7 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { gpu::BufferView combinedVertexBufferView(combinedVertexBufferPointer, vertexElement); result->setVertexBuffer(combinedVertexBufferView); + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); gpu::Buffer* combinedNormalsBuffer = new gpu::Buffer(combinedNormalSize, combinedNormalData); gpu::BufferPointer combinedNormalsBufferPointer(combinedNormalsBuffer); @@ -136,7 +122,6 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { gpu::BufferView combinedIndexesBufferView(combinedIndexesBufferPointer, indexElement); result->setIndexBuffer(combinedIndexesBufferView); - std::vector parts; parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex (model::Index)result->getNumIndices(), // numIndices @@ -151,92 +136,6 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { } -// QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { -// int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - -// if (!meshProxy) { -// return QScriptValue(false); -// } - -// MeshPointer mesh = meshProxy->getMeshPointer(); - -// gpu::Resource::Size vertexSize = mesh->getNumVertices() * sizeof(glm::vec3); -// unsigned char* resultVertexData = new unsigned char[vertexSize]; -// unsigned char* vertexDataCursor = resultVertexData; - -// gpu::Resource::Size normalSize = mesh->getNumAttributes() * sizeof(glm::vec3); -// unsigned char* resultNormalData = new unsigned char[normalSize]; -// unsigned char* normalDataCursor = resultNormalData; - -// gpu::Resource::Size indexSize = mesh->getNumIndices() * sizeof(uint32_t); -// unsigned char* resultIndexData = new unsigned char[indexSize]; -// unsigned char* indexDataCursor = resultIndexData; - -// // vertex data -// const gpu::BufferView& vertexBufferView = mesh->getVertexBuffer(); -// gpu::BufferView::Index numVertices = (gpu::BufferView::Index)mesh->getNumVertices(); -// for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { -// glm::vec3 pos = vertexBufferView.get(i); -// pos = glm::vec3(transform * glm::vec4(pos, 1.0f)); -// memcpy(vertexDataCursor, &pos, sizeof(pos)); -// vertexDataCursor += sizeof(pos); -// } - -// // normal data -// const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); -// gpu::BufferView::Index numNormals = (gpu::BufferView::Index)mesh->getNumAttributes(); -// for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { -// glm::vec3 normal = normalsBufferView.get(i); -// normal = glm::vec3(transform * glm::vec4(normal, 0.0f)); -// memcpy(normalDataCursor, &normal, sizeof(normal)); -// normalDataCursor += sizeof(normal); -// } -// // TODO -- other attributes - -// // face data -// const gpu::BufferView& indexBufferView = mesh->getIndexBuffer(); -// gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)mesh->getNumIndices(); -// for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { -// uint32_t index = indexBufferView.get(i); -// memcpy(indexDataCursor, &index, sizeof(index)); -// indexDataCursor += sizeof(index); -// } - -// model::MeshPointer result(new model::Mesh()); - -// gpu::Element vertexElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); -// gpu::Buffer* resultVertexBuffer = new gpu::Buffer(vertexSize, resultVertexData); -// gpu::BufferPointer resultVertexBufferPointer(resultVertexBuffer); -// gpu::BufferView resultVertexBufferView(resultVertexBufferPointer, vertexElement); -// result->setVertexBuffer(resultVertexBufferView); - -// gpu::Element normalElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); -// gpu::Buffer* resultNormalsBuffer = new gpu::Buffer(normalSize, resultNormalData); -// gpu::BufferPointer resultNormalsBufferPointer(resultNormalsBuffer); -// gpu::BufferView resultNormalsBufferView(resultNormalsBufferPointer, normalElement); -// result->addAttribute(attributeTypeNormal, resultNormalsBufferView); - -// gpu::Element indexElement = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW); -// gpu::Buffer* resultIndexesBuffer = new gpu::Buffer(indexSize, resultIndexData); -// gpu::BufferPointer resultIndexesBufferPointer(resultIndexesBuffer); -// gpu::BufferView resultIndexesBufferView(resultIndexesBufferPointer, indexElement); -// result->setIndexBuffer(resultIndexesBufferView); - - -// std::vector parts; -// parts.emplace_back(model::Mesh::Part((model::Index)0, // startIndex -// (model::Index)result->getNumIndices(), // numIndices -// (model::Index)0, // baseVertex -// model::Mesh::TRIANGLES)); // topology -// result->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(model::Mesh::Part), -// (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); - - - -// MeshProxy* resultProxy = new MeshProxy(result); -// return meshToScriptValue(_modelScriptEngine, resultProxy); -// } - QScriptValue ModelScriptingInterface::transformMesh(glm::mat4 transform, MeshProxy* meshProxy) { if (!meshProxy) { From b945d9c4cb92b80a78846108444556c35d57bb4f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 18 Mar 2017 14:34:19 -0700 Subject: [PATCH 26/33] fix a bug that caused obj models with no material to randomly use the materials of other things in the view --- libraries/fbx/src/OBJReader.cpp | 5 +++-- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 73cf7a520e..0cb932b375 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -546,6 +546,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, QString queryPart = _url.query(); bool suppressMaterialsHack = queryPart.contains("hifiusemat"); // If this appears in query string, don't fetch mtl even if used. OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; + preDefinedMaterial.used = true; if (suppressMaterialsHack) { needsMaterialLibrary = preDefinedMaterial.userSpecifiesUV = false; // I said it was a hack... } @@ -594,8 +595,8 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, } foreach (QString materialID, materials.keys()) { - OBJMaterial& objMaterial = materials[materialID]; - if (!objMaterial.used) { + OBJMaterial& objMaterial = materials[materialID]; + if (!objMaterial.used) { continue; } geometry.materials[materialID] = FBXMaterial(objMaterial.diffuseColor, diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index 200f11548d..b4a48c570e 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -58,7 +58,7 @@ public: QByteArray specularTextureFilename; bool used { false }; bool userSpecifiesUV { false }; - OBJMaterial() : shininess(96.0f), opacity(1.0f), diffuseColor(1.0f), specularColor(1.0f) {} + OBJMaterial() : shininess(0.0f), opacity(1.0f), diffuseColor(0.9f), specularColor(0.9f) {} }; class OBJReader: public QObject { // QObject so we can make network requests. From e6446b69136dda58a174f11a3776768eec020bde Mon Sep 17 00:00:00 2001 From: anshuman64 Date: Sat, 18 Mar 2017 19:59:23 -0700 Subject: [PATCH 27/33] New simplified, stand-alone build guide for Windows Still throws this error after trying to build in Visual Studio: Error 9 error MSB3073: The command "setlocal "C:\Program Files\CMake\bin\cmake.exe" "-DBUNDLE_EXECUTABLE=C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/render-perf-test.exe" "-DBUNDLE_PLUGIN_DIR=C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/plugins" -P "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/FixupBundlePostBuild.cmake" if %errorlevel% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone :cmErrorLevel exit /b %1 :cmDone if %errorlevel% neq 0 goto :VCEnd setlocal CMD /C "SET PATH=%PATH%;C:/Qt/Qt5.6.1/5.6/msvc2013_64/bin && C:/Qt/Qt5.6.1/5.6/msvc2013_64/bin/windeployqt.exe --release C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/render-perf-test.exe" if %errorlevel% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone :cmErrorLevel exit /b %1 :cmDone if %errorlevel% neq 0 goto :VCEnd setlocal if exist "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio/qtaudio_windows.dll" ( "C:/Program Files/CMake/bin/cmake.exe" -E remove "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio/qtaudio_windows.dll" && "C:/Program Files/CMake/bin/cmake.exe" -E copy "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/ext/vc12/wasapi/project/src/wasapi/qtaudio_wasapi.dll" "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio" && "C:/Program Files/CMake/bin/cmake.exe" -E copy "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/ext/vc12/wasapi/project/src/wasapi/qtaudio_wasapi.pdb" "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio" ) if %errorlevel% neq 0 goto :cmEnd if exist "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio/qtaudio_windowsd.dll" ( "C:/Program Files/CMake/bin/cmake.exe" -E remove "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio/qtaudio_windowsd.dll" && "C:/Program Files/CMake/bin/cmake.exe" -E copy "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/ext/vc12/wasapi/project/src/wasapi/qtaudio_wasapid.dll" "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio" && "C:/Program Files/CMake/bin/cmake.exe" -E copy "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/ext/vc12/wasapi/project/src/wasapi/qtaudio_wasapid.pdb" "C:/Users/Chris i5 AMD/Documents/GitHub/hifi/build/tests/render-perf/Release/audio" ) if %errorlevel% neq 0 goto :cmEnd :cmEnd endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone :cmErrorLevel exit /b %1 :cmDone if %errorlevel% neq 0 goto :VCEnd :VCEnd" exited with code 1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets 132 5 render-perf-test --- BUILD_WIN.md | 144 +++++++++++++++++++++------------------------------ 1 file changed, 60 insertions(+), 84 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 45373d3093..5d7812342a 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -1,104 +1,80 @@ -Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Windows specific instructions are found in this file. +This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit. -Interface can be built as 32 or 64 bit. +###Step 1. Installing Visual Studio 2013 -###Visual Studio 2013 +If you don't already have the Community or Professional edition of Visual Studio 2013, download and install [Visual Studio Community 2013](https://www.visualstudio.com/en-us/news/releasenotes/vs2013-community-vs). You do not need to install any of the optional components when going through the installer. -You can use the Community or Professional editions of Visual Studio 2013. +Note: Newer versions of Visual Studio are not yet compatible. -You can start a Visual Studio 2013 command prompt using the shortcut provided in the Visual Studio Tools folder installed as part of Visual Studio 2013. +###Step 2. Installing CMake -Or you can start a regular command prompt and then run: +Download and install the "win64-x64 Installer" from the [CMake Website](https://cmake.org/download/). Make sure "Add CMake to system PATH for all users" is checked when going through the installer. - "%VS120COMNTOOLS%\vsvars32.bat" +###Step 3. Installing Qt -####Windows SDK 8.1 +Download and install the [Qt 5.6.1 Installer](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe) -If using Visual Studio 2013 and building as a Visual Studio 2013 project you need the Windows 8 SDK which you should already have as part of installing Visual Studio 2013. You should be able to see it at `C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86`. +Make sure to select all components when going through the installer. -####nmake +###Step 4. Setting Qt Environment Variable -Some of the external projects may require nmake to compile and install. If it is not installed at the location listed below, please ensure that it is in your PATH so CMake can find it when required. +Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." +* Set "Variable name": QT_CMAKE_PREFIX_PATH +* Set "Variable value": `C:\Qt\Qt5.6.1\5.6\msvc2013_64\lib\cmake` -We expect nmake.exe to be located at the following path. +###Step 5. Installing OpenSSL - C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin +Download and install the "Win64 OpenSSL v1.0.xk" Installer from [this website](https://slproweb.com/products/Win32OpenSSL.html), where "x" is the number of the latest release (ex. Win64 OpenSSL v1.0.2k). -###Qt -You can use the online installer or the offline installer. If you use the offline installer, be sure to select the "OpenGL" version. - -* [Download the online installer](http://www.qt.io/download-open-source/#section-2) - * When it asks you to select components, ONLY select one of the following, 32- or 64-bit to match your build preference: - * Qt > Qt 5.6.1 > **msvc2013 32-bit** - * Qt > Qt 5.6.1 > **msvc2013 64-bit** - -* Download the offline installer, 32- or 64-bit to match your build preference: - * [32-bit](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe) - * [64-bit](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe) - -Once Qt is installed, you need to manually configure the following: -* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.6.1\msvc2013\lib\cmake` or `Qt\5.6.1\msvc2013_64\lib\cmake` directory. - * You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New - -###External Libraries - -All libraries should be 32- or 64-bit to match your build preference. - -CMake will need to know where the headers and libraries for required external dependencies are. - -We use CMake's `fixup_bundle` to find the DLLs all of our executable targets require, and then copy them beside the executable in a post-build step. If `fixup_bundle` is having problems finding a DLL, you can fix it manually on your end by adding the folder containing that DLL to your path. Let us know which DLL CMake had trouble finding, as it is possible a tweak to our CMake files is required. - -The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure: - - root_lib_dir - -> openssl - -> bin - -> include - -> lib - -For many of the external libraries where precompiled binaries are readily available you should be able to simply copy the extracted folder that you get from the download links provided at the top of the guide. Otherwise you may need to build from source and install the built product to this directory. The `root_lib_dir` in the above example can be wherever you choose on your system - as long as the environment variable HIFI_LIB_DIR is set to it. From here on, whenever you see %HIFI_LIB_DIR% you should substitute the directory that you chose. - -####OpenSSL - -Qt will use OpenSSL if it's available, but it doesn't install it, so you must install it separately. - -Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll, libeay32.dll) lying around, but they may be the wrong version. If these DLL's are in the PATH then QT will try to use them, and if they're the wrong version then you will see the following errors in the console: - - QSslSocket: cannot resolve TLSv1_1_client_method - QSslSocket: cannot resolve TLSv1_2_client_method - QSslSocket: cannot resolve TLSv1_1_server_method - QSslSocket: cannot resolve TLSv1_2_server_method - QSslSocket: cannot resolve SSL_select_next_proto - QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb - QSslSocket: cannot resolve SSL_get0_next_proto_negotiated - -To prevent these problems, install OpenSSL yourself. Download one of the following binary packages [from this website](https://slproweb.com/products/Win32OpenSSL.html): -* Win32 OpenSSL v1.0.1q -* Win64 OpenSSL v1.0.1q - -Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version. - -###Build High Fidelity using Visual Studio -Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake. - -For 32-bit builds: - - cmake .. -G "Visual Studio 12" - -For 64-bit builds: +###Step 6. Running CMake to Generate Build Files +Run Command Prompt from Start and run the following commands: + cd "%HIFI_DIR%" + mkdir build + cd build cmake .. -G "Visual Studio 12 Win64" + +Where %HIFI_DIR% is the directory for the highfidelity repository. -Open %HIFI_DIR%\build\hifi.sln and compile. +###Step 7. Making a Build -###Running Interface -If you need to debug Interface, you can run interface from within Visual Studio (see the section below). You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Debug\interface.exe +Open '%HIFI_DIR%\build\hifi.sln' using Visual Studio. -###Debugging Interface -* In the Solution Explorer, right click interface and click Set as StartUp Project -* Set the "Working Directory" for the Interface debugging sessions to the Debug output directory so that your application can load resources. Do this: right click interface and click Properties, choose Debugging from Configuration Properties, set Working Directory to .\Debug -* Now you can run and debug interface through Visual Studio +Change the Solution Configuration (next to the green play button) from "Debug" to "Release" for best performance. -For better performance when running debug builds, set the environment variable ```_NO_DEBUG_HEAP``` to ```1``` +Run Build > Build Solution. -http://preshing.com/20110717/the-windows-heap-is-slow-when-launched-from-the-debugger/ +###Step 8. Testing the Interface + +Create another environment variable (see Step #4) +* Set "Variable name": _NO_DEBUG_HEAP +* Set "Variable value": 1 + +In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run Debug > Start Debugging. + +Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow. + +Note: You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Debug\interface.exe + +###Troubleshooting + +For any problems after Step #6, first try this: +* Delete the highfidelity repository +* Restart your computer +* Redownload the [repository](https://github.com/highfidelity/hifi) +* Restart directions from Step #6 + +####CMake gives you the same error message repeatedly after the build fails + +Remove `CMakeCache.txt` found in the '%HIFI_DIR%\build' directory + +####nmake cannot be found + +Make sure nmake.exe is located at the following path: + C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin + +If not, add the directory where nmake is located to the PATH environment variable. + +####Qt is throwing an error + +Make sure you have the current version (5.6.1-1) installed and 'QT_CMAKE_PREFIX_PATH' environment variable is set correctly. From b876d22e46f21bd4c6e87eec2b8c6675255975cc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 18 Mar 2017 22:36:24 -0700 Subject: [PATCH 28/33] fix handling of normals. don't crash when extracting a mesh from a polyvox with no 'on' voxels --- .../src/RenderablePolyVoxEntityItem.h | 2 ++ .../entities/src/EntityScriptingInterface.cpp | 10 ++++-- libraries/entities/src/PolyVoxEntityItem.h | 2 ++ libraries/model/src/model/Geometry.cpp | 31 +++++++++---------- .../src/ModelScriptingInterface.cpp | 7 ++++- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index fa2cdb952f..cf4672f068 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -61,6 +61,8 @@ public: virtual uint8_t getVoxel(int x, int y, int z) override; virtual bool setVoxel(int x, int y, int z, uint8_t toValue) override; + int getOnCount() const override { return _onCount; } + void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 37e9e940b1..7ab0c3f7d9 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -930,11 +930,15 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) { PROFILE_RANGE(script_entities, __FUNCTION__); - bool success; - QScriptValue mesh; + bool success { false }; + QScriptValue mesh { false }; polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable { - success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); + if (polyVoxEntity.getOnCount() == 0) { + success = true; + } else { + success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh); + } return true; }); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 943d273452..311a002a4a 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -57,6 +57,8 @@ class PolyVoxEntityItem : public EntityItem { virtual void setVoxelData(QByteArray voxelData); virtual const QByteArray getVoxelData() const; + virtual int getOnCount() const { return 0; } + enum PolyVoxSurfaceStyle { SURFACE_MARCHING_CUBES, SURFACE_CUBIC, diff --git a/libraries/model/src/model/Geometry.cpp b/libraries/model/src/model/Geometry.cpp index d511ae6cb9..04b0db92d3 100755 --- a/libraries/model/src/model/Geometry.cpp +++ b/libraries/model/src/model/Geometry.cpp @@ -138,15 +138,13 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { model::MeshPointer Mesh::map(std::function vertexFunc, std::function normalFunc, std::function indexFunc) { - int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h - // vertex data - gpu::Resource::Size vertexSize = getNumVertices() * sizeof(glm::vec3); - unsigned char* resultVertexData = new unsigned char[vertexSize]; - unsigned char* vertexDataCursor = resultVertexData; - const gpu::BufferView& vertexBufferView = getVertexBuffer(); gpu::BufferView::Index numVertices = (gpu::BufferView::Index)getNumVertices(); + gpu::Resource::Size vertexSize = numVertices * sizeof(glm::vec3); + unsigned char* resultVertexData = new unsigned char[vertexSize]; + unsigned char* vertexDataCursor = resultVertexData; + for (gpu::BufferView::Index i = 0; i < numVertices; i ++) { glm::vec3 pos = vertexFunc(vertexBufferView.get(i)); memcpy(vertexDataCursor, &pos, sizeof(pos)); @@ -154,12 +152,13 @@ model::MeshPointer Mesh::map(std::function vertexFunc, } // normal data - gpu::Resource::Size normalSize = getNumAttributes() * sizeof(glm::vec3); - unsigned char* resultNormalData = new unsigned char[normalSize]; + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); + gpu::Resource::Size normalSize = numNormals * sizeof(glm::vec3); + unsigned char* resultNormalData = new unsigned char[normalSize]; unsigned char* normalDataCursor = resultNormalData; - const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { glm::vec3 normal = normalFunc(normalsBufferView.get(i)); memcpy(normalDataCursor, &normal, sizeof(normal)); @@ -168,12 +167,12 @@ model::MeshPointer Mesh::map(std::function vertexFunc, // TODO -- other attributes // face data - gpu::Resource::Size indexSize = getNumIndices() * sizeof(uint32_t); - unsigned char* resultIndexData = new unsigned char[indexSize]; + const gpu::BufferView& indexBufferView = getIndexBuffer(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); + gpu::Resource::Size indexSize = numIndexes * sizeof(uint32_t); + unsigned char* resultIndexData = new unsigned char[indexSize]; unsigned char* indexDataCursor = resultIndexData; - const gpu::BufferView& indexBufferView = getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { uint32_t index = indexFunc(indexBufferView.get(i)); memcpy(indexDataCursor, &index, sizeof(index)); @@ -229,7 +228,7 @@ void Mesh::forEach(std::function vertexFunc, // normal data const gpu::BufferView& normalsBufferView = getAttributeBuffer(attributeTypeNormal); - gpu::BufferView::Index numNormals = (gpu::BufferView::Index)getNumAttributes(); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index) normalsBufferView.getNumElements(); for (gpu::BufferView::Index i = 0; i < numNormals; i ++) { normalFunc(normalsBufferView.get(i)); } @@ -237,7 +236,7 @@ void Mesh::forEach(std::function vertexFunc, // face data const gpu::BufferView& indexBufferView = getIndexBuffer(); - gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); + gpu::BufferView::Index numIndexes = (gpu::BufferView::Index)getNumIndices(); for (gpu::BufferView::Index i = 0; i < numIndexes; i ++) { indexFunc(indexBufferView.get(i)); } diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp index cfcb6da0dc..833ac5b64d 100644 --- a/libraries/script-engine/src/ModelScriptingInterface.cpp +++ b/libraries/script-engine/src/ModelScriptingInterface.cpp @@ -61,7 +61,12 @@ QScriptValue ModelScriptingInterface::appendMeshes(MeshProxyList in) { foreach (const MeshProxy* meshProxy, in) { MeshPointer mesh = meshProxy->getMeshPointer(); totalVertexCount += mesh->getNumVertices(); - totalAttributeCount += mesh->getNumAttributes(); + + int attributeTypeNormal = gpu::Stream::InputSlot::NORMAL; // libraries/gpu/src/gpu/Stream.h + const gpu::BufferView& normalsBufferView = mesh->getAttributeBuffer(attributeTypeNormal); + gpu::BufferView::Index numNormals = (gpu::BufferView::Index)normalsBufferView.getNumElements(); + totalAttributeCount += numNormals; + totalIndexCount += mesh->getNumIndices(); } From c430e0c9d6d6fd9b6596ab6dc5eee10760f73ff8 Mon Sep 17 00:00:00 2001 From: anshuman64 Date: Sun, 19 Mar 2017 12:07:45 -0700 Subject: [PATCH 29/33] Small changes based on Zach's recommendations --- BUILD_WIN.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 5d7812342a..e37bf27503 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -8,23 +8,23 @@ Note: Newer versions of Visual Studio are not yet compatible. ###Step 2. Installing CMake -Download and install the "win64-x64 Installer" from the [CMake Website](https://cmake.org/download/). Make sure "Add CMake to system PATH for all users" is checked when going through the installer. +Download and install the CMake 3.8.0-rc2 "win64-x64 Installer" from the [CMake Website](https://cmake.org/download/). Make sure "Add CMake to system PATH for all users" is checked when going through the installer. ###Step 3. Installing Qt -Download and install the [Qt 5.6.1 Installer](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe) +Download and install the [Qt 5.6.1 Installer](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe). Please note that the download file is large (850MB) and may take some time. Make sure to select all components when going through the installer. ###Step 4. Setting Qt Environment Variable -Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." +Go to "Control Panel > System > Advanced System Settings > Environment Variables > New..." (or search “Environment Variables” in Start Search). * Set "Variable name": QT_CMAKE_PREFIX_PATH * Set "Variable value": `C:\Qt\Qt5.6.1\5.6\msvc2013_64\lib\cmake` ###Step 5. Installing OpenSSL -Download and install the "Win64 OpenSSL v1.0.xk" Installer from [this website](https://slproweb.com/products/Win32OpenSSL.html), where "x" is the number of the latest release (ex. Win64 OpenSSL v1.0.2k). +Download and install the "Win64 OpenSSL v1.0.2k" Installer from [this website](https://slproweb.com/products/Win32OpenSSL.html). ###Step 6. Running CMake to Generate Build Files @@ -44,7 +44,7 @@ Change the Solution Configuration (next to the green play button) from "Debug" t Run Build > Build Solution. -###Step 8. Testing the Interface +###Step 8. Testing Interface Create another environment variable (see Step #4) * Set "Variable name": _NO_DEBUG_HEAP @@ -54,12 +54,12 @@ In Visual Studio, right+click "interface" under the Apps folder in Solution Expl Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow. -Note: You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Debug\interface.exe +Note: You can also run Interface by launching it from command line or File Explorer from %HIFI_DIR%\build\interface\Release\interface.exe ###Troubleshooting For any problems after Step #6, first try this: -* Delete the highfidelity repository +* Delete your locally cloned copy of the highfidelity repository * Restart your computer * Redownload the [repository](https://github.com/highfidelity/hifi) * Restart directions from Step #6 @@ -77,4 +77,5 @@ If not, add the directory where nmake is located to the PATH environment variabl ####Qt is throwing an error -Make sure you have the current version (5.6.1-1) installed and 'QT_CMAKE_PREFIX_PATH' environment variable is set correctly. +Make sure you have the correct version (5.6.1-1) installed and 'QT_CMAKE_PREFIX_PATH' environment variable is set correctly. + From 3612b9fccc91e2acfc4c4d339c0632437fb26feb Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Sun, 19 Mar 2017 07:40:22 -0400 Subject: [PATCH 30/33] Remove Edit > Scripts Editor and all related source files --- interface/src/Application.cpp | 2 - interface/src/Menu.cpp | 5 - interface/src/Menu.h | 1 - interface/src/ui/DialogsManager.cpp | 7 - interface/src/ui/DialogsManager.h | 2 - interface/src/ui/ScriptEditBox.cpp | 111 -------- interface/src/ui/ScriptEditBox.h | 38 --- interface/src/ui/ScriptEditorWidget.cpp | 256 ----------------- interface/src/ui/ScriptEditorWidget.h | 64 ----- interface/src/ui/ScriptEditorWindow.cpp | 259 ----------------- interface/src/ui/ScriptEditorWindow.h | 64 ----- interface/src/ui/ScriptLineNumberArea.cpp | 28 -- interface/src/ui/ScriptLineNumberArea.h | 32 --- interface/src/ui/ScriptsTableWidget.cpp | 49 ---- interface/src/ui/ScriptsTableWidget.h | 28 -- interface/ui/scriptEditorWidget.ui | 142 ---------- interface/ui/scriptEditorWindow.ui | 324 ---------------------- 17 files changed, 1412 deletions(-) delete mode 100644 interface/src/ui/ScriptEditBox.cpp delete mode 100644 interface/src/ui/ScriptEditBox.h delete mode 100644 interface/src/ui/ScriptEditorWidget.cpp delete mode 100644 interface/src/ui/ScriptEditorWidget.h delete mode 100644 interface/src/ui/ScriptEditorWindow.cpp delete mode 100644 interface/src/ui/ScriptEditorWindow.h delete mode 100644 interface/src/ui/ScriptLineNumberArea.cpp delete mode 100644 interface/src/ui/ScriptLineNumberArea.h delete mode 100644 interface/src/ui/ScriptsTableWidget.cpp delete mode 100644 interface/src/ui/ScriptsTableWidget.h delete mode 100644 interface/ui/scriptEditorWidget.ui delete mode 100644 interface/ui/scriptEditorWindow.ui diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 03f992bf7a..880f9ca8f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2768,8 +2768,6 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_S: if (isShifted && isMeta && !isOption) { Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings); - } else if (isOption && !isShifted && !isMeta) { - Menu::getInstance()->triggerOption(MenuOption::ScriptEditor); } else if (!isOption && !isShifted && isMeta) { takeSnapshot(true); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8e124d27c7..3d0b7735ad 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -120,11 +120,6 @@ Menu::Menu() { scriptEngines.data(), SLOT(reloadAllScripts()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - // Edit > Scripts Editor... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, - dialogsManager.data(), SLOT(showScriptEditor()), - QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - // Edit > Console... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, DependencyManager::get().data(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e0ac340edc..ec5cbba948 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,7 +168,6 @@ namespace MenuOption { const QString RunningScripts = "Running Scripts..."; const QString RunClientScriptTests = "Run Client Script Tests"; const QString RunTimingTests = "Run Timing Tests"; - const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; const QString SendWrongDSConnectVersion = "Send wrong DS connect version"; const QString SendWrongProtocolVersion = "Send wrong protocol version"; diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 20b9f6b173..52ce84df6e 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -27,7 +27,6 @@ #include "LoginDialog.h" #include "OctreeStatsDialog.h" #include "PreferencesDialog.h" -#include "ScriptEditorWindow.h" #include "UpdateDialog.h" template @@ -126,12 +125,6 @@ void DialogsManager::hmdToolsClosed() { } } -void DialogsManager::showScriptEditor() { - maybeCreateDialog(_scriptEditor); - _scriptEditor->show(); - _scriptEditor->raise(); -} - void DialogsManager::showTestingResults() { if (!_testingDialog) { _testingDialog = new TestingDialog(qApp->getWindow()); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 4e3b785679..662cbd1640 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -51,7 +51,6 @@ public slots: void octreeStatsDetails(); void lodTools(); void hmdTools(bool showTools); - void showScriptEditor(); void showDomainConnectionDialog(); void showTestingResults(); @@ -79,7 +78,6 @@ private: QPointer _hmdToolsDialog; QPointer _lodToolsDialog; QPointer _octreeStatsDialog; - QPointer _scriptEditor; QPointer _testingDialog; QPointer _domainConnectionDialog; }; diff --git a/interface/src/ui/ScriptEditBox.cpp b/interface/src/ui/ScriptEditBox.cpp deleted file mode 100644 index 2aea225b17..0000000000 --- a/interface/src/ui/ScriptEditBox.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// ScriptEditBox.cpp -// interface/src/ui -// -// Created by Thijs Wenker on 4/30/14. -// Copyright 2014 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 "ScriptEditBox.h" - -#include -#include - -#include "ScriptLineNumberArea.h" - -ScriptEditBox::ScriptEditBox(QWidget* parent) : - QPlainTextEdit(parent) -{ - _scriptLineNumberArea = new ScriptLineNumberArea(this); - - connect(this, &ScriptEditBox::blockCountChanged, this, &ScriptEditBox::updateLineNumberAreaWidth); - connect(this, &ScriptEditBox::updateRequest, this, &ScriptEditBox::updateLineNumberArea); - connect(this, &ScriptEditBox::cursorPositionChanged, this, &ScriptEditBox::highlightCurrentLine); - - updateLineNumberAreaWidth(0); - highlightCurrentLine(); -} - -int ScriptEditBox::lineNumberAreaWidth() { - int digits = 1; - const int SPACER_PIXELS = 3; - const int BASE_TEN = 10; - int max = qMax(1, blockCount()); - while (max >= BASE_TEN) { - max /= BASE_TEN; - digits++; - } - return SPACER_PIXELS + fontMetrics().width(QLatin1Char('H')) * digits; -} - -void ScriptEditBox::updateLineNumberAreaWidth(int blockCount) { - setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); -} - -void ScriptEditBox::updateLineNumberArea(const QRect& rect, int deltaY) { - if (deltaY) { - _scriptLineNumberArea->scroll(0, deltaY); - } else { - _scriptLineNumberArea->update(0, rect.y(), _scriptLineNumberArea->width(), rect.height()); - } - - if (rect.contains(viewport()->rect())) { - updateLineNumberAreaWidth(0); - } -} - -void ScriptEditBox::resizeEvent(QResizeEvent* event) { - QPlainTextEdit::resizeEvent(event); - - QRect localContentsRect = contentsRect(); - _scriptLineNumberArea->setGeometry(QRect(localContentsRect.left(), localContentsRect.top(), lineNumberAreaWidth(), - localContentsRect.height())); -} - -void ScriptEditBox::highlightCurrentLine() { - QList extraSelections; - - if (!isReadOnly()) { - QTextEdit::ExtraSelection selection; - - QColor lineColor = QColor(Qt::gray).lighter(); - - selection.format.setBackground(lineColor); - selection.format.setProperty(QTextFormat::FullWidthSelection, true); - selection.cursor = textCursor(); - selection.cursor.clearSelection(); - extraSelections.append(selection); - } - - setExtraSelections(extraSelections); -} - -void ScriptEditBox::lineNumberAreaPaintEvent(QPaintEvent* event) -{ - QPainter painter(_scriptLineNumberArea); - painter.fillRect(event->rect(), Qt::lightGray); - QTextBlock block = firstVisibleBlock(); - int blockNumber = block.blockNumber(); - int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); - int bottom = top + (int) blockBoundingRect(block).height(); - - while (block.isValid() && top <= event->rect().bottom()) { - if (block.isVisible() && bottom >= event->rect().top()) { - QFont font = painter.font(); - font.setBold(this->textCursor().blockNumber() == block.blockNumber()); - painter.setFont(font); - QString number = QString::number(blockNumber + 1); - painter.setPen(Qt::black); - painter.drawText(0, top, _scriptLineNumberArea->width(), fontMetrics().height(), - Qt::AlignRight, number); - } - - block = block.next(); - top = bottom; - bottom = top + (int) blockBoundingRect(block).height(); - blockNumber++; - } -} diff --git a/interface/src/ui/ScriptEditBox.h b/interface/src/ui/ScriptEditBox.h deleted file mode 100644 index 0b037db16a..0000000000 --- a/interface/src/ui/ScriptEditBox.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// ScriptEditBox.h -// interface/src/ui -// -// Created by Thijs Wenker on 4/30/14. -// Copyright 2014 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 -// - -#ifndef hifi_ScriptEditBox_h -#define hifi_ScriptEditBox_h - -#include - -class ScriptEditBox : public QPlainTextEdit { - Q_OBJECT - -public: - ScriptEditBox(QWidget* parent = NULL); - - void lineNumberAreaPaintEvent(QPaintEvent* event); - int lineNumberAreaWidth(); - -protected: - void resizeEvent(QResizeEvent* event) override; - -private slots: - void updateLineNumberAreaWidth(int blockCount); - void highlightCurrentLine(); - void updateLineNumberArea(const QRect& rect, int deltaY); - -private: - QWidget* _scriptLineNumberArea; -}; - -#endif // hifi_ScriptEditBox_h diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp deleted file mode 100644 index ada6b11355..0000000000 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// -// ScriptEditorWidget.cpp -// interface/src/ui -// -// Created by Thijs Wenker on 4/14/14. -// Copyright 2014 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 "ui_scriptEditorWidget.h" -#include "ScriptEditorWidget.h" -#include "ScriptEditorWindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Application.h" -#include "ScriptHighlighting.h" - -ScriptEditorWidget::ScriptEditorWidget() : - _scriptEditorWidgetUI(new Ui::ScriptEditorWidget), - _scriptEngine(NULL), - _isRestarting(false), - _isReloading(false) -{ - setAttribute(Qt::WA_DeleteOnClose); - - _scriptEditorWidgetUI->setupUi(this); - - connect(_scriptEditorWidgetUI->scriptEdit->document(), &QTextDocument::modificationChanged, this, - &ScriptEditorWidget::scriptModified); - connect(_scriptEditorWidgetUI->scriptEdit->document(), &QTextDocument::contentsChanged, this, - &ScriptEditorWidget::onScriptModified); - - // remove the title bar (see the Qt docs on setTitleBarWidget) - setTitleBarWidget(new QWidget()); - QFontMetrics fm(_scriptEditorWidgetUI->scriptEdit->font()); - _scriptEditorWidgetUI->scriptEdit->setTabStopWidth(fm.width('0') * 4); - // We create a new ScriptHighligting QObject and provide it with a parent so this is NOT a memory leak. - new ScriptHighlighting(_scriptEditorWidgetUI->scriptEdit->document()); - QTimer::singleShot(0, _scriptEditorWidgetUI->scriptEdit, SLOT(setFocus())); - - _console = new JSConsole(this); - _console->setFixedHeight(CONSOLE_HEIGHT); - _scriptEditorWidgetUI->verticalLayout->addWidget(_console); - connect(_scriptEditorWidgetUI->clearButton, &QPushButton::clicked, _console, &JSConsole::clear); -} - -ScriptEditorWidget::~ScriptEditorWidget() { - delete _scriptEditorWidgetUI; - delete _console; -} - -void ScriptEditorWidget::onScriptModified() { - if(_scriptEditorWidgetUI->onTheFlyCheckBox->isChecked() && isModified() && isRunning() && !_isReloading) { - _isRestarting = true; - setRunning(false); - // Script is restarted once current script instance finishes. - } -} - -void ScriptEditorWidget::onScriptFinished(const QString& scriptPath) { - _scriptEngine = NULL; - _console->setScriptEngine(NULL); - if (_isRestarting) { - _isRestarting = false; - setRunning(true); - } -} - -bool ScriptEditorWidget::isModified() { - return _scriptEditorWidgetUI->scriptEdit->document()->isModified(); -} - -bool ScriptEditorWidget::isRunning() { - return (_scriptEngine != NULL) ? _scriptEngine->isRunning() : false; -} - -bool ScriptEditorWidget::setRunning(bool run) { - if (run && isModified() && !save()) { - return false; - } - - if (_scriptEngine != NULL) { - disconnect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); - disconnect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); - disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); - } - - auto scriptEngines = DependencyManager::get(); - if (run) { - const QString& scriptURLString = QUrl(_currentScript).toString(); - // Reload script so that an out of date copy is not retrieved from the cache - _scriptEngine = scriptEngines->loadScript(scriptURLString, true, true, false, true); - connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); - connect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); - connect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); - } else { - connect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); - const QString& scriptURLString = QUrl(_currentScript).toString(); - scriptEngines->stopScript(scriptURLString); - _scriptEngine = NULL; - } - _console->setScriptEngine(_scriptEngine); - return true; -} - -bool ScriptEditorWidget::saveFile(const QString &scriptPath) { - QFile file(scriptPath); - if (!file.open(QFile::WriteOnly | QFile::Text)) { - OffscreenUi::warning(this, tr("Interface"), tr("Cannot write script %1:\n%2.").arg(scriptPath) - .arg(file.errorString())); - return false; - } - - QTextStream out(&file); - out << _scriptEditorWidgetUI->scriptEdit->toPlainText(); - file.close(); - - setScriptFile(scriptPath); - return true; -} - -void ScriptEditorWidget::loadFile(const QString& scriptPath) { - QUrl url(scriptPath); - - // if the scheme length is one or lower, maybe they typed in a file, let's try - const int WINDOWS_DRIVE_LETTER_SIZE = 1; - if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) { - QFile file(scriptPath); - if (!file.open(QFile::ReadOnly | QFile::Text)) { - OffscreenUi::warning(this, tr("Interface"), tr("Cannot read script %1:\n%2.").arg(scriptPath) - .arg(file.errorString())); - return; - } - QTextStream in(&file); - _scriptEditorWidgetUI->scriptEdit->setPlainText(in.readAll()); - file.close(); - setScriptFile(scriptPath); - - if (_scriptEngine != NULL) { - disconnect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); - disconnect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); - disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); - } - } else { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest = QNetworkRequest(url); - networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - QNetworkReply* reply = networkAccessManager.get(networkRequest); - qDebug() << "Downloading included script at" << scriptPath; - QEventLoop loop; - QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); - loop.exec(); - _scriptEditorWidgetUI->scriptEdit->setPlainText(reply->readAll()); - delete reply; - - if (!saveAs()) { - static_cast(this->parent()->parent()->parent())->terminateCurrentTab(); - } - } - const QString& scriptURLString = QUrl(_currentScript).toString(); - _scriptEngine = DependencyManager::get()->getScriptEngine(scriptURLString); - if (_scriptEngine != NULL) { - connect(_scriptEngine, &ScriptEngine::runningStateChanged, this, &ScriptEditorWidget::runningStateChanged); - connect(_scriptEngine, &ScriptEngine::update, this, &ScriptEditorWidget::onScriptModified); - connect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); - } - _console->setScriptEngine(_scriptEngine); -} - -bool ScriptEditorWidget::save() { - return _currentScript.isEmpty() ? saveAs() : saveFile(_currentScript); -} - -bool ScriptEditorWidget::saveAs() { - auto scriptEngines = DependencyManager::get(); - QString fileName = QFileDialog::getSaveFileName(this, tr("Save script"), - qApp->getPreviousScriptLocation(), - tr("JavaScript Files (*.js)")); - if (!fileName.isEmpty()) { - qApp->setPreviousScriptLocation(fileName); - return saveFile(fileName); - } else { - return false; - } -} - -void ScriptEditorWidget::setScriptFile(const QString& scriptPath) { - _currentScript = scriptPath; - _currentScriptModified = QFileInfo(_currentScript).lastModified(); - _scriptEditorWidgetUI->scriptEdit->document()->setModified(false); - setWindowModified(false); - - emit scriptnameChanged(); -} - -bool ScriptEditorWidget::questionSave() { - if (_scriptEditorWidgetUI->scriptEdit->document()->isModified()) { - QMessageBox::StandardButton button = OffscreenUi::warning(this, tr("Interface"), - tr("The script has been modified.\nDo you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard | - QMessageBox::Cancel, QMessageBox::Save); - return button == QMessageBox::Save ? save() : (button == QMessageBox::Discard); - } - return true; -} - -void ScriptEditorWidget::onWindowActivated() { - if (!_isReloading) { - _isReloading = true; - - QDateTime fileStamp = QFileInfo(_currentScript).lastModified(); - if (fileStamp > _currentScriptModified) { - bool doReload = false; - auto window = static_cast(this->parent()->parent()->parent()); - window->inModalDialog = true; - if (window->autoReloadScripts() - || OffscreenUi::question(this, tr("Reload Script"), - tr("The following file has been modified outside of the Interface editor:") + "\n" + _currentScript + "\n" - + (isModified() - ? tr("Do you want to reload it and lose the changes you've made in the Interface editor?") - : tr("Do you want to reload it?")), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - doReload = true; - } - window->inModalDialog = false; - if (doReload) { - loadFile(_currentScript); - if (_scriptEditorWidgetUI->onTheFlyCheckBox->isChecked() && isRunning()) { - _isRestarting = true; - setRunning(false); - // Script is restarted once current script instance finishes. - } - } else { - _currentScriptModified = fileStamp; // Asked and answered. Don't ask again until the external file is changed again. - } - } - _isReloading = false; - } -} diff --git a/interface/src/ui/ScriptEditorWidget.h b/interface/src/ui/ScriptEditorWidget.h deleted file mode 100644 index f53fd7b718..0000000000 --- a/interface/src/ui/ScriptEditorWidget.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// ScriptEditorWidget.h -// interface/src/ui -// -// Created by Thijs Wenker on 4/14/14. -// Copyright 2014 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 -// - -#ifndef hifi_ScriptEditorWidget_h -#define hifi_ScriptEditorWidget_h - -#include - -#include "JSConsole.h" -#include "ScriptEngine.h" - -namespace Ui { - class ScriptEditorWidget; -} - -class ScriptEditorWidget : public QDockWidget { - Q_OBJECT - -public: - ScriptEditorWidget(); - ~ScriptEditorWidget(); - - bool isModified(); - bool isRunning(); - bool setRunning(bool run); - bool saveFile(const QString& scriptPath); - void loadFile(const QString& scriptPath); - void setScriptFile(const QString& scriptPath); - bool save(); - bool saveAs(); - bool questionSave(); - const QString getScriptName() const { return _currentScript; }; - -signals: - void runningStateChanged(); - void scriptnameChanged(); - void scriptModified(); - -public slots: - void onWindowActivated(); - -private slots: - void onScriptModified(); - void onScriptFinished(const QString& scriptName); - -private: - JSConsole* _console; - Ui::ScriptEditorWidget* _scriptEditorWidgetUI; - ScriptEngine* _scriptEngine; - QString _currentScript; - QDateTime _currentScriptModified; - bool _isRestarting; - bool _isReloading; -}; - -#endif // hifi_ScriptEditorWidget_h diff --git a/interface/src/ui/ScriptEditorWindow.cpp b/interface/src/ui/ScriptEditorWindow.cpp deleted file mode 100644 index 58abd23979..0000000000 --- a/interface/src/ui/ScriptEditorWindow.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// -// ScriptEditorWindow.cpp -// interface/src/ui -// -// Created by Thijs Wenker on 4/14/14. -// Copyright 2014 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 - -#include "ui_scriptEditorWindow.h" -#include "ScriptEditorWindow.h" -#include "ScriptEditorWidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "Application.h" -#include "PathUtils.h" - -ScriptEditorWindow::ScriptEditorWindow(QWidget* parent) : - QWidget(parent), - _ScriptEditorWindowUI(new Ui::ScriptEditorWindow), - _loadMenu(new QMenu), - _saveMenu(new QMenu) -{ - setAttribute(Qt::WA_DeleteOnClose); - - _ScriptEditorWindowUI->setupUi(this); - - this->setWindowFlags(Qt::Tool); - addScriptEditorWidget("New script"); - connect(_loadMenu, &QMenu::aboutToShow, this, &ScriptEditorWindow::loadMenuAboutToShow); - _ScriptEditorWindowUI->loadButton->setMenu(_loadMenu); - - _saveMenu->addAction("Save as..", this, SLOT(saveScriptAsClicked()), Qt::CTRL | Qt::SHIFT | Qt::Key_S); - - _ScriptEditorWindowUI->saveButton->setMenu(_saveMenu); - - connect(new QShortcut(QKeySequence("Ctrl+N"), this), &QShortcut::activated, this, &ScriptEditorWindow::newScriptClicked); - connect(new QShortcut(QKeySequence("Ctrl+S"), this), &QShortcut::activated, this,&ScriptEditorWindow::saveScriptClicked); - connect(new QShortcut(QKeySequence("Ctrl+O"), this), &QShortcut::activated, this, &ScriptEditorWindow::loadScriptClicked); - connect(new QShortcut(QKeySequence("F5"), this), &QShortcut::activated, this, &ScriptEditorWindow::toggleRunScriptClicked); - - _ScriptEditorWindowUI->loadButton->setIcon(QIcon(QPixmap(PathUtils::resourcesPath() + "icons/load-script.svg"))); - _ScriptEditorWindowUI->newButton->setIcon(QIcon(QPixmap(PathUtils::resourcesPath() + "icons/new-script.svg"))); - _ScriptEditorWindowUI->saveButton->setIcon(QIcon(QPixmap(PathUtils::resourcesPath() + "icons/save-script.svg"))); - _ScriptEditorWindowUI->toggleRunButton->setIcon(QIcon(QPixmap(PathUtils::resourcesPath() + "icons/start-script.svg"))); -} - -ScriptEditorWindow::~ScriptEditorWindow() { - delete _ScriptEditorWindowUI; -} - -void ScriptEditorWindow::setRunningState(bool run) { - if (_ScriptEditorWindowUI->tabWidget->currentIndex() != -1) { - static_cast(_ScriptEditorWindowUI->tabWidget->currentWidget())->setRunning(run); - } - this->updateButtons(); -} - -void ScriptEditorWindow::updateButtons() { - bool isRunning = _ScriptEditorWindowUI->tabWidget->currentIndex() != -1 && - static_cast(_ScriptEditorWindowUI->tabWidget->currentWidget())->isRunning(); - _ScriptEditorWindowUI->toggleRunButton->setEnabled(_ScriptEditorWindowUI->tabWidget->currentIndex() != -1); - _ScriptEditorWindowUI->toggleRunButton->setIcon(QIcon(QPixmap(PathUtils::resourcesPath() + ((isRunning ? - "icons/stop-script.svg" : "icons/start-script.svg"))))); -} - -void ScriptEditorWindow::loadScriptMenu(const QString& scriptName) { - addScriptEditorWidget("loading...")->loadFile(scriptName); - updateButtons(); -} - -void ScriptEditorWindow::loadScriptClicked() { - QString scriptName = QFileDialog::getOpenFileName(this, tr("Interface"), - qApp->getPreviousScriptLocation(), - tr("JavaScript Files (*.js)")); - if (!scriptName.isEmpty()) { - qApp->setPreviousScriptLocation(scriptName); - addScriptEditorWidget("loading...")->loadFile(scriptName); - updateButtons(); - } -} - -void ScriptEditorWindow::loadMenuAboutToShow() { - _loadMenu->clear(); - QStringList runningScripts = DependencyManager::get()->getRunningScripts(); - if (runningScripts.count() > 0) { - QSignalMapper* signalMapper = new QSignalMapper(this); - foreach (const QString& runningScript, runningScripts) { - QAction* runningScriptAction = new QAction(runningScript, _loadMenu); - connect(runningScriptAction, SIGNAL(triggered()), signalMapper, SLOT(map())); - signalMapper->setMapping(runningScriptAction, runningScript); - _loadMenu->addAction(runningScriptAction); - } - connect(signalMapper, SIGNAL(mapped(const QString &)), this, SLOT(loadScriptMenu(const QString&))); - } else { - QAction* naAction = new QAction("(no running scripts)", _loadMenu); - naAction->setDisabled(true); - _loadMenu->addAction(naAction); - } -} - -void ScriptEditorWindow::newScriptClicked() { - addScriptEditorWidget(QString("New script")); -} - -void ScriptEditorWindow::toggleRunScriptClicked() { - this->setRunningState(!(_ScriptEditorWindowUI->tabWidget->currentIndex() !=-1 - && static_cast(_ScriptEditorWindowUI->tabWidget->currentWidget())->isRunning())); -} - -void ScriptEditorWindow::saveScriptClicked() { - if (_ScriptEditorWindowUI->tabWidget->currentIndex() != -1) { - ScriptEditorWidget* currentScriptWidget = static_cast(_ScriptEditorWindowUI->tabWidget - ->currentWidget()); - currentScriptWidget->save(); - } -} - -void ScriptEditorWindow::saveScriptAsClicked() { - if (_ScriptEditorWindowUI->tabWidget->currentIndex() != -1) { - ScriptEditorWidget* currentScriptWidget = static_cast(_ScriptEditorWindowUI->tabWidget - ->currentWidget()); - currentScriptWidget->saveAs(); - } -} - -ScriptEditorWidget* ScriptEditorWindow::addScriptEditorWidget(QString title) { - ScriptEditorWidget* newScriptEditorWidget = new ScriptEditorWidget(); - connect(newScriptEditorWidget, &ScriptEditorWidget::scriptnameChanged, this, &ScriptEditorWindow::updateScriptNameOrStatus); - connect(newScriptEditorWidget, &ScriptEditorWidget::scriptModified, this, &ScriptEditorWindow::updateScriptNameOrStatus); - connect(newScriptEditorWidget, &ScriptEditorWidget::runningStateChanged, this, &ScriptEditorWindow::updateButtons); - connect(this, &ScriptEditorWindow::windowActivated, newScriptEditorWidget, &ScriptEditorWidget::onWindowActivated); - _ScriptEditorWindowUI->tabWidget->addTab(newScriptEditorWidget, title); - _ScriptEditorWindowUI->tabWidget->setCurrentWidget(newScriptEditorWidget); - newScriptEditorWidget->setUpdatesEnabled(true); - newScriptEditorWidget->adjustSize(); - return newScriptEditorWidget; -} - -void ScriptEditorWindow::tabSwitched(int tabIndex) { - this->updateButtons(); - if (_ScriptEditorWindowUI->tabWidget->currentIndex() != -1) { - ScriptEditorWidget* currentScriptWidget = static_cast(_ScriptEditorWindowUI->tabWidget - ->currentWidget()); - QString modifiedStar = (currentScriptWidget->isModified() ? "*" : ""); - if (currentScriptWidget->getScriptName().length() > 0) { - this->setWindowTitle("Script Editor [" + currentScriptWidget->getScriptName() + modifiedStar + "]"); - } else { - this->setWindowTitle("Script Editor [New script" + modifiedStar + "]"); - } - } else { - this->setWindowTitle("Script Editor"); - } -} - -void ScriptEditorWindow::tabCloseRequested(int tabIndex) { - if (ignoreCloseForModal(nullptr)) { - return; - } - ScriptEditorWidget* closingScriptWidget = static_cast(_ScriptEditorWindowUI->tabWidget - ->widget(tabIndex)); - if(closingScriptWidget->questionSave()) { - _ScriptEditorWindowUI->tabWidget->removeTab(tabIndex); - } -} - -// If this operating system window causes a qml overlay modal dialog (which might not even be seen by the user), closing this window -// will crash the code that was waiting on the dialog result. So that code whousl set inModalDialog to true while the question is up. -// This code will not be necessary when switch out all operating system windows for qml overlays. -bool ScriptEditorWindow::ignoreCloseForModal(QCloseEvent* event) { - if (!inModalDialog) { - return false; - } - // Deliberately not using OffscreenUi, so that the dialog is seen. - QMessageBox::information(this, tr("Interface"), tr("There is a modal dialog that must be answered before closing."), - QMessageBox::Discard, QMessageBox::Discard); - if (event) { - event->ignore(); // don't close - } - return true; -} - -void ScriptEditorWindow::closeEvent(QCloseEvent *event) { - if (ignoreCloseForModal(event)) { - return; - } - bool unsaved_docs_warning = false; - for (int i = 0; i < _ScriptEditorWindowUI->tabWidget->count(); i++){ - if(static_cast(_ScriptEditorWindowUI->tabWidget->widget(i))->isModified()){ - unsaved_docs_warning = true; - break; - } - } - - if (!unsaved_docs_warning || QMessageBox::warning(this, tr("Interface"), - tr("There are some unsaved scripts, are you sure you want to close the editor? Changes will be lost!"), - QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Discard) { - event->accept(); - } else { - event->ignore(); - } -} - -void ScriptEditorWindow::updateScriptNameOrStatus() { - ScriptEditorWidget* source = static_cast(QObject::sender()); - QString modifiedStar = (source->isModified()? "*" : ""); - if (source->getScriptName().length() > 0) { - for (int i = 0; i < _ScriptEditorWindowUI->tabWidget->count(); i++){ - if (_ScriptEditorWindowUI->tabWidget->widget(i) == source) { - _ScriptEditorWindowUI->tabWidget->setTabText(i, modifiedStar + QFileInfo(source->getScriptName()).fileName()); - _ScriptEditorWindowUI->tabWidget->setTabToolTip(i, source->getScriptName()); - } - } - } - - if (_ScriptEditorWindowUI->tabWidget->currentWidget() == source) { - if (source->getScriptName().length() > 0) { - this->setWindowTitle("Script Editor [" + source->getScriptName() + modifiedStar + "]"); - } else { - this->setWindowTitle("Script Editor [New script" + modifiedStar + "]"); - } - } -} - -void ScriptEditorWindow::terminateCurrentTab() { - if (_ScriptEditorWindowUI->tabWidget->currentIndex() != -1) { - _ScriptEditorWindowUI->tabWidget->removeTab(_ScriptEditorWindowUI->tabWidget->currentIndex()); - this->raise(); - } -} - -bool ScriptEditorWindow::autoReloadScripts() { - return _ScriptEditorWindowUI->autoReloadCheckBox->isChecked(); -} - -bool ScriptEditorWindow::event(QEvent* event) { - if (event->type() == QEvent::WindowActivate) { - emit windowActivated(); - } - return QWidget::event(event); -} - diff --git a/interface/src/ui/ScriptEditorWindow.h b/interface/src/ui/ScriptEditorWindow.h deleted file mode 100644 index af9863d136..0000000000 --- a/interface/src/ui/ScriptEditorWindow.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// ScriptEditorWindow.h -// interface/src/ui -// -// Created by Thijs Wenker on 4/14/14. -// Copyright 2014 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 -// - -#ifndef hifi_ScriptEditorWindow_h -#define hifi_ScriptEditorWindow_h - -#include "ScriptEditorWidget.h" - -namespace Ui { - class ScriptEditorWindow; -} - -class ScriptEditorWindow : public QWidget { - Q_OBJECT - -public: - ScriptEditorWindow(QWidget* parent = nullptr); - ~ScriptEditorWindow(); - - void terminateCurrentTab(); - bool autoReloadScripts(); - - bool inModalDialog { false }; - bool ignoreCloseForModal(QCloseEvent* event); - -signals: - void windowActivated(); - -protected: - void closeEvent(QCloseEvent* event) override; - virtual bool event(QEvent* event) override; - -private: - Ui::ScriptEditorWindow* _ScriptEditorWindowUI; - QMenu* _loadMenu; - QMenu* _saveMenu; - - ScriptEditorWidget* addScriptEditorWidget(QString title); - void setRunningState(bool run); - void setScriptName(const QString& scriptName); - -private slots: - void loadScriptMenu(const QString& scriptName); - void loadScriptClicked(); - void newScriptClicked(); - void toggleRunScriptClicked(); - void saveScriptClicked(); - void saveScriptAsClicked(); - void loadMenuAboutToShow(); - void tabSwitched(int tabIndex); - void tabCloseRequested(int tabIndex); - void updateScriptNameOrStatus(); - void updateButtons(); -}; - -#endif // hifi_ScriptEditorWindow_h diff --git a/interface/src/ui/ScriptLineNumberArea.cpp b/interface/src/ui/ScriptLineNumberArea.cpp deleted file mode 100644 index 6d7e9185ea..0000000000 --- a/interface/src/ui/ScriptLineNumberArea.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// -// ScriptLineNumberArea.cpp -// interface/src/ui -// -// Created by Thijs Wenker on 4/30/14. -// Copyright 2014 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 "ScriptLineNumberArea.h" - -#include "ScriptEditBox.h" - -ScriptLineNumberArea::ScriptLineNumberArea(ScriptEditBox* scriptEditBox) : - QWidget(scriptEditBox) -{ - _scriptEditBox = scriptEditBox; -} - -QSize ScriptLineNumberArea::sizeHint() const { - return QSize(_scriptEditBox->lineNumberAreaWidth(), 0); -} - -void ScriptLineNumberArea::paintEvent(QPaintEvent* event) { - _scriptEditBox->lineNumberAreaPaintEvent(event); -} diff --git a/interface/src/ui/ScriptLineNumberArea.h b/interface/src/ui/ScriptLineNumberArea.h deleted file mode 100644 index 77de8244ce..0000000000 --- a/interface/src/ui/ScriptLineNumberArea.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// ScriptLineNumberArea.h -// interface/src/ui -// -// Created by Thijs Wenker on 4/30/14. -// Copyright 2014 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 -// - -#ifndef hifi_ScriptLineNumberArea_h -#define hifi_ScriptLineNumberArea_h - -#include - -class ScriptEditBox; - -class ScriptLineNumberArea : public QWidget { - -public: - ScriptLineNumberArea(ScriptEditBox* scriptEditBox); - QSize sizeHint() const override; - -protected: - void paintEvent(QPaintEvent* event) override; - -private: - ScriptEditBox* _scriptEditBox; -}; - -#endif // hifi_ScriptLineNumberArea_h diff --git a/interface/src/ui/ScriptsTableWidget.cpp b/interface/src/ui/ScriptsTableWidget.cpp deleted file mode 100644 index 7b4f9e6b1f..0000000000 --- a/interface/src/ui/ScriptsTableWidget.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// ScriptsTableWidget.cpp -// interface -// -// Created by Mohammed Nafees on 04/03/2014. -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include -#include - -#include "ScriptsTableWidget.h" - -ScriptsTableWidget::ScriptsTableWidget(QWidget* parent) : - QTableWidget(parent) { - verticalHeader()->setVisible(false); - horizontalHeader()->setVisible(false); - setShowGrid(false); - setSelectionMode(QAbstractItemView::NoSelection); - setEditTriggers(QAbstractItemView::NoEditTriggers); - setStyleSheet("QTableWidget { border: none; background: transparent; color: #333333; } QToolTip { color: #000000; background: #f9f6e4; padding: 2px; }"); - setToolTipDuration(200); - setWordWrap(true); - setGeometry(0, 0, parent->width(), parent->height()); -} - -void ScriptsTableWidget::paintEvent(QPaintEvent* event) { - QPainter painter(viewport()); - painter.setPen(QColor::fromRgb(225, 225, 225)); // #e1e1e1 - - int y = 0; - for (int i = 0; i < rowCount(); i++) { - painter.drawLine(5, rowHeight(i) + y, width(), rowHeight(i) + y); - y += rowHeight(i); - } - painter.end(); - - QTableWidget::paintEvent(event); -} - -void ScriptsTableWidget::keyPressEvent(QKeyEvent* event) { - // Ignore keys so they will propagate correctly - event->ignore(); -} diff --git a/interface/src/ui/ScriptsTableWidget.h b/interface/src/ui/ScriptsTableWidget.h deleted file mode 100644 index f5e3407e97..0000000000 --- a/interface/src/ui/ScriptsTableWidget.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// ScriptsTableWidget.h -// interface -// -// Created by Mohammed Nafees on 04/03/2014. -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi__ScriptsTableWidget_h -#define hifi__ScriptsTableWidget_h - -#include -#include - -class ScriptsTableWidget : public QTableWidget { - Q_OBJECT -public: - explicit ScriptsTableWidget(QWidget* parent); - -protected: - virtual void paintEvent(QPaintEvent* event) override; - virtual void keyPressEvent(QKeyEvent* event) override; -}; - -#endif // hifi__ScriptsTableWidget_h diff --git a/interface/ui/scriptEditorWidget.ui b/interface/ui/scriptEditorWidget.ui deleted file mode 100644 index e2e538a595..0000000000 --- a/interface/ui/scriptEditorWidget.ui +++ /dev/null @@ -1,142 +0,0 @@ - - - ScriptEditorWidget - - - - 0 - 0 - 691 - 549 - - - - - 0 - 0 - - - - - 690 - 328 - - - - font-family: Helvetica, Arial, sans-serif; - - - QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - - - Qt::NoDockWidgetArea - - - Edit Script - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Courier - -1 - 50 - false - false - - - - font: 16px "Courier"; - - - - - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - font: 13px "Helvetica","Arial","sans-serif"; - - - Debug Log: - - - - - - - - Helvetica,Arial,sans-serif - -1 - 50 - false - false - - - - font: 13px "Helvetica","Arial","sans-serif"; - - - Run on the fly (Careful: Any valid change made to the code will run immediately) - - - - - - - Clear - - - - 16 - 16 - - - - - - - - - - - - ScriptEditBox - QTextEdit -
ui/ScriptEditBox.h
-
-
- -
diff --git a/interface/ui/scriptEditorWindow.ui b/interface/ui/scriptEditorWindow.ui deleted file mode 100644 index 1e50aaef0b..0000000000 --- a/interface/ui/scriptEditorWindow.ui +++ /dev/null @@ -1,324 +0,0 @@ - - - ScriptEditorWindow - - - Qt::NonModal - - - - 0 - 0 - 780 - 717 - - - - - 400 - 250 - - - - Script Editor - - - font-family: Helvetica, Arial, sans-serif; - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 3 - - - QLayout::SetNoConstraint - - - 0 - - - 0 - - - - - New Script (Ctrl+N) - - - New - - - - 32 - 32 - - - - - - - - - 30 - 0 - - - - - 25 - 0 - - - - Load Script (Ctrl+O) - - - Load - - - - 32 - 32 - - - - false - - - QToolButton::MenuButtonPopup - - - Qt::ToolButtonIconOnly - - - - - - - - 30 - 0 - - - - - 32 - 0 - - - - Qt::NoFocus - - - Qt::NoContextMenu - - - Save Script (Ctrl+S) - - - Save - - - - 32 - 32 - - - - 316 - - - QToolButton::MenuButtonPopup - - - - - - - Toggle Run Script (F5) - - - Run/Stop - - - - 32 - 32 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - font: 13px "Helvetica","Arial","sans-serif"; - - - Automatically reload externally changed files - - - - - - - - - true - - - - 250 - 80 - - - - QTabWidget::West - - - QTabWidget::Triangular - - - -1 - - - Qt::ElideNone - - - true - - - true - - - - - - - - - saveButton - clicked() - ScriptEditorWindow - saveScriptClicked() - - - 236 - 10 - - - 199 - 264 - - - - - toggleRunButton - clicked() - ScriptEditorWindow - toggleRunScriptClicked() - - - 330 - 10 - - - 199 - 264 - - - - - newButton - clicked() - ScriptEditorWindow - newScriptClicked() - - - 58 - 10 - - - 199 - 264 - - - - - loadButton - clicked() - ScriptEditorWindow - loadScriptClicked() - - - 85 - 10 - - - 199 - 264 - - - - - tabWidget - currentChanged(int) - ScriptEditorWindow - tabSwitched(int) - - - 352 - 360 - - - 352 - 340 - - - - - tabWidget - tabCloseRequested(int) - ScriptEditorWindow - tabCloseRequested(int) - - - 352 - 360 - - - 352 - 340 - - - - - From c46052398071165c2292f50e8963d52b1ed55990 Mon Sep 17 00:00:00 2001 From: Mohammed Nafees Date: Mon, 20 Mar 2017 00:25:32 -0400 Subject: [PATCH 31/33] Remove related icon files for Scripts Editor --- interface/resources/icons/load-script.svg | 125 ---- interface/resources/icons/new-script.svg | 129 ---- interface/resources/icons/save-script.svg | 674 --------------------- interface/resources/icons/start-script.svg | 550 ----------------- interface/resources/icons/stop-script.svg | 163 ----- 5 files changed, 1641 deletions(-) delete mode 100644 interface/resources/icons/load-script.svg delete mode 100644 interface/resources/icons/new-script.svg delete mode 100644 interface/resources/icons/save-script.svg delete mode 100644 interface/resources/icons/start-script.svg delete mode 100644 interface/resources/icons/stop-script.svg diff --git a/interface/resources/icons/load-script.svg b/interface/resources/icons/load-script.svg deleted file mode 100644 index 21be61c321..0000000000 --- a/interface/resources/icons/load-script.svg +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - T.Hofmeister - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/new-script.svg b/interface/resources/icons/new-script.svg deleted file mode 100644 index f68fcfa967..0000000000 --- a/interface/resources/icons/new-script.svg +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - T.Hofmeister - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/save-script.svg b/interface/resources/icons/save-script.svg deleted file mode 100644 index 04d41b8302..0000000000 --- a/interface/resources/icons/save-script.svg +++ /dev/null @@ -1,674 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - T.Hofmeister - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/start-script.svg b/interface/resources/icons/start-script.svg deleted file mode 100644 index 994eb61efe..0000000000 --- a/interface/resources/icons/start-script.svg +++ /dev/null @@ -1,550 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - Maximillian Merlin - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/interface/resources/icons/stop-script.svg b/interface/resources/icons/stop-script.svg deleted file mode 100644 index 31cdcee749..0000000000 --- a/interface/resources/icons/stop-script.svg +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - Maximillian Merlin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 3b8636b75c3df242c0aeecbca6e01f386e238f45 Mon Sep 17 00:00:00 2001 From: trent Date: Mon, 20 Mar 2017 17:55:52 -0400 Subject: [PATCH 32/33] Doubled-ish the size of the physics status icons, fixed texture coordinates to be right-side up. --- libraries/render/src/render/drawItemStatus.slv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/render/src/render/drawItemStatus.slv b/libraries/render/src/render/drawItemStatus.slv index cb4ae7ebd2..792f2733c5 100644 --- a/libraries/render/src/render/drawItemStatus.slv +++ b/libraries/render/src/render/drawItemStatus.slv @@ -75,7 +75,7 @@ void main(void) { vec4(1.0, 1.0, 0.0, 1.0) ); - const vec2 ICON_PIXEL_SIZE = vec2(20, 20); + const vec2 ICON_PIXEL_SIZE = vec2(36, 36); const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2); const vec2 ICON_GRID_SLOTS[MAX_NUM_ICONS] = vec2[MAX_NUM_ICONS](vec2(-1.5, 0.5), vec2(-0.5, 0.5), @@ -114,7 +114,7 @@ void main(void) { varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0); // Pass the texcoord and the z texcoord is representing the texture icon - varTexcoord = vec3((quadPos.xy + 1.0) * 0.5, iconStatus.z); + varTexcoord = vec3( (quadPos.x + 1.0) * 0.5, (quadPos.y + 1.0) * -0.5, iconStatus.z); // Also changes the size of the notification vec2 iconScale = ICON_PIXEL_SIZE; From 73dd2abdafdfc8cc71fa843b3b7ef31f5c44717a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 20 Mar 2017 17:29:44 -0700 Subject: [PATCH 33/33] Delete old sitting points code --- .../entities/src/EntityItemProperties.cpp | 21 -------------- libraries/entities/src/EntityItemProperties.h | 4 --- .../entities/src/EntityScriptingInterface.cpp | 6 ++-- libraries/entities/src/PropertyGroup.h | 29 ++----------------- libraries/fbx/src/FBXReader.cpp | 13 --------- libraries/fbx/src/FBXReader.h | 20 ------------- 6 files changed, 5 insertions(+), 88 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index ea81df3801..1ed020e592 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -49,13 +49,6 @@ EntityItemProperties::EntityItemProperties(EntityPropertyFlags desiredProperties } -void EntityItemProperties::setSittingPoints(const QVector& sittingPoints) { - _sittingPoints.clear(); - foreach (SittingPoint sitPoint, sittingPoints) { - _sittingPoints.append(sitPoint); - } -} - void EntityItemProperties::calculateNaturalPosition(const glm::vec3& min, const glm::vec3& max) { glm::vec3 halfDimension = (max - min) / 2.0f; _naturalPosition = max - halfDimension; @@ -546,20 +539,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); } - // Sitting properties support - if (!skipDefaults && !strictSemantics) { - 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_ALWAYS(sittingPoints, sittingPoints); // gettable, but not settable - } - if (!skipDefaults && !strictSemantics) { AABox aaBox = getAABox(); QScriptValue boundingBox = engine->newObject(); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 419740e4ea..590298e102 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -22,7 +22,6 @@ #include #include -#include // for SittingPoint #include #include #include @@ -255,8 +254,6 @@ public: void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; } void markAllChanged(); - void setSittingPoints(const QVector& sittingPoints); - const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } @@ -325,7 +322,6 @@ private: // NOTE: The following are pseudo client only properties. They are only used in clients which can access // properties of model geometry. But these properties are not serialized like other properties. - QVector _sittingPoints; QVariantMap _textureNames; glm::vec3 _naturalDimensions; glm::vec3 _naturalPosition; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 91d39e9490..355bef5170 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -292,13 +292,11 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit results = entity->getProperties(desiredProperties); - // TODO: improve sitting points and naturalDimensions in the future, - // for now we've included the old sitting points model behavior for entity types that are models - // we've also added this hack for setting natural dimensions of models + // TODO: improve naturalDimensions in the future, + // for now we've added this hack for setting natural dimensions of models if (entity->getType() == EntityTypes::Model) { const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity); if (geometry) { - results.setSittingPoints(geometry->sittingPoints); Extents meshExtents = geometry->getUnscaledMeshExtents(); results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); results.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum); diff --git a/libraries/entities/src/PropertyGroup.h b/libraries/entities/src/PropertyGroup.h index 38b1e5f599..f45d19f5eb 100644 --- a/libraries/entities/src/PropertyGroup.h +++ b/libraries/entities/src/PropertyGroup.h @@ -14,9 +14,11 @@ #include -//#include "EntityItemProperties.h" +#include + #include "EntityPropertyFlags.h" + class EntityItemProperties; class EncodeBitstreamParams; class OctreePacketData; @@ -24,31 +26,6 @@ class EntityTreeElementExtraEncodeData; class ReadBitstreamToTreeParams; using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr; -#include - -/* -#include - -#include -#include - -#include -#include -#include - -#include -#include // for SittingPoint -#include -#include -#include - -#include "EntityItemID.h" -#include "PropertyGroupMacros.h" -#include "EntityTypes.h" -*/ - -//typedef PropertyFlags EntityPropertyFlags; - class PropertyGroup { public: diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index fcaef90527..b9e1edc168 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1795,19 +1795,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString()); - // Add sitting points - QVariantHash sittingPoints = mapping.value("sit").toHash(); - for (QVariantHash::const_iterator it = sittingPoints.constBegin(); it != sittingPoints.constEnd(); it++) { - SittingPoint sittingPoint; - sittingPoint.name = it.key(); - - QVariantList properties = it->toList(); - sittingPoint.position = parseVec3(properties.at(0).toString()); - sittingPoint.rotation = glm::quat(glm::radians(parseVec3(properties.at(1).toString()))); - - geometry.sittingPoints.append(sittingPoint); - } - // attempt to map any meshes to a named model for (QHash::const_iterator m = meshIDsToMeshIndices.constBegin(); m != meshIDsToMeshIndices.constEnd(); m++) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 6e51c413dc..fa047e512f 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -265,24 +265,6 @@ public: Q_DECLARE_METATYPE(FBXAnimationFrame) Q_DECLARE_METATYPE(QVector) -/// A point where an avatar can sit -class SittingPoint { -public: - QString name; - glm::vec3 position; // relative postion - glm::quat rotation; // relative orientation -}; - -inline bool operator==(const SittingPoint& lhs, const SittingPoint& rhs) -{ - return (lhs.name == rhs.name) && (lhs.position == rhs.position) && (lhs.rotation == rhs.rotation); -} - -inline bool operator!=(const SittingPoint& lhs, const SittingPoint& rhs) -{ - return (lhs.name != rhs.name) || (lhs.position != rhs.position) || (lhs.rotation != rhs.rotation); -} - /// A set of meshes extracted from an FBX document. class FBXGeometry { public: @@ -320,8 +302,6 @@ public: glm::vec3 palmDirection; - QVector sittingPoints; - glm::vec3 neckPivot; Extents bindExtents;