From 08d63b7fd89839c1b34ccf5ff44fac70f1480800 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 11:03:02 -0700 Subject: [PATCH 01/25] first attempt at palm rotation --- interface/src/avatar/AvatarActionHold.cpp | 4 ++++ interface/src/avatar/MyAvatar.cpp | 26 +++++++++++++++++++++++ interface/src/avatar/MyAvatar.h | 6 ++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ca903a9771..c28032ddde 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -52,15 +52,19 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } glm::vec3 palmPosition; + glm::quat palmRotation; if (_hand == "right") { palmPosition = myAvatar->getRightPalmPosition(); + palmRotation = myAvatar->getRightPalmRotation(); } else { palmPosition = myAvatar->getLeftPalmPosition(); + palmRotation = myAvatar->getLeftPalmRotation(); } auto rotation = myAvatar->getWorldAlignedOrientation(); auto offset = rotation * _relativePosition; auto position = palmPosition + offset; + rotation *= palmRotation; rotation *= _relativeRotation; unlock(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aa6b6afc66..1a900d6afd 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -371,6 +371,19 @@ glm::vec3 MyAvatar::getLeftPalmPosition() { return leftHandPosition; } +glm::quat MyAvatar::getLeftPalmRotation() { + unsigned int leftIndex = 0; + if (getHand()->getNumPalms() > leftIndex) { + PalmData& palm = getHand()->getPalms()[leftIndex]; + if (palm.isActive()) { + glm::vec3 tipDirection = glm::normalize(palm.getTipPosition() - palm.getPosition()); + glm::vec3 avatarDirection = glm::vec3(0.0f, 0.0f, 1.0f) * getOrientation(); + return rotationBetween(avatarDirection, tipDirection); + } + } + return glm::quat(); +} + glm::vec3 MyAvatar::getRightPalmPosition() { glm::vec3 rightHandPosition; getSkeletonModel().getRightHandPosition(rightHandPosition); @@ -380,6 +393,19 @@ glm::vec3 MyAvatar::getRightPalmPosition() { return rightHandPosition; } +glm::quat MyAvatar::getRightPalmRotation() { + unsigned int rightIndex = 1; + if (getHand()->getNumPalms() > rightIndex) { + PalmData& palm = getHand()->getPalms()[rightIndex]; + if (palm.isActive()) { + glm::vec3 tipDirection = glm::normalize(palm.getTipPosition() - palm.getPosition()); + glm::vec3 avatarDirection = glm::vec3(0.0f, 0.0f, 1.0f) * getOrientation(); + return rotationBetween(avatarDirection, tipDirection); + } + } + return glm::quat(); +} + void MyAvatar::clearReferential() { changeReferential(NULL); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4e76143774..34dfcad2ad 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -195,10 +195,12 @@ public slots: void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void updateMotionBehavior(); - + glm::vec3 getLeftPalmPosition(); + glm::quat getLeftPalmRotation(); glm::vec3 getRightPalmPosition(); - + glm::quat getRightPalmRotation(); + void clearReferential(); bool setModelReferential(const QUuid& id); bool setJointReferential(const QUuid& id, int jointIndex); From d197bf2a8519d69bf90ae8f1f6d6975197afa576 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 12:18:32 -0700 Subject: [PATCH 02/25] use palm rotation data in hold action --- examples/stick-hydra.js | 73 +++++++++++++++++++++++ interface/src/avatar/AvatarActionHold.cpp | 4 +- interface/src/avatar/MyAvatar.cpp | 26 ++------ 3 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 examples/stick-hydra.js diff --git a/examples/stick-hydra.js b/examples/stick-hydra.js new file mode 100644 index 0000000000..42ac6c6cda --- /dev/null +++ b/examples/stick-hydra.js @@ -0,0 +1,73 @@ +// stick.js +// examples +// +// Created by Seth Alves on 2015-6-10 +// Copyright 2015 High Fidelity, Inc. +// +// Allow avatar to hold a stick +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var hand = "left"; +var nullActionID = "00000000-0000-0000-0000-000000000000"; +var controllerID; +var controllerActive; +var stickID = null; +var actionID = nullActionID; +var makingNewStick = false; + +function makeNewStick() { + if (makingNewStick) { + return; + } + makingNewStick = true; + cleanUp(); + // sometimes if this is run immediately the stick doesn't get created? use a timer. + Script.setTimeout(function() { + stickID = Entities.addEntity({ + type: "Model", + name: "stick", + modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx", + compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj", + dimensions: {x: .11, y: .11, z: 1.0}, + position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close + rotation: MyAvatar.orientation, + damping: .1, + collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/67LCollision07.wav", + restitution: 0.01, + collisionsWillMove: true + }); + actionID = Entities.addAction("hold", stickID, + {relativePosition: {x: 0.0, y: 0.0, z: -0.5}, + relativeRotation: Quat.fromVec3Degrees({x: 0.0, y: 90.0, z: 0.0}), + hand: hand, + timeScale: 0.15}); + if (actionID == nullActionID) { + cleanUp(); + } + makingNewStick = false; + }, 3000); +} + + +function cleanUp() { + if (stickID) { + Entities.deleteEntity(stickID); + stickID = null; + } +} + + +function initControls(){ + if (hand == "right") { + controllerID = 3; // right handed + } else { + controllerID = 4; // left handed + } +} + + +Script.scriptEnding.connect(cleanUp); +makeNewStick(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index c28032ddde..97d679f94b 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -61,11 +61,9 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = myAvatar->getLeftPalmRotation(); } - auto rotation = myAvatar->getWorldAlignedOrientation(); + auto rotation = palmRotation * _relativeRotation; auto offset = rotation * _relativePosition; auto position = palmPosition + offset; - rotation *= palmRotation; - rotation *= _relativeRotation; unlock(); if (!tryLockForWrite()) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1a900d6afd..79c600b7ec 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -372,16 +372,9 @@ glm::vec3 MyAvatar::getLeftPalmPosition() { } glm::quat MyAvatar::getLeftPalmRotation() { - unsigned int leftIndex = 0; - if (getHand()->getNumPalms() > leftIndex) { - PalmData& palm = getHand()->getPalms()[leftIndex]; - if (palm.isActive()) { - glm::vec3 tipDirection = glm::normalize(palm.getTipPosition() - palm.getPosition()); - glm::vec3 avatarDirection = glm::vec3(0.0f, 0.0f, 1.0f) * getOrientation(); - return rotationBetween(avatarDirection, tipDirection); - } - } - return glm::quat(); + glm::quat leftRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation); + return leftRotation; } glm::vec3 MyAvatar::getRightPalmPosition() { @@ -394,16 +387,9 @@ glm::vec3 MyAvatar::getRightPalmPosition() { } glm::quat MyAvatar::getRightPalmRotation() { - unsigned int rightIndex = 1; - if (getHand()->getNumPalms() > rightIndex) { - PalmData& palm = getHand()->getPalms()[rightIndex]; - if (palm.isActive()) { - glm::vec3 tipDirection = glm::normalize(palm.getTipPosition() - palm.getPosition()); - glm::vec3 avatarDirection = glm::vec3(0.0f, 0.0f, 1.0f) * getOrientation(); - return rotationBetween(avatarDirection, tipDirection); - } - } - return glm::quat(); + glm::quat rightRotation; + getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); + return rightRotation; } void MyAvatar::clearReferential() { From 85f206d49d36e6ab7d13355c3e8b3b938f430c56 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 14:13:01 -0700 Subject: [PATCH 03/25] if an action is updating its own arguments, cause updates to go out over network --- 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 8d77f815b7..b06c6f264b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -287,6 +287,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { } if (_serverActionData != _entity->getActionData()) { + setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); return true; } From 25708678f6eed2ed69b6dbaaac358fb30bb0b0e0 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Thu, 9 Jul 2015 14:18:53 -0700 Subject: [PATCH 04/25] Fixed shutdown procedure for Datagrams so that there is no crash on exit --- interface/src/DatagramProcessor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index f691527186..99308a922f 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -29,12 +29,13 @@ DatagramProcessor::DatagramProcessor(QObject* parent) : } void DatagramProcessor::processDatagrams() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "DatagramProcessor::processDatagrams()"); if (_isShuttingDown) { return; // bail early... we're shutting down. } + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "DatagramProcessor::processDatagrams()"); + HifiSockAddr senderSockAddr; From 85f6fdb8cfedd09f73fc66de9223df983b8c1de2 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Thu, 9 Jul 2015 14:20:10 -0700 Subject: [PATCH 05/25] Fixed bug which would cause program to crash if there was no image associated with an overlay in windows build (see checkbox in sunLightExample) --- interface/src/ui/overlays/ImageOverlay.cpp | 67 +++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 399e8a459a..e80c6f584b 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -75,46 +75,49 @@ void ImageOverlay::render(RenderArgs* args) { glm::vec2 topLeft(left, top); glm::vec2 bottomRight(right, bottom); - float imageWidth = _texture->getWidth(); - float imageHeight = _texture->getHeight(); + // if for some reason our image is not over 0 width or height, don't attempt to render the image - if (_renderImage && imageWidth > 0 && imageHeight > 0) { + if (_renderImage) { + float imageWidth = _texture->getWidth(); + float imageHeight = _texture->getHeight(); + if (imageWidth > 0 && imageHeight > 0) { + QRect fromImage; + if (_wantClipFromImage) { + float scaleX = imageWidth / _texture->getOriginalWidth(); + float scaleY = imageHeight / _texture->getOriginalHeight(); - QRect fromImage; - if (_wantClipFromImage) { - float scaleX = imageWidth / _texture->getOriginalWidth(); - float scaleY = imageHeight / _texture->getOriginalHeight(); + fromImage.setX(scaleX * _fromImage.x()); + fromImage.setY(scaleY * _fromImage.y()); + fromImage.setWidth(scaleX * _fromImage.width()); + fromImage.setHeight(scaleY * _fromImage.height()); + } + else { + fromImage.setX(0); + fromImage.setY(0); + fromImage.setWidth(imageWidth); + fromImage.setHeight(imageHeight); + } - fromImage.setX(scaleX * _fromImage.x()); - fromImage.setY(scaleY * _fromImage.y()); - fromImage.setWidth(scaleX * _fromImage.width()); - fromImage.setHeight(scaleY * _fromImage.height()); - } else { - fromImage.setX(0); - fromImage.setY(0); - fromImage.setWidth(imageWidth); - fromImage.setHeight(imageHeight); + float x = fromImage.x() / imageWidth; + float y = fromImage.y() / imageHeight; + float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure + float h = fromImage.height() / imageHeight; + + glm::vec2 texCoordTopLeft(x, y); + glm::vec2 texCoordBottomRight(x + w, y + h); + + DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); + } + else { + DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); } - float x = fromImage.x() / imageWidth; - float y = fromImage.y() / imageHeight; - float w = fromImage.width() / imageWidth; // ?? is this what we want? not sure - float h = fromImage.height() / imageHeight; - - glm::vec2 texCoordTopLeft(x, y); - glm::vec2 texCoordBottomRight(x + w, y + h); - - DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); - } else { - DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); - } - - if (_renderImage) { - glDisable(GL_TEXTURE_2D); + if (_renderImage) { + glDisable(GL_TEXTURE_2D); + } } } - void ImageOverlay::setProperties(const QScriptValue& properties) { Overlay2D::setProperties(properties); From a01fb6f1dc89712df6fd03aedc3323242257987b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 14:32:34 -0700 Subject: [PATCH 06/25] if an action changes its own arguments, cause reserialisation --- interface/src/avatar/AvatarActionHold.cpp | 4 ++++ libraries/entities/src/EntityItem.cpp | 8 ++++++++ libraries/entities/src/EntityItem.h | 2 ++ 3 files changed, 14 insertions(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 97d679f94b..cdb59ebb96 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -147,6 +147,10 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { _rotationalTargetSet = true; _active = true; unlock(); + auto ownerEntity = _ownerEntity.lock(); + if (ownerEntity) { + ownerEntity->setActionDataDirty(true); + } return true; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1165518097..3aeaf4829f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1714,6 +1714,14 @@ QByteArray EntityItem::serializeActions(bool& success) const { } const QByteArray EntityItem::getActionData() const { + if (_actionDataDirty) { + bool success; + QByteArray newDataCache = serializeActions(success); + if (success) { + _allActionsDataCache = newDataCache; + } + _actionDataDirty = false; + } return _allActionsDataCache; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bc8901c6b1..7893818267 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -395,6 +395,7 @@ public: bool hasActions() { return !_objectActions.empty(); } QList getActionIDs() { return _objectActions.keys(); } QVariantMap getActionArguments(const QUuid& actionID) const; + void setActionDataDirty(bool value) const { _actionDataDirty = value; } protected: @@ -482,6 +483,7 @@ protected: void checkWaitingToRemove(EntitySimulation* simulation = nullptr); mutable QByteArray _waitingActionData; mutable QSet _actionsToRemove; + mutable bool _actionDataDirty = false; }; #endif // hifi_EntityItem_h From 5312beeaf4905e1f99695da2a26c4a8fef26067b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 14:50:31 -0700 Subject: [PATCH 07/25] if an action changes its own arguments, cause reserialisation --- interface/src/avatar/AvatarActionHold.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index cdb59ebb96..72019ecf28 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -89,6 +89,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { _rotationalTarget = rotation; unlock(); + auto ownerEntity = _ownerEntity.lock(); + if (ownerEntity) { + ownerEntity->setActionDataDirty(true); + } + ObjectActionSpring::updateActionWorker(deltaTimeStep); } From 2dc4922da35f9d5674caf15169c498bfae4fdce1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 15:23:05 -0700 Subject: [PATCH 08/25] bring over code from entity-level-locking branch --- .../src/AssignmentActionFactory.cpp | 7 +- .../src/AssignmentActionFactory.h | 7 +- interface/src/InterfaceActionFactory.cpp | 7 +- interface/src/InterfaceActionFactory.h | 6 +- interface/src/avatar/AvatarActionHold.cpp | 16 +- .../src/EntityActionFactoryInterface.h | 6 +- libraries/entities/src/EntityItem.cpp | 272 ++++++++++++------ libraries/entities/src/EntityItem.h | 39 ++- .../entities/src/EntityScriptingInterface.cpp | 2 +- libraries/entities/src/EntitySimulation.cpp | 1 + 10 files changed, 243 insertions(+), 120 deletions(-) diff --git a/assignment-client/src/AssignmentActionFactory.cpp b/assignment-client/src/AssignmentActionFactory.cpp index e1c5d3adff..7c404cbd97 100644 --- a/assignment-client/src/AssignmentActionFactory.cpp +++ b/assignment-client/src/AssignmentActionFactory.cpp @@ -17,8 +17,7 @@ EntityActionPointer assignmentActionFactory(EntityActionType type, const QUuid& } -EntityActionPointer AssignmentActionFactory::factory(EntitySimulation* simulation, - EntityActionType type, +EntityActionPointer AssignmentActionFactory::factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { @@ -33,9 +32,7 @@ EntityActionPointer AssignmentActionFactory::factory(EntitySimulation* simulatio } -EntityActionPointer AssignmentActionFactory::factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data) { +EntityActionPointer AssignmentActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) { QDataStream serializedActionDataStream(data); EntityActionType type; QUuid id; diff --git a/assignment-client/src/AssignmentActionFactory.h b/assignment-client/src/AssignmentActionFactory.h index 41245dac68..e2d58f3e6a 100644 --- a/assignment-client/src/AssignmentActionFactory.h +++ b/assignment-client/src/AssignmentActionFactory.h @@ -19,14 +19,11 @@ class AssignmentActionFactory : public EntityActionFactoryInterface { public: AssignmentActionFactory() : EntityActionFactoryInterface() { } virtual ~AssignmentActionFactory() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments); - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data); + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data); }; #endif // hifi_AssignmentActionFactory_h diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 363fb66e76..dca1015ecc 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -35,8 +35,7 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i } -EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation, - EntityActionType type, +EntityActionPointer InterfaceActionFactory::factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { @@ -51,9 +50,7 @@ EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation } -EntityActionPointer InterfaceActionFactory::factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, - QByteArray data) { +EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEntity, QByteArray data) { QDataStream serializedArgumentStream(data); EntityActionType type; QUuid id; diff --git a/interface/src/InterfaceActionFactory.h b/interface/src/InterfaceActionFactory.h index 004c24163f..2031f5c57a 100644 --- a/interface/src/InterfaceActionFactory.h +++ b/interface/src/InterfaceActionFactory.h @@ -18,13 +18,11 @@ class InterfaceActionFactory : public EntityActionFactoryInterface { public: InterfaceActionFactory() : EntityActionFactoryInterface() { } virtual ~InterfaceActionFactory() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments); - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data); }; diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 72019ecf28..ba37112fe1 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -85,15 +85,17 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { return; } + if (_positionalTarget != position || _rotationalTarget != rotation) { + auto ownerEntity = _ownerEntity.lock(); + if (ownerEntity) { + ownerEntity->setActionDataDirty(true); + } + } + _positionalTarget = position; _rotationalTarget = rotation; unlock(); - auto ownerEntity = _ownerEntity.lock(); - if (ownerEntity) { - ownerEntity->setActionDataDirty(true); - } - ObjectActionSpring::updateActionWorker(deltaTimeStep); } @@ -152,10 +154,6 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { _rotationalTargetSet = true; _active = true; unlock(); - auto ownerEntity = _ownerEntity.lock(); - if (ownerEntity) { - ownerEntity->setActionDataDirty(true); - } return true; } diff --git a/libraries/entities/src/EntityActionFactoryInterface.h b/libraries/entities/src/EntityActionFactoryInterface.h index 9f4056cdff..adff1a53ba 100644 --- a/libraries/entities/src/EntityActionFactoryInterface.h +++ b/libraries/entities/src/EntityActionFactoryInterface.h @@ -23,13 +23,11 @@ class EntityActionFactoryInterface : public QObject, public Dependency { public: EntityActionFactoryInterface() { } virtual ~EntityActionFactoryInterface() { } - virtual EntityActionPointer factory(EntitySimulation* simulation, - EntityActionType type, + virtual EntityActionPointer factory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity, QVariantMap arguments) { assert(false); return nullptr; } - virtual EntityActionPointer factoryBA(EntitySimulation* simulation, - EntityItemPointer ownerEntity, + virtual EntityActionPointer factoryBA(EntityItemPointer ownerEntity, QByteArray data) { assert(false); return nullptr; } }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3aeaf4829f..e408ce3afa 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1489,20 +1489,22 @@ void EntityItem::clearSimulationOwnership() { } + bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer action) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false; - } bool result = addActionInternal(simulation, action); if (!result) { removeAction(simulation, action->getID()); } + + unlock(); return result; } bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPointer action) { + assertLocked(); assert(action); assert(simulation); auto actionOwnerEntity = action->getOwnerEntity().lock(); @@ -1523,36 +1525,37 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi } bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionID, const QVariantMap& arguments) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false; - } if (!_objectActions.contains(actionID)) { + unlock(); return false; } EntityActionPointer action = _objectActions[actionID]; - bool success = action->updateArguments(arguments); + bool success = action->updateArguments(arguments); if (success) { _allActionsDataCache = serializeActions(success); } else { qDebug() << "EntityItem::updateAction failed"; } + unlock(); return success; } bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionID) { + lockForWrite(); checkWaitingToRemove(simulation); - if (!checkWaitingActionData(simulation)) { - return false;; - } - return removeActionInternal(actionID); + bool success = removeActionInternal(actionID); + unlock(); + return success; } bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) { + assertWriteLocked(); if (_objectActions.contains(actionID)) { if (!simulation) { EntityTree* entityTree = _element ? _element->getTree() : nullptr; @@ -1575,7 +1578,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s } bool EntityItem::clearActions(EntitySimulation* simulation) { - _waitingActionData.clear(); + lockForWrite(); QHash::iterator i = _objectActions.begin(); while (i != _objectActions.end()) { const QUuid id = i.key(); @@ -1584,85 +1587,84 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { action->setOwnerEntity(nullptr); action->removeFromSimulation(simulation); } + // empty _serializedActions means no actions for the EntityItem _actionsToRemove.clear(); _allActionsDataCache.clear(); + unlock(); return true; } -bool EntityItem::deserializeActions(QByteArray allActionsData, EntitySimulation* simulation) const { - bool success = true; - QVector serializedActions; - if (allActionsData.size() > 0) { - QDataStream serializedActionsStream(allActionsData); - serializedActionsStream >> serializedActions; + +void EntityItem::deserializeActions() { + assertUnlocked(); + lockForWrite(); + deserializeActionsInternal(); + unlock(); +} + + +void EntityItem::deserializeActionsInternal() { + assertWriteLocked(); + + if (!_element) { + return; } // Keep track of which actions got added or updated by the new actionData - QSet updated; EntityTree* entityTree = _element ? _element->getTree() : nullptr; - if (!simulation) { - simulation = entityTree ? entityTree->getSimulation() : nullptr; + assert(entityTree); + EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; + assert(simulation); + + QVector serializedActions; + if (_allActionsDataCache.size() > 0) { + QDataStream serializedActionsStream(_allActionsDataCache); + serializedActionsStream >> serializedActions; } - if (simulation && entityTree) { - foreach(QByteArray serializedAction, serializedActions) { - QDataStream serializedActionStream(serializedAction); - EntityActionType actionType; - QUuid actionID; - serializedActionStream >> actionType; - serializedActionStream >> actionID; - updated << actionID; + QSet updated; - if (_objectActions.contains(actionID)) { - EntityActionPointer action = _objectActions[actionID]; - // TODO: make sure types match? there isn't currently a way to - // change the type of an existing action. - action->deserialize(serializedAction); - } else { - auto actionFactory = DependencyManager::get(); - if (simulation) { - EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id); - EntityActionPointer action = actionFactory->factoryBA(simulation, entity, serializedAction); - if (action) { - entity->addActionInternal(simulation, action); - } - } else { - // we can't yet add the action. This method will be called later. - success = false; - } + foreach(QByteArray serializedAction, serializedActions) { + QDataStream serializedActionStream(serializedAction); + EntityActionType actionType; + QUuid actionID; + serializedActionStream >> actionType; + serializedActionStream >> actionID; + updated << actionID; + + if (_objectActions.contains(actionID)) { + EntityActionPointer action = _objectActions[actionID]; + // TODO: make sure types match? there isn't currently a way to + // change the type of an existing action. + action->deserialize(serializedAction); + } else { + auto actionFactory = DependencyManager::get(); + + // EntityItemPointer entity = entityTree->findEntityByEntityItemID(_id, false); + EntityItemPointer entity = shared_from_this(); + EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); + if (action) { + entity->addActionInternal(simulation, action); } } + } - // remove any actions that weren't included in the new data. - QHash::const_iterator i = _objectActions.begin(); - while (i != _objectActions.end()) { - const QUuid id = i.key(); - if (!updated.contains(id)) { - _actionsToRemove << id; - } - i++; + // remove any actions that weren't included in the new data. + QHash::const_iterator i = _objectActions.begin(); + while (i != _objectActions.end()) { + const QUuid id = i.key(); + if (!updated.contains(id)) { + _actionsToRemove << id; } - } else { - // no simulation - success = false; + i++; } - return success; -} - -bool EntityItem::checkWaitingActionData(EntitySimulation* simulation) const { - if (_waitingActionData.size() == 0) { - return true; - } - bool success = deserializeActions(_waitingActionData, simulation); - if (success) { - _waitingActionData.clear(); - } - return success; + return; } void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { + assertLocked(); foreach(QUuid actionID, _actionsToRemove) { removeActionInternal(actionID, simulation); } @@ -1670,21 +1672,22 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { + assertUnlocked(); + lockForWrite(); + setActionDataInternal(actionData); + unlock(); +} + +void EntityItem::setActionDataInternal(QByteArray actionData) { + assertWriteLocked(); checkWaitingToRemove(); - bool success = deserializeActions(actionData); _allActionsDataCache = actionData; - if (success) { - _waitingActionData.clear(); - } else { - _waitingActionData = actionData; - } + deserializeActionsInternal(); } QByteArray EntityItem::serializeActions(bool& success) const { + assertLocked(); QByteArray result; - if (!checkWaitingActionData()) { - return _waitingActionData; - } if (_objectActions.size() == 0) { success = true; @@ -1713,7 +1716,7 @@ QByteArray EntityItem::serializeActions(bool& success) const { return result; } -const QByteArray EntityItem::getActionData() const { +const QByteArray EntityItem::getActionDataInternal() const { if (_actionDataDirty) { bool success; QByteArray newDataCache = serializeActions(success); @@ -1725,17 +1728,120 @@ const QByteArray EntityItem::getActionData() const { return _allActionsDataCache; } +const QByteArray EntityItem::getActionData() const { + assertUnlocked(); + lockForRead(); + auto result = getActionDataInternal(); + unlock(); + return result; +} + QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const { QVariantMap result; - - if (!checkWaitingActionData()) { - return result; - } + lockForRead(); if (_objectActions.contains(actionID)) { EntityActionPointer action = _objectActions[actionID]; result = action->getArguments(); result["type"] = EntityActionInterface::actionTypeToString(action->getType()); } + unlock(); return result; } + + + +#define ENABLE_LOCKING 1 + +#ifdef ENABLE_LOCKING +void EntityItem::lockForRead() const { + _lock.lockForRead(); +} + +bool EntityItem::tryLockForRead() const { + return _lock.tryLockForRead(); +} + +void EntityItem::lockForWrite() const { + _lock.lockForWrite(); +} + +bool EntityItem::tryLockForWrite() const { + return _lock.tryLockForWrite(); +} + +void EntityItem::unlock() const { + _lock.unlock(); +} + +bool EntityItem::isLocked() const { + bool readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + } + bool writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + } + if (readSuccess && writeSuccess) { + return false; // if we can take both kinds of lock, there was no previous lock + } + return true; // either read or write failed, so there is some lock in place. +} + + +bool EntityItem::isWriteLocked() const { + bool readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + return false; + } + bool writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + return false; + } + return true; // either read or write failed, so there is some lock in place. +} + + +bool EntityItem::isUnlocked() const { + // this can't be sure -- this may get unlucky and hit locks from other threads. what we're actually trying + // to discover is if *this* thread hasn't locked the EntityItem. Try repeatedly to take both kinds of lock. + bool readSuccess = false; + for (int i=0; i<80; i++) { + readSuccess = tryLockForRead(); + if (readSuccess) { + unlock(); + break; + } + QThread::usleep(200); + } + + bool writeSuccess = false; + if (readSuccess) { + for (int i=0; i<80; i++) { + writeSuccess = tryLockForWrite(); + if (writeSuccess) { + unlock(); + break; + } + QThread::usleep(300); + } + } + + if (readSuccess && writeSuccess) { + return true; // if we can take both kinds of lock, there was no previous lock + } + return false; +} +#else +void EntityItem::lockForRead() const { } +bool EntityItem::tryLockForRead() const { return true; } +void EntityItem::lockForWrite() const { } +bool EntityItem::tryLockForWrite() const { return true; } +void EntityItem::unlock() const { } +bool EntityItem::isLocked() const { return true; } +bool EntityItem::isWriteLocked() const { return true; } +bool EntityItem::isUnlocked() const { return true; } +#endif diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7893818267..de431446e8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -68,10 +68,28 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" +#if DEBUG + #define assertLocked() assert(isLocked()) +#else + #define assertLocked() +#endif + +#if DEBUG + #define assertWriteLocked() assert(isWriteLocked()) +#else + #define assertWriteLocked() +#endif + +#if DEBUG + #define assertUnlocked() assert(isUnlocked()) +#else + #define assertUnlocked() +#endif + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem { +class EntityItem : public std::enable_shared_from_this { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -395,10 +413,14 @@ public: bool hasActions() { return !_objectActions.empty(); } QList getActionIDs() { return _objectActions.keys(); } QVariantMap getActionArguments(const QUuid& actionID) const; + void deserializeActions(); void setActionDataDirty(bool value) const { _actionDataDirty = value; } protected: + const QByteArray getActionDataInternal() const; + void setActionDataInternal(QByteArray actionData); + static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; QUuid _id; @@ -471,19 +493,28 @@ protected: bool addActionInternal(EntitySimulation* simulation, EntityActionPointer action); bool removeActionInternal(const QUuid& actionID, EntitySimulation* simulation = nullptr); - bool deserializeActions(QByteArray allActionsData, EntitySimulation* simulation = nullptr) const; + void deserializeActionsInternal(); QByteArray serializeActions(bool& success) const; QHash _objectActions; + static int _maxActionsDataSize; mutable QByteArray _allActionsDataCache; // when an entity-server starts up, EntityItem::setActionData is called before the entity-tree is // ready. This means we can't find our EntityItemPointer or add the action to the simulation. These // are used to keep track of and work around this situation. - bool checkWaitingActionData(EntitySimulation* simulation = nullptr) const; void checkWaitingToRemove(EntitySimulation* simulation = nullptr); - mutable QByteArray _waitingActionData; mutable QSet _actionsToRemove; mutable bool _actionDataDirty = false; + + mutable QReadWriteLock _lock; + void lockForRead() const; + bool tryLockForRead() const; + void lockForWrite() const; + bool tryLockForWrite() const; + void unlock() const; + bool isLocked() const; + bool isWriteLocked() const; + bool isUnlocked() const; }; #endif // hifi_EntityItem_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7cc2c03dfc..f1c6157694 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -574,7 +574,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, if (actionType == ACTION_TYPE_NONE) { return false; } - EntityActionPointer action = actionFactory->factory(simulation, actionType, actionID, entity, arguments); + EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); if (action) { entity->addAction(simulation, action); auto nodeList = DependencyManager::get(); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index a2d20fe5d5..f2bd1e873e 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -146,6 +146,7 @@ void EntitySimulation::sortEntitiesThatMoved() { void EntitySimulation::addEntity(EntityItemPointer entity) { assert(entity); + entity->deserializeActions(); if (entity->isMortal()) { _mortalEntities.insert(entity); quint64 expiry = entity->getExpiry(); From 99c563602f34349614b409e7b96e6663213485d6 Mon Sep 17 00:00:00 2001 From: Bing Shearer Date: Thu, 9 Jul 2015 15:25:37 -0700 Subject: [PATCH 09/25] Fixed Else case where _renderImage is true but the texture has 0 size, else case did not previously exist. --- interface/src/ui/overlays/ImageOverlay.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index e80c6f584b..7a0c3c00c3 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -75,8 +75,6 @@ void ImageOverlay::render(RenderArgs* args) { glm::vec2 topLeft(left, top); glm::vec2 bottomRight(right, bottom); - - // if for some reason our image is not over 0 width or height, don't attempt to render the image if (_renderImage) { float imageWidth = _texture->getWidth(); @@ -108,16 +106,15 @@ void ImageOverlay::render(RenderArgs* args) { glm::vec2 texCoordBottomRight(x + w, y + h); DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor); - } - else { + } else { DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); } - - if (_renderImage) { - glDisable(GL_TEXTURE_2D); - } + glDisable(GL_TEXTURE_2D); + } else { + DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); } } + void ImageOverlay::setProperties(const QScriptValue& properties) { Overlay2D::setProperties(properties); From fa06f50841b138eb5ad74165505342cee4948a4c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 15:34:03 -0700 Subject: [PATCH 10/25] fix header comment --- examples/stick-hydra.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/stick-hydra.js b/examples/stick-hydra.js index 42ac6c6cda..a74f7954bb 100644 --- a/examples/stick-hydra.js +++ b/examples/stick-hydra.js @@ -1,10 +1,10 @@ -// stick.js +// stick-hydra.js // examples // -// Created by Seth Alves on 2015-6-10 +// Created by Seth Alves on 2015-7-9 // Copyright 2015 High Fidelity, Inc. // -// Allow avatar to hold a stick +// Allow avatar to hold a stick and control it with a hand-tracker // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html From 446f800aeed371fe3eb9a3c96ce4d814b1a6f002 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Jul 2015 15:40:43 -0700 Subject: [PATCH 11/25] More profiling ranges and updated performance testing scripts --- examples/animationPerfTest.js | 81 +++++++++++----------- examples/cubePerfTest.js | 58 ++++++++++++++++ interface/src/Application.cpp | 13 ++-- interface/src/ui/ApplicationCompositor.cpp | 2 + interface/src/ui/ApplicationOverlay.cpp | 4 ++ interface/src/ui/overlays/Overlays.cpp | 1 + 6 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 examples/cubePerfTest.js diff --git a/examples/animationPerfTest.js b/examples/animationPerfTest.js index 6bf310db23..b832d2e61f 100644 --- a/examples/animationPerfTest.js +++ b/examples/animationPerfTest.js @@ -9,9 +9,7 @@ var NUM_MOONS = 20; // 1 = 60Hz, 2 = 30Hz, 3 = 20Hz, etc var UPDATE_FREQUENCY_DIVISOR = 2; - var MAX_RANGE = 75.0; -var LIFETIME = 600; var SCALE = 0.1; var center = Vec3.sum(MyAvatar.position, @@ -22,44 +20,47 @@ var PARTICLE_MIN_SIZE = 2.50; var PARTICLE_MAX_SIZE = 2.50; -var planet = Entities.addEntity({ - type: "Sphere", - position: center, - dimensions: { x: 10 * SCALE, y: 10 * SCALE, z: 10 * SCALE }, - color: { red: 0, green: 0, blue: 255 }, - ignoreCollisions: true, - collisionsWillMove: false, - lifetime: LIFETIME -}); +function deleteAnimationTestEntitites() { + var ids = Entities.findEntities(MyAvatar.position, 50); + for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + if (properties.name == "AnimationTest") { + Entities.deleteEntity(id); + } + } +} + +deleteAnimationTestEntitites(); var moons = []; // Create initial test particles that will move according to gravity from the planets for (var i = 0; i < NUM_MOONS; i++) { - var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE; - radius *= SCALE; - var gray = Math.random() * 155; - var position = { x: 10 , y: i * 3, z: 0 }; - var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; - if (i == 0) { - color = { red: 255, green: 0, blue: 0 }; - radius = 6 * SCALE - } - moons.push(Entities.addEntity({ - type: "Sphere", - position: Vec3.sum(center, position), - dimensions: { x: radius, y: radius, z: radius }, - color: color, - ignoreCollisions: true, - lifetime: LIFETIME, - collisionsWillMove: false - })); + var radius = PARTICLE_MIN_SIZE + Math.random() * PARTICLE_MAX_SIZE; + radius *= SCALE; + var gray = Math.random() * 155; + var position = { x: 10 , y: i * 3, z: 0 }; + var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; + if (i == 0) { + color = { red: 255, green: 0, blue: 0 }; + radius = 6 * SCALE + } + moons.push(Entities.addEntity({ + type: "Sphere", + name: "AnimationTest", + position: Vec3.sum(center, position), + dimensions: { x: radius, y: radius, z: radius }, + color: color, + ignoreCollisions: true, + collisionsWillMove: false + + })); } Script.update.connect(update); function scriptEnding() { - Entities.deleteEntity(planet); for (var i = 0; i < moons.length; i++) { Entities.deleteEntity(moons[i]); } @@ -70,22 +71,20 @@ var updateCount = 0; function update(deltaTime) { // Apply gravitational force from planets totalTime += deltaTime; - updateCount++; - if (0 != updateCount % UPDATE_FREQUENCY_DIVISOR) { - return; - } - - var planetProperties = Entities.getEntityProperties(planet); - var center = planetProperties.position; + updateCount++; + if (0 != updateCount % UPDATE_FREQUENCY_DIVISOR) { + return; + } + var particlePos = Entities.getEntityProperties(moons[0]).position; var relativePos = Vec3.subtract(particlePos.position, center); for (var t = 0; t < moons.length; t++) { - var thetaDelta = (Math.PI * 2.0 / NUM_MOONS) * t; - var y = Math.sin(totalTime + thetaDelta) * 10.0 * SCALE; - var x = Math.cos(totalTime + thetaDelta) * 10.0 * SCALE; + var thetaDelta = (Math.PI * 2.0 / NUM_MOONS) * t; + var y = Math.sin(totalTime + thetaDelta) * 10.0 * SCALE; + var x = Math.cos(totalTime + thetaDelta) * 10.0 * SCALE; var newBasePos = Vec3.sum({ x: 0, y: y, z: x }, center); Entities.editEntity(moons[t], { position: newBasePos}); } } -Script.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(deleteAnimationTestEntitites); diff --git a/examples/cubePerfTest.js b/examples/cubePerfTest.js new file mode 100644 index 0000000000..e349b7add7 --- /dev/null +++ b/examples/cubePerfTest.js @@ -0,0 +1,58 @@ +// +// Created by Bradley Austin Davis on 2015/07/01 +// Copyright 2015 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 +// + +var SIDE_SIZE = 10; + +var center = { x: 0, y: 0, z: 0 }; + +var DEGREES_TO_RADIANS = Math.PI / 180.0; +var PARTICLE_MIN_SIZE = 2.50; +var PARTICLE_MAX_SIZE = 2.50; +var LIFETIME = 600; +var boxes = []; + +var ids = Entities.findEntities({ x: 512, y: 512, z: 512 }, 50); +for (var i = 0; i < ids.length; i++) { + var id = ids[i]; + var properties = Entities.getEntityProperties(id); + if (properties.name == "PerfTest") { + Entities.deleteEntity(id); + } +} + + +// Create initial test particles that will move according to gravity from the planets +for (var x = 0; x < SIDE_SIZE; x++) { + for (var y = 0; y < SIDE_SIZE; y++) { + for (var z = 0; z < SIDE_SIZE; z++) { + var gray = Math.random() * 155; + var cube = Math.random() > 0.5; + var color = { red: 100 + gray, green: 100 + gray, blue: 100 + gray }; + var position = { x: 512 + x * 0.2, y: 512 + y * 0.2, z: 512 + z * 0.2}; + var radius = Math.random() * 0.1; + boxes.push(Entities.addEntity({ + type: cube ? "Box" : "Sphere", + name: "PerfTest", + position: position, + dimensions: { x: radius, y: radius, z: radius }, + color: color, + ignoreCollisions: true, + collisionsWillMove: false, + lifetime: LIFETIME + })); + } + } +} + + +function scriptEnding() { + for (var i = 0; i < boxes.length; i++) { + //Entities.deleteEntity(boxes[i]); + } +} +Script.scriptEnding.connect(scriptEnding); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a30df36159..21acadd3be 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -887,12 +887,6 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); - /* - gpu::Context context(new gpu::GLBackend()); - RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(), - lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, - RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); - */ _applicationOverlay.renderOverlay(&renderArgs); } @@ -968,6 +962,8 @@ void Application::paintGL() { } else if (TV3DManager::isConnected()) { TV3DManager::display(&renderArgs, _myCamera); } else { + PROFILE_RANGE(__function__ "/mainRender"); + DependencyManager::get()->prepare(&renderArgs); // Viewport is assigned to the size of the framebuffer @@ -1002,6 +998,7 @@ void Application::paintGL() { if (!OculusManager::isConnected() || OculusManager::allowSwap()) { + PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); _glWidget->swapBuffers(); } @@ -1051,6 +1048,7 @@ void Application::resetCameras(Camera& camera, const glm::uvec2& size) { } void Application::resizeGL() { + PROFILE_RANGE(__FUNCTION__); // Set the desired FBO texture size. If it hasn't changed, this does nothing. // Otherwise, it must rebuild the FBOs QSize renderSize; @@ -1526,6 +1524,7 @@ void Application::focusOutEvent(QFocusEvent* event) { } void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { + PROFILE_RANGE(__FUNCTION__); // Used by application overlay to determine how to draw cursor(s) _lastMouseMoveWasSimulated = deviceID > 0; if (!_lastMouseMoveWasSimulated) { @@ -1829,6 +1828,7 @@ void Application::idle() { PerformanceTimer perfTimer("update"); PerformanceWarning warn(showWarnings, "Application::idle()... update()"); const float BIGGEST_DELTA_TIME_SECS = 0.25f; + PROFILE_RANGE(__FUNCTION__ "/idleUpdate"); update(glm::clamp((float)timeSinceLastUpdate / 1000.0f, 0.0f, BIGGEST_DELTA_TIME_SECS)); } { @@ -2954,6 +2954,7 @@ QRect Application::getDesirableApplicationGeometry() { // or the "myCamera". // void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { + PROFILE_RANGE(__FUNCTION__); // We will use these below, from either the camera or head vectors calculated above viewFrustum.setProjection(camera.getProjection()); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index dafa332d53..2c1c800f94 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -184,6 +184,7 @@ void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorI // Draws the FBO texture for the screen void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); if (_alpha == 0.0f) { return; } @@ -252,6 +253,7 @@ vec2 getPolarCoordinates(const PalmData& palm) { // Draws the FBO texture for Oculus rift. void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int eye) { + PROFILE_RANGE(__FUNCTION__); if (_alpha == 0.0f) { return; } diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e7d220893f..cadd78942c 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -74,6 +74,7 @@ ApplicationOverlay::~ApplicationOverlay() { // Renders the overlays either to a texture or to the screen void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); CHECK_GL_ERROR(); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()"); @@ -98,6 +99,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { } void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); if (_uiTexture) { gpu::Batch batch; auto geometryCache = DependencyManager::get(); @@ -112,6 +114,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { } void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); glm::vec2 size = qApp->getCanvasSize(); mat4 legacyProjection = glm::ortho(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); @@ -219,6 +222,7 @@ GLuint ApplicationOverlay::getOverlayTexture() { } void ApplicationOverlay::buildFramebufferObject() { + PROFILE_RANGE(__FUNCTION__); QSize fboSize = qApp->getDeviceSize(); if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { // Already built diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index fb0a095e13..db1bc2185a 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -96,6 +96,7 @@ void Overlays::cleanupOverlaysToDelete() { } void Overlays::renderHUD(RenderArgs* renderArgs) { + PROFILE_RANGE(__FUNCTION__); QReadLocker lock(&_lock); gpu::Batch batch; renderArgs->_batch = &batch; From 408ecb9735870f0788c9f447750322f06597e6c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 9 Jul 2015 15:59:32 -0700 Subject: [PATCH 12/25] move domain server check in timer to node thread --- interface/src/Application.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c1397beb28..07ddfe1377 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -394,6 +394,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : static_cast(dependency)->deleteLater(); }); + // setup a timer for domain-server check ins + QTimer* domainCheckInTimer = new QTimer(nodeList); + connect(domainCheckInTimer, &QTimer::timeout, nodeList, &NodeList::sendDomainServerCheckIn); + domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); + // put the NodeList and datagram processing on the node thread nodeList->moveToThread(nodeThread); @@ -1781,9 +1786,6 @@ void Application::checkFPS() { _frameCount = 0; _datagramProcessor->resetCounters(); _timerStart.start(); - - // ask the node list to check in with the domain server - DependencyManager::get()->sendDomainServerCheckIn(); } void Application::idle() { From a4f1145f067376681a9aab75fe48635f529d5016 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 9 Jul 2015 16:01:41 -0700 Subject: [PATCH 13/25] fix QTimer connection to nodeList --- interface/src/Application.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 07ddfe1377..48af04b031 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -396,7 +396,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // setup a timer for domain-server check ins QTimer* domainCheckInTimer = new QTimer(nodeList); - connect(domainCheckInTimer, &QTimer::timeout, nodeList, &NodeList::sendDomainServerCheckIn); + connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn); domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); // put the NodeList and datagram processing on the node thread @@ -987,7 +987,7 @@ void Application::paintGL() { renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - renderRearViewMirror(&renderArgs, _mirrorViewRect); + renderRearViewMirror(&renderArgs, _mirrorViewRect); } renderArgs._renderMode = RenderArgs::NORMAL_RENDER_MODE; @@ -1853,7 +1853,7 @@ void Application::idle() { // After finishing all of the above work, ensure the idle timer is set to the proper interval, // depending on whether we're throttling or not idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 0); - } + } // check for any requested background downloads. emit checkBackgroundDownloads(); @@ -3308,7 +3308,7 @@ namespace render { const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f; const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f; - glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) + glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation()) / closestData.getAtmosphereOuterRadius(); float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter()); if (height < closestData.getAtmosphereInnerRadius()) { @@ -3316,8 +3316,8 @@ namespace render { alpha = 0.0f; if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + APPROXIMATE_DISTANCE_FROM_HORIZON; alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); } @@ -3328,8 +3328,8 @@ namespace render { (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius()); if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) { - float directionY = glm::clamp(sunDirection.y, - -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + float directionY = glm::clamp(sunDirection.y, + -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON) + APPROXIMATE_DISTANCE_FROM_HORIZON; alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON); } @@ -3506,8 +3506,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload); } else { - pendingChanges.updateItem(WorldBoxRenderData::_item, - [](WorldBoxRenderData& payload) { + pendingChanges.updateItem(WorldBoxRenderData::_item, + [](WorldBoxRenderData& payload) { payload._val++; }); } @@ -3526,7 +3526,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se } { - PerformanceTimer perfTimer("SceneProcessPendingChanges"); + PerformanceTimer perfTimer("SceneProcessPendingChanges"); _main3DScene->enqueuePendingChanges(pendingChanges); _main3DScene->processPendingChangesQueue(); @@ -4835,7 +4835,7 @@ qreal Application::getDevicePixelRatio() { mat4 Application::getEyeProjection(int eye) const { if (isHMDMode()) { return OculusManager::getEyeProjection(eye); - } + } return _viewFrustum.getProjection(); } From efb89c281f0b771c92948ea4a2b47853d56d3f03 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 9 Jul 2015 16:02:29 -0700 Subject: [PATCH 14/25] fix creation of QTimer parented by NodeList --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48af04b031..e662263958 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -395,7 +395,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : }); // setup a timer for domain-server check ins - QTimer* domainCheckInTimer = new QTimer(nodeList); + QTimer* domainCheckInTimer = new QTimer(nodeList.data()); connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn); domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); From 214405a0e5012bc68ef895e0566413bb60e54842 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Jul 2015 16:06:27 -0700 Subject: [PATCH 15/25] Fixing typo --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21acadd3be..69e8710333 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -962,7 +962,7 @@ void Application::paintGL() { } else if (TV3DManager::isConnected()) { TV3DManager::display(&renderArgs, _myCamera); } else { - PROFILE_RANGE(__function__ "/mainRender"); + PROFILE_RANGE(__FUNCTION__ "/mainRender"); DependencyManager::get()->prepare(&renderArgs); From 1dce5f80cc68501ea8c72f99ce4450e2a856dfc2 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 16:17:58 -0700 Subject: [PATCH 16/25] Entities are now added/removed from rendering based on Scene.shouldRenderEntities --- interface/src/Application.cpp | 20 ++++++++++++++----- .../src/EntityTreeRenderer.cpp | 19 ++++++++++++++++++ .../src/EntityTreeRenderer.h | 6 ++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a30df36159..fb1aa737a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1014,7 +1014,6 @@ void Application::paintGL() { void Application::runTests() { runTimingTests(); - runUnitTests(); } void Application::audioMuteToggled() { @@ -1183,6 +1182,7 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { + if (event->type() == QEvent::ShortcutOverride) { if (DependencyManager::get()->shouldSwallowShortcut(event)) { event->accept(); @@ -1787,7 +1787,6 @@ void Application::checkFPS() { } void Application::idle() { - PROFILE_RANGE(__FUNCTION__); static SimpleAverage interIdleDurations; static uint64_t lastIdleEnd{ 0 }; @@ -3387,6 +3386,14 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // load the view frustum loadViewFrustum(theCamera, _displayViewFrustum); + // flip x if in mirror mode (also requires reversing winding order for backface culling) + if (theCamera.getMode() == CAMERA_MODE_MIRROR) { + //glScalef(-1.0f, 1.0f, 1.0f); + //glFrontFace(GL_CW); + } else { + glFrontFace(GL_CCW); + } + // transform view according to theCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -3404,6 +3411,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se Transform viewTransform; viewTransform.setTranslation(theCamera.getPosition()); viewTransform.setRotation(rotation); + if (theCamera.getMode() == CAMERA_MODE_MIRROR) { +// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); + } if (renderArgs->_renderSide != RenderArgs::MONO) { glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); @@ -3458,9 +3468,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // Assuming nothing get's rendered through that if (!selfAvatarOnly) { - + auto var = DependencyManager::get()->shouldRenderEntities(); // render models... - if (DependencyManager::get()->shouldRenderEntities()) { + //if (DependencyManager::get()->shouldRenderEntities()) { PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); @@ -3476,7 +3486,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se } renderArgs->_debugFlags = renderDebugFlags; _entities.render(renderArgs); - } + //} // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 03d88200c5..58068e7557 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -802,6 +803,8 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity); connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity); connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity); + + connect(&(*DependencyManager::get()), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityTree, Qt::QueuedConnection); } QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) { @@ -1152,3 +1155,19 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons entityScriptB.property("collisionWithEntity").call(entityScriptA, args); } } + +void EntityTreeRenderer::updateEntityTree(bool shouldRenderEntities) { + if (DependencyManager::get()->shouldRenderEntities()) { + qDebug() << "SHOULD RENDER ENTITIES NOW"; + for (auto entityID : _entityIDsLastInScene) { + addingEntity(entityID); + } + _entityIDsLastInScene.clear(); + } else { + qDebug() << "SHOULD NOT RENDER ENTITIES"; + _entityIDsLastInScene = _entitiesInScene.keys(); + for (auto entityID : _entityIDsLastInScene) { + deletingEntity(entityID); + } + } +} diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index bd6044516f..aae9c63d9a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -90,6 +90,9 @@ public: virtual void scriptContentsAvailable(const QUrl& url, const QString& scriptContents); virtual void errorInLoadingScript(const QUrl& url); + // For Scene.shouldRenderEntities + QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } + signals: void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); @@ -112,6 +115,7 @@ public slots: void deletingEntity(const EntityItemID& entityID); void entitySciptChanging(const EntityItemID& entityID, const bool reload); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); + void updateEntityTree(bool shouldRenderEntities); // optional slots that can be wired to menu items void setDisplayElementChildProxies(bool value) { _displayElementChildProxies = value; } @@ -188,6 +192,8 @@ private: int _previousStageDay; QHash _entitiesInScene; + // For Scene.shouldRenderEntities + QList _entityIDsLastInScene; }; From 52095fd38d9e8dfbdc1c853f4129f4011a2cc3d8 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 16:23:40 -0700 Subject: [PATCH 17/25] Fixing merge --- interface/src/Application.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fb1aa737a7..0ee65b56f4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1014,6 +1014,7 @@ void Application::paintGL() { void Application::runTests() { runTimingTests(); + runUnitTests(); } void Application::audioMuteToggled() { @@ -1182,7 +1183,6 @@ bool Application::event(QEvent* event) { } bool Application::eventFilter(QObject* object, QEvent* event) { - if (event->type() == QEvent::ShortcutOverride) { if (DependencyManager::get()->shouldSwallowShortcut(event)) { event->accept(); @@ -1787,6 +1787,7 @@ void Application::checkFPS() { } void Application::idle() { + PROFILE_RANGE(__FUNCTION__); static SimpleAverage interIdleDurations; static uint64_t lastIdleEnd{ 0 }; @@ -3386,14 +3387,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // load the view frustum loadViewFrustum(theCamera, _displayViewFrustum); - // flip x if in mirror mode (also requires reversing winding order for backface culling) - if (theCamera.getMode() == CAMERA_MODE_MIRROR) { - //glScalef(-1.0f, 1.0f, 1.0f); - //glFrontFace(GL_CW); - } else { - glFrontFace(GL_CCW); - } - // transform view according to theCamera // could be myCamera (if in normal mode) // or could be viewFrustumOffsetCamera if in offset mode @@ -3411,9 +3404,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se Transform viewTransform; viewTransform.setTranslation(theCamera.getPosition()); viewTransform.setRotation(rotation); - if (theCamera.getMode() == CAMERA_MODE_MIRROR) { -// viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f)); - } if (renderArgs->_renderSide != RenderArgs::MONO) { glm::mat4 invView = glm::inverse(_untranslatedViewMatrix); From adf5b95835df4a65ffc6c1da9c3d81820ccbfa5c Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 16:25:29 -0700 Subject: [PATCH 18/25] Changing formatting --- interface/src/Application.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0ee65b56f4..9482ed8586 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3460,23 +3460,21 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se if (!selfAvatarOnly) { auto var = DependencyManager::get()->shouldRenderEntities(); // render models... - //if (DependencyManager::get()->shouldRenderEntities()) { - PerformanceTimer perfTimer("entities"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... entities..."); + PerformanceTimer perfTimer("entities"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... entities..."); - RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS); - } - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { - renderDebugFlags = - (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); - } - renderArgs->_debugFlags = renderDebugFlags; - _entities.render(renderArgs); - //} + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { + renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS); + } + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { + renderDebugFlags = + (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); + } + renderArgs->_debugFlags = renderDebugFlags; + _entities.render(renderArgs); // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { From bd91daf712c9e4893d59db4785fe97890a978a10 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 16:27:23 -0700 Subject: [PATCH 19/25] Removing debug code --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 58068e7557..a2f6bc3289 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include @@ -1158,13 +1157,11 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons void EntityTreeRenderer::updateEntityTree(bool shouldRenderEntities) { if (DependencyManager::get()->shouldRenderEntities()) { - qDebug() << "SHOULD RENDER ENTITIES NOW"; for (auto entityID : _entityIDsLastInScene) { addingEntity(entityID); } _entityIDsLastInScene.clear(); } else { - qDebug() << "SHOULD NOT RENDER ENTITIES"; _entityIDsLastInScene = _entitiesInScene.keys(); for (auto entityID : _entityIDsLastInScene) { deletingEntity(entityID); From bf6fce4e454d03720f1faf0858d4307a744594ce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 9 Jul 2015 17:05:15 -0700 Subject: [PATCH 20/25] remove unneeded const --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e408ce3afa..794d0752a1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1653,7 +1653,7 @@ void EntityItem::deserializeActionsInternal() { // remove any actions that weren't included in the new data. QHash::const_iterator i = _objectActions.begin(); while (i != _objectActions.end()) { - const QUuid id = i.key(); + QUuid id = i.key(); if (!updated.contains(id)) { _actionsToRemove << id; } From 706f85e4ce81985752d71950dadb9f2daa959d06 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 17:31:38 -0700 Subject: [PATCH 21/25] Fixes to comply with coding standard --- interface/src/Application.cpp | 1 - libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 ++-- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9482ed8586..91baa8c8b5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3458,7 +3458,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // Assuming nothing get's rendered through that if (!selfAvatarOnly) { - auto var = DependencyManager::get()->shouldRenderEntities(); // render models... PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a2f6bc3289..11d24c6d9d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -803,7 +803,7 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity); connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity); - connect(&(*DependencyManager::get()), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityTree, Qt::QueuedConnection); + connect(&(*DependencyManager::get()), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection); } QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) { @@ -1155,7 +1155,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons } } -void EntityTreeRenderer::updateEntityTree(bool shouldRenderEntities) { +void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) { if (DependencyManager::get()->shouldRenderEntities()) { for (auto entityID : _entityIDsLastInScene) { addingEntity(entityID); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index aae9c63d9a..28a6a3172c 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -115,7 +115,7 @@ public slots: void deletingEntity(const EntityItemID& entityID); void entitySciptChanging(const EntityItemID& entityID, const bool reload); void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); - void updateEntityTree(bool shouldRenderEntities); + void updateEntityRenderStatus(bool shouldRenderEntities); // optional slots that can be wired to menu items void setDisplayElementChildProxies(bool value) { _displayElementChildProxies = value; } From 11f2d740308df31ed56ccd2c2d36771e6b1268bc Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Thu, 9 Jul 2015 17:33:25 -0700 Subject: [PATCH 22/25] Simple cleaning to remove dependancies on the viewStateInterface in the deferredLightingEffect --- .../render-utils/src/DeferredLightingEffect.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a721e0cad3..9bda5b8048 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include #include @@ -24,7 +23,7 @@ #include "TextureCache.h" #include "gpu/Batch.h" -#include "gpu/GLBackend.h" +#include "gpu/Context.h" #include "gpu/StandardShaderLib.h" #include "simple_vert.h" @@ -269,7 +268,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { // Fetch the ViewMatrix; glm::mat4 invViewMat; - _viewState->getViewTransform().getMatrix(invViewMat); + invViewMat = args->_viewFrustum->getView(); auto& program = _directionalLight; const LightLocations* locations = &_directionalLightLocations; @@ -344,7 +343,8 @@ void DeferredLightingEffect::render(RenderArgs* args) { float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + args->_viewFrustum->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + batch._glUniform1f(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; @@ -394,9 +394,9 @@ void DeferredLightingEffect::render(RenderArgs* args) { // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; - - const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition(); - float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft()); + + auto eyePoint = args->_viewFrustum->getPosition(); + float nearRadius = glm::distance(eyePoint, args->_viewFrustum->getNearTopLeft()); auto geometryCache = DependencyManager::get(); From 007d662db1dcf6fdb6721b0160e9819baf395772 Mon Sep 17 00:00:00 2001 From: Niraj Venkat Date: Thu, 9 Jul 2015 17:40:14 -0700 Subject: [PATCH 23/25] Re-added for shouldRenderEntities --- interface/src/Application.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 91baa8c8b5..5188e19c1a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3458,22 +3458,24 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // Assuming nothing get's rendered through that if (!selfAvatarOnly) { - // render models... - PerformanceTimer perfTimer("entities"); - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "Application::displaySide() ... entities..."); + if (DependencyManager::get()->shouldRenderEntities()) { + // render models... + PerformanceTimer perfTimer("entities"); + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "Application::displaySide() ... entities..."); - RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; + RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE; - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { - renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS); + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) { + renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS); + } + if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { + renderDebugFlags = + (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); + } + renderArgs->_debugFlags = renderDebugFlags; + _entities.render(renderArgs); } - if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) { - renderDebugFlags = - (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP); - } - renderArgs->_debugFlags = renderDebugFlags; - _entities.render(renderArgs); // render the ambient occlusion effect if enabled if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { From a92a7980d7e5e094b608662408153798dc176b3b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Jul 2015 17:49:25 -0700 Subject: [PATCH 24/25] Restore audio scope --- interface/src/audio/AudioScope.cpp | 41 ++++++++++++++----------- interface/src/audio/AudioScope.h | 13 ++++---- interface/src/ui/ApplicationOverlay.cpp | 3 +- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 8cc27341d6..7a93be80f1 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include #include "AudioScope.h" @@ -104,7 +107,7 @@ void AudioScope::freeScope() { } } -void AudioScope::render(int width, int height) { +void AudioScope::render(RenderArgs* renderArgs, int width, int height) { if (!_isEnabled) { return; @@ -122,24 +125,26 @@ void AudioScope::render(int width, int height) { int y = (height - (int)SCOPE_HEIGHT) / 2; int w = (int)SCOPE_WIDTH; int h = (int)SCOPE_HEIGHT; - - renderBackground(backgroundColor, x, y, w, h); - renderGrid(gridColor, x, y, w, h, gridRows, gridCols); - - renderLineStrip(_inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); - renderLineStrip(_outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); - renderLineStrip(_outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); + + gpu::Batch batch; + auto geometryCache = DependencyManager::get(); + geometryCache->useSimpleDrawPipeline(batch); + auto textureCache = DependencyManager::get(); + batch.setUniformTexture(0, textureCache->getWhiteTexture()); + mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); + batch.setProjectionTransform(legacyProjection); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); + geometryCache->renderQuad(batch, x, y, w, h, backgroundColor); + geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid); + renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); + renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); + renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); + renderArgs->_context->syncCache(); + renderArgs->_context->render(batch); } -void AudioScope::renderBackground(const glm::vec4& color, int x, int y, int width, int height) { - DependencyManager::get()->renderQuad(x, y, width, height, color); -} - -void AudioScope::renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols) { - DependencyManager::get()->renderGrid(x, y, width, height, rows, cols, color, _audioScopeGrid); -} - -void AudioScope::renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) { +void AudioScope::renderLineStrip(gpu::Batch& batch, int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) { int16_t sample; int16_t* samples = ((int16_t*) byteArray->data()) + offset; @@ -194,7 +199,7 @@ void AudioScope::renderLineStrip(int id, const glm::vec4& color, int x, int y, i geometryCache->updateVertices(id, points, color); - geometryCache->renderVertices(gpu::LINE_STRIP, id); + geometryCache->renderVertices(batch, gpu::LINE_STRIP, id); } int AudioScope::addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamplesPerChannel, diff --git a/interface/src/audio/AudioScope.h b/interface/src/audio/AudioScope.h index cc9367e2d5..4ff4b55c29 100644 --- a/interface/src/audio/AudioScope.h +++ b/interface/src/audio/AudioScope.h @@ -14,11 +14,14 @@ #include -#include - #include #include +#include +#include +#include + + class AudioScope : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -28,7 +31,7 @@ public: void freeScope(); void reallocateScope(int frames); - void render(int width, int height); + void render(RenderArgs* renderArgs, int width, int height); public slots: void toggle(); @@ -48,9 +51,7 @@ private slots: private: // Audio scope methods for rendering - static void renderBackground(const glm::vec4& color, int x, int y, int width, int height); - void renderGrid(const glm::vec4& color, int x, int y, int width, int height, int rows, int cols); - void renderLineStrip(int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray); + void renderLineStrip(gpu::Batch& batch, int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray); // Audio scope methods for data acquisition int addBufferToScope(QByteArray* byteArray, int frameOffset, const int16_t* source, int sourceSamples, diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index e7d220893f..c58d450126 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -129,11 +129,12 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { emit qApp->renderingOverlay(); qApp->getOverlays().renderHUD(renderArgs); + DependencyManager::get()->render(renderArgs, _overlayFramebuffer->size().width(), _overlayFramebuffer->size().height()); + glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - renderArgs->_context->syncCache(); fboViewport(_overlayFramebuffer); } From 6c5d7b87891d909500325425a6a1ede7e35da63c Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 9 Jul 2015 17:53:26 -0700 Subject: [PATCH 25/25] Performance optimizations in transform buffers and geometry cache --- libraries/gpu/src/gpu/GLBackendTransform.cpp | 4 +- libraries/render-utils/src/GeometryCache.cpp | 60 +++++++++++++------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 5f4d5f4af6..48a42fe5f1 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -117,7 +117,7 @@ void GLBackend::updateTransform() { if (_transform._invalidView || _transform._invalidProj || _transform._invalidViewport) { glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformCamera), (const void*)&_transform._transformCamera); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); } @@ -125,7 +125,7 @@ void GLBackend::updateTransform() { if (_transform._invalidModel) { glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_transform._transformObject), (const void*) &_transform._transformObject); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 35f946c55c..02e59bfa3a 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -279,14 +279,21 @@ void GeometryCache::renderSphere(gpu::Batch& batch, float radius, int slices, in const int VERTICES_SLOT = 0; const int NORMALS_SLOT = 1; const int COLOR_SLOT = 2; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, normalElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } - gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView normalsView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); + gpu::BufferView verticesView(verticesBuffer, positionElement); + gpu::BufferView normalsView(verticesBuffer, normalElement); + gpu::BufferView colorView(colorBuffer, colorElement); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, verticesView); @@ -899,14 +906,21 @@ void GeometryCache::renderSolidCube(gpu::Batch& batch, float size, const glm::ve const int VERTICES_SLOT = 0; const int NORMALS_SLOT = 1; const int COLOR_SLOT = 2; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, normalElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + normalElement = streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::NORMAL, NORMALS_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::NORMAL)._element); + + gpu::BufferView verticesView(verticesBuffer, 0, verticesBuffer->getSize(), VERTEX_STRIDE, positionElement); + gpu::BufferView normalsView(verticesBuffer, NORMALS_OFFSET, verticesBuffer->getSize(), VERTEX_STRIDE, normalElement); gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); batch.setInputFormat(streamFormat); @@ -986,12 +1000,18 @@ void GeometryCache::renderWireCube(gpu::Batch& batch, float size, const glm::vec const int VERTICES_SLOT = 0; const int COLOR_SLOT = 1; - gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone - streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); - - gpu::BufferView verticesView(verticesBuffer, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); - gpu::BufferView colorView(colorBuffer, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); + static gpu::Stream::FormatPointer streamFormat; + static gpu::Element positionElement, colorElement; + if (!streamFormat) { + streamFormat.reset(new gpu::Stream::Format()); // 1 for everyone + streamFormat->setAttribute(gpu::Stream::POSITION, VERTICES_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_SLOT, gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA)); + positionElement = streamFormat->getAttributes().at(gpu::Stream::POSITION)._element; + colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element; + } + + gpu::BufferView verticesView(verticesBuffer, positionElement); + gpu::BufferView colorView(colorBuffer, colorElement); batch.setInputFormat(streamFormat); batch.setInputBuffer(VERTICES_SLOT, verticesView);