From 7fc66392cce00da8f70fd6a1c2048e5275392a08 Mon Sep 17 00:00:00 2001 From: stojce Date: Sat, 8 Feb 2014 12:04:55 +0100 Subject: [PATCH 01/41] Interface OS X hifi URL scheme --- cmake/modules/MacOSXBundleInfo.plist.in | 47 +++++++++++++++++++++++++ interface/CMakeLists.txt | 4 +++ 2 files changed, 51 insertions(+) create mode 100644 cmake/modules/MacOSXBundleInfo.plist.in diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in new file mode 100644 index 0000000000..1682b6c022 --- /dev/null +++ b/cmake/modules/MacOSXBundleInfo.plist.in @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + LSRequiresCarbon + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + CFBundleURLTypes + + + CFBundleURLName + ${MACOSX_BUNDLE_BUNDLE_NAME} URL + CFBundleURLSchemes + + hifi + + + + + diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 6af6ed478d..846df5e493 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -90,6 +90,10 @@ qt5_wrap_ui(QT_UI_HEADERS ${QT_UI_FILES}) set(INTERFACE_SRCS ${INTERFACE_SRCS} ${QT_UI_HEADERS}) if (APPLE) + + # configure CMake to use a custom Info.plist + SET_TARGET_PROPERTIES( ${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in ) + set(MACOSX_BUNDLE_BUNDLE_NAME Interface) # set how the icon shows up in the Info.plist file SET(MACOSX_BUNDLE_ICON_FILE interface.icns) From b05967a5149ccff2a723a46581214861fcb54e8a Mon Sep 17 00:00:00 2001 From: stojce Date: Sun, 9 Feb 2014 17:47:46 +0100 Subject: [PATCH 02/41] Custom URL handler --- interface/src/Application.cpp | 17 +++++++ interface/src/Application.h | 4 +- interface/src/Menu.cpp | 84 +++++++++++++++-------------------- interface/src/Menu.h | 1 + 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f32c6be09..9ba7699714 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -101,6 +101,8 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D const int STATS_PELS_PER_LINE = 20; +const QString CUSTOM_URL_SCHEME = "hifi:"; + void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { if (message.size() > 0) { QString messageWithNewLine = message + "\n"; @@ -680,6 +682,21 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod } } +bool Application::event(QEvent* event) { + + // handle custom URL + if (event->type() == QEvent::FileOpen) { + QFileOpenEvent* fileEvent = static_cast(event); + if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) { + QString destination = fileEvent->url().toLocalFile().remove(QRegExp(CUSTOM_URL_SCHEME + "|/")); + Menu::getInstance()->goToDestination(destination); + } + + return false; + } + return QApplication::event(event); +} + void Application::keyPressEvent(QKeyEvent* event) { _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts diff --git a/interface/src/Application.h b/interface/src/Application.h index 94b5601797..c4550e2f0b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -127,7 +127,9 @@ public: void touchUpdateEvent(QTouchEvent* event); void wheelEvent(QWheelEvent* event); - + + bool event(QEvent* event); + void makeVoxel(glm::vec3 position, float scale, unsigned char red, diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6640df3468..a447c6703a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -913,6 +913,39 @@ void Menu::goToDomain() { sendFakeEnterEvent(); } +bool Menu::goToDestination(QString destination) { + + QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); + + const int NUMBER_OF_COORDINATE_ITEMS = 3; + const int X_ITEM = 0; + const int Y_ITEM = 1; + const int Z_ITEM = 2; + if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { + + double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); + double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); + double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); + + glm::vec3 newAvatarPos(x, y, z); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::vec3 avatarPos = myAvatar->getPosition(); + if (newAvatarPos != avatarPos) { + // send a node kill request, indicating to other clients that they should play the "disappeared" effect + MyAvatar::sendKillAvatar(); + + qDebug("Going To Location: %f, %f, %f...", x, y, z); + myAvatar->setPosition(newAvatarPos); + } + + return true; + } + + // no coordinates were parsed + return false; +} + void Menu::goTo() { QInputDialog gotoDialog(Application::getInstance()->getWindow()); @@ -928,31 +961,8 @@ void Menu::goTo() { destination = gotoDialog.textValue(); - QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); - - const int NUMBER_OF_COORDINATE_ITEMS = 3; - const int X_ITEM = 0; - const int Y_ITEM = 1; - const int Z_ITEM = 2; - if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { - - double x = replaceLastOccurrence('-', '.', coordinateItems[X_ITEM].trimmed()).toDouble(); - double y = replaceLastOccurrence('-', '.', coordinateItems[Y_ITEM].trimmed()).toDouble(); - double z = replaceLastOccurrence('-', '.', coordinateItems[Z_ITEM].trimmed()).toDouble(); - - glm::vec3 newAvatarPos(x, y, z); - - MyAvatar* myAvatar = Application::getInstance()->getAvatar(); - glm::vec3 avatarPos = myAvatar->getPosition(); - if (newAvatarPos != avatarPos) { - // send a node kill request, indicating to other clients that they should play the "disappeared" effect - MyAvatar::sendKillAvatar(); - - qDebug("Going To Location: %f, %f, %f...", x, y, z); - myAvatar->setPosition(newAvatarPos); - } - - } else { + // go to coordinate destination or to Username + if (!goToDestination(destination)) { // there's a username entered by the user, make a request to the data-server DataServerClient::getValuesForKeysAndUserString( QStringList() @@ -983,29 +993,7 @@ void Menu::goToLocation() { int dialogReturn = coordinateDialog.exec(); if (dialogReturn == QDialog::Accepted && !coordinateDialog.textValue().isEmpty()) { - QByteArray newCoordinates; - - QString delimiterPattern(","); - QStringList coordinateItems = coordinateDialog.textValue().split(delimiterPattern); - - const int NUMBER_OF_COORDINATE_ITEMS = 3; - const int X_ITEM = 0; - const int Y_ITEM = 1; - const int Z_ITEM = 2; - if (coordinateItems.size() == NUMBER_OF_COORDINATE_ITEMS) { - double x = coordinateItems[X_ITEM].toDouble(); - double y = coordinateItems[Y_ITEM].toDouble(); - double z = coordinateItems[Z_ITEM].toDouble(); - glm::vec3 newAvatarPos(x, y, z); - - if (newAvatarPos != avatarPos) { - // send a node kill request, indicating to other clients that they should play the "disappeared" effect - MyAvatar::sendKillAvatar(); - - qDebug("Going To Location: %f, %f, %f...", x, y, z); - myAvatar->setPosition(newAvatarPos); - } - } + goToDestination(coordinateDialog.textValue()); } sendFakeEnterEvent(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fcd2d74940..4e835146e6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -84,6 +84,7 @@ public: const char* member = NULL, QAction::MenuRole role = QAction::NoRole); virtual void removeAction(QMenu* menu, const QString& actionName); + bool goToDestination(QString destination); public slots: void bandwidthDetails(); From 8acb6d13d57efb1d685d9b402b26dcc09cc405f4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 15:25:09 -0800 Subject: [PATCH 03/41] move hydra thrust and view code into JS example --- examples/cameraExample.js | 7 +++ examples/hydraThrustAndView.js | 86 +++++++++++++++++++++++++++++++ interface/src/Application.cpp | 2 +- interface/src/avatar/Hand.cpp | 1 - interface/src/avatar/Hand.h | 6 --- interface/src/avatar/MyAvatar.cpp | 34 +----------- interface/src/avatar/MyAvatar.h | 10 ++-- 7 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 examples/hydraThrustAndView.js diff --git a/examples/cameraExample.js b/examples/cameraExample.js index d42c3c1b0e..65cffb17dd 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -69,6 +69,13 @@ function checkCamera() { var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER); yaw -= viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime; pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime; + if (yaw > 360) { + yaw -= 360; + } + if (yaw < -360) { + yaw += 360; + } + print("pitch="+ pitch + " yaw="+ yaw + " roll=" + roll); var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); Camera.setOrientation(orientation); } diff --git a/examples/hydraThrustAndView.js b/examples/hydraThrustAndView.js new file mode 100644 index 0000000000..249aa5948c --- /dev/null +++ b/examples/hydraThrustAndView.js @@ -0,0 +1,86 @@ +// +// hydraThrustAndView.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/6/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Controller and MyAvatar classes to implement +// avatar flying through the hydra/controller joysticks +// +// + +var damping = 0.9; +var position = { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }; +var joysticksCaptured = false; +var THRUST_CONTROLLER = 0; +var VIEW_CONTROLLER = 1; +var INITIAL_THRUST_MULTPLIER = 1.0; +var THRUST_INCREASE_RATE = 1.05; +var MAX_THRUST_MULTIPLIER = 75.0; +var thrustMultiplier = INITIAL_THRUST_MULTPLIER; + +function flyWithHydra() { + var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call + var THRUST_MAG_UP = 800.0; + var THRUST_MAG_DOWN = 300.0; + var THRUST_MAG_FWD = 500.0; + var THRUST_MAG_BACK = 300.0; + var THRUST_MAG_LATERAL = 250.0; + var THRUST_JUMP = 120.0; + var scale = 1.0; + + var YAW_MAG = 500.0; + var PITCH_MAG = 100.0; + var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; + var JOYSTICK_YAW_MAG = YAW_MAG; + var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5; + + var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER); + + if (thrustJoystickPosition.x != 0 || thrustJoystickPosition.y != 0) { + if (thrustMultiplier < MAX_THRUST_MULTIPLIER) { + thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE); + } + var currentOrientation = MyAvatar.orientation; + + var front = Quat.getFront(currentOrientation); + var right = Quat.getRight(currentOrientation); + var up = Quat.getUp(currentOrientation); + + var thrustFront = Vec3.multiply(front, scale * THRUST_MAG_HAND_JETS * thrustJoystickPosition.y * thrustMultiplier * deltaTime); + MyAvatar.addThrust(thrustFront); + var thrustRight = Vec3.multiply(right, scale * THRUST_MAG_HAND_JETS * thrustJoystickPosition.x * thrustMultiplier * deltaTime); + MyAvatar.addThrust(thrustRight); + } else { + thrustMultiplier = INITIAL_THRUST_MULTPLIER; + } + + // View Controller + var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER); + if (viewJoystickPosition.x != 0 || viewJoystickPosition.y != 0) { + + // change the body yaw based on our x controller + var orientation = MyAvatar.orientation; + var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); + MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); + + // change the headPitch based on our x controller + //pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime; + var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime); + MyAvatar.headPitch = newPitch; + } +} + +Script.willSendVisualDataCallback.connect(flyWithHydra); +Controller.captureJoystick(THRUST_CONTROLLER); +Controller.captureJoystick(VIEW_CONTROLLER); + +// Map keyPress and mouse move events to our callbacks +function scriptEnding() { + // re-enabled the standard application for touch events + Controller.releaseJoystick(THRUST_CONTROLLER); + Controller.releaseJoystick(VIEW_CONTROLLER); +} +Script.scriptEnding.connect(scriptEnding); + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 160d6b7c2c..004b71074b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4042,7 +4042,7 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); // hook our avatar object into this script engine - scriptEngine->setAvatarData( static_cast(_myAvatar), "MyAvatar"); + scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features CameraScriptableObject* cameraScriptable = new CameraScriptableObject(&_myCamera, &_viewFrustum); scriptEngine->registerGlobalObject("Camera", cameraScriptable); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index b441000cc1..302475df8a 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -33,7 +33,6 @@ Hand::Hand(Avatar* owningAvatar) : _collisionCenter(0,0,0), _collisionAge(0), _collisionDuration(0), - _pitchUpdate(0), _grabDelta(0, 0, 0), _grabDeltaVelocity(0, 0, 0), _grabStartRotation(0, 0, 0, 1), diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 3c8ec2d562..aec5cdb921 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -58,10 +58,6 @@ public: const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} - // Pitch from controller input to view - const float getPitchUpdate() const { return _pitchUpdate; } - void setPitchUpdate(float pitchUpdate) { _pitchUpdate = pitchUpdate; } - // Get the drag distance to move glm::vec3 getAndResetGrabDelta(); glm::vec3 getAndResetGrabDeltaVelocity(); @@ -101,8 +97,6 @@ private: void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); - float _pitchUpdate; - glm::vec3 _grabDelta; glm::vec3 _grabDeltaVelocity; glm::quat _grabStartRotation; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 98eb9a4431..4eec6e70f8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -323,6 +323,7 @@ void MyAvatar::simulate(float deltaTime) { updateChatCircle(deltaTime); + // TODO: this should be removed and turned into JS instead // Get any position, velocity, or rotation update from Grab Drag controller glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta(); if (glm::length(moveFromGrab) > EPSILON) { @@ -797,39 +798,6 @@ void MyAvatar::updateThrust(float deltaTime) { up; } } - // Add thrust and rotation from hand controllers - const float THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; - const float JOYSTICK_YAW_MAG = YAW_MAG; - const float JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5f; - const int THRUST_CONTROLLER = 0; - const int VIEW_CONTROLLER = 1; - for (size_t i = 0; i < getHand().getPalms().size(); ++i) { - PalmData& palm = getHand().getPalms()[i]; - - // If the script hasn't captured this joystick, then let the default behavior work - if (!Application::getInstance()->getControllerScriptingInterface()->isJoystickCaptured(palm.getSixenseID())) { - if (palm.isActive() && (palm.getSixenseID() == THRUST_CONTROLLER)) { - if (palm.getJoystickY() != 0.f) { - FingerData& finger = palm.getFingers()[0]; - if (finger.isActive()) { - } - _thrust += front * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickY() * _thrustMultiplier * deltaTime; - } - if (palm.getJoystickX() != 0.f) { - _thrust += right * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickX() * _thrustMultiplier * deltaTime; - } - } else if (palm.isActive() && (palm.getSixenseID() == VIEW_CONTROLLER)) { - if (palm.getJoystickX() != 0.f) { - _bodyYawDelta -= palm.getJoystickX() * JOYSTICK_YAW_MAG * deltaTime; - } - if (palm.getJoystickY() != 0.f) { - getHand().setPitchUpdate(getHand().getPitchUpdate() + - (palm.getJoystickY() * JOYSTICK_PITCH_MAG * deltaTime)); - } - } - } - - } // Update speed brake status const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7dfb8812dd..4e381509b9 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -45,7 +45,6 @@ public: // setters void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; } - void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } void setLeanScale(float scale) { _leanScale = scale; } void setGravity(glm::vec3 gravity); @@ -78,9 +77,6 @@ public: static void sendKillAvatar(); - // Set/Get update the thrust that will move the avatar around - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; - glm::vec3 getThrust() { return _thrust; }; void orbit(const glm::vec3& position, int deltaX, int deltaY); @@ -94,9 +90,13 @@ public slots: void increaseSize(); void decreaseSize(); void resetSize(); - void sendIdentityPacket(); + // Set/Get update the thrust that will move the avatar around + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } + private: bool _mousePressed; float _bodyPitchDelta; From c68abb3499aecf9c255abc1396107eb592861589 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 15:33:07 -0800 Subject: [PATCH 04/41] nodelist bug --- libraries/shared/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 92f6f961d5..3d4e86decf 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -87,7 +87,7 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { if (packet[1] != versionForPacketType(packetTypeForPacket(packet)) && packetTypeForPacket(packet) != PacketTypeStunResponse) { PacketType mismatchType = packetTypeForPacket(packet); - int numPacketTypeBytes = arithmeticCodingValueFromBuffer(packet.data()); + int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); qDebug() << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" << uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but" From 0c547a8160f7b874caeb68171fad9ad4daacc4eb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 15:37:49 -0800 Subject: [PATCH 05/41] added Quat.safeEulerAngles() for JS --- libraries/script-engine/src/Quat.cpp | 5 +++++ libraries/script-engine/src/Quat.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index a197d59aeb..dceb1e40df 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -10,6 +10,7 @@ // #include +#include #include "Quat.h" glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { @@ -35,3 +36,7 @@ glm::vec3 Quat::getRight(const glm::quat& orientation) { glm::vec3 Quat::getUp(const glm::quat& orientation) { return orientation * IDENTITY_UP; } + +glm::vec3 Quat::safeEulerAngles(const glm::quat& orientation) { + return safeEulerAngles(orientation); +} diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 72fec6d6dc..7e29c41833 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -26,6 +26,7 @@ public slots: glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); glm::vec3 getUp(const glm::quat& orientation); + glm::vec3 safeEulerAngles(const glm::quat& orientation); }; From 3f73b61a76a11554f4dfd85038738c040551eff3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 15:38:19 -0800 Subject: [PATCH 06/41] renamed hydraMove.js --- examples/{hydraThrustAndView.js => hydraMove.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{hydraThrustAndView.js => hydraMove.js} (100%) diff --git a/examples/hydraThrustAndView.js b/examples/hydraMove.js similarity index 100% rename from examples/hydraThrustAndView.js rename to examples/hydraMove.js From 65121aefb678758d521e404820f459ba44760752 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 10 Feb 2014 16:42:05 -0800 Subject: [PATCH 07/41] EditVoxels.js: Added color changing with number keys, better audio --- examples/editVoxels.js | 52 +++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 96bb09e6d6..7210a07e1b 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -7,9 +7,10 @@ // // Captures mouse clicks and edits voxels accordingly. // -// click = create a new voxel on this face, same color as old -// Alt + click = delete this voxel +// click = create a new voxel on this face, same color as old (default color picker state) +// right click or control + click = delete this voxel // shift + click = recolor this voxel +// 1 - 8 = pick new color from palette // // Click and drag to create more new voxels in the same direction // @@ -18,6 +19,11 @@ function vLength(v) { return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } +function vMinus(a, b) { + var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; + return rval; +} + var key_alt = false; var key_shift = false; var isAdding = false; @@ -37,31 +43,32 @@ colors[4] = { red: 193, green: 99, blue: 122 }; colors[5] = { red: 255, green: 54, blue: 69 }; colors[6] = { red: 124, green: 36, blue: 36 }; colors[7] = { red: 63, green: 35, blue: 19 }; -var numColors = 6; -var whichColor = 0; +var numColors = 8; +var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw"); var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw"); var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw"); +var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Collisions-ballhitsandcatches/ballcatch2.raw"); var audioOptions = new AudioInjectionOptions();
 +audioOptions.volume = 0.5; function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - audioOptions.volume = 1.0; - audioOptions.position = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z }; + audioOptions.position = { x: pickRay.origin.x + pickRay.direction.x, + y: pickRay.origin.y + pickRay.direction.y, + z: pickRay.origin.z + pickRay.direction.z }; if (intersection.intersects) { - if (key_alt) { + if (event.isRightButton || event.isControl) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); - } else if (key_shift) { + } else if (event.isShifted) { // Recolor Voxel - whichColor++; - if (whichColor == numColors) whichColor = 0; Voxels.setVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, @@ -70,7 +77,9 @@ function mousePressEvent(event) { Audio.playSound(changeColorSound, audioOptions); } else { // Add voxel on face - var newVoxel = { + if (whichColor == -1) { + // Copy mode - use clicked voxel color + var newVoxel = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, @@ -78,6 +87,16 @@ function mousePressEvent(event) { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; + } else { + var newVoxel = { + x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z, + s: intersection.voxel.s, + red: colors[whichColor].red, + green: colors[whichColor].green, + blue: colors[whichColor].blue }; + } if (intersection.face == "MIN_X_FACE") { newVoxel.x -= newVoxel.s; @@ -108,7 +127,18 @@ function mousePressEvent(event) { function keyPressEvent(event) { key_alt = event.isAlt; key_shift = event.isShifted; + var nVal = parseInt(event.text); + if (event.text == "0") { + print("Color = Copy"); + whichColor = -1; + Audio.playSound(clickSound, audioOptions); + } else if ((nVal > 0) && (nVal <= numColors)) { + whichColor = nVal - 1; + print("Color = " + (whichColor + 1)); + Audio.playSound(clickSound, audioOptions); + } } + function keyReleaseEvent(event) { key_alt = false; key_shift = false; From 991c72006c9ffc0567f0ec48541cd9f91ca69d88 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 17:25:14 -0800 Subject: [PATCH 08/41] moving the hydra grab behavior to JS --- examples/hydraMove.js | 88 +++++++++++++++++++ .../src/ControllerScriptingInterface.cpp | 15 ++++ interface/src/ControllerScriptingInterface.h | 2 +- interface/src/avatar/Hand.cpp | 41 +-------- interface/src/avatar/Hand.h | 10 --- interface/src/avatar/MyAvatar.cpp | 16 ---- .../AbstractControllerScriptingInterface.h | 2 + libraries/script-engine/src/Quat.cpp | 14 ++- libraries/script-engine/src/Quat.h | 2 + libraries/script-engine/src/Vec3.cpp | 8 ++ libraries/script-engine/src/Vec3.h | 2 + 11 files changed, 132 insertions(+), 68 deletions(-) diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 249aa5948c..252d3c7756 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -19,6 +19,46 @@ var INITIAL_THRUST_MULTPLIER = 1.0; var THRUST_INCREASE_RATE = 1.05; var MAX_THRUST_MULTIPLIER = 75.0; var thrustMultiplier = INITIAL_THRUST_MULTPLIER; +var grabDelta = { x: 0, y: 0, z: 0}; +var grabDeltaVelocity = { x: 0, y: 0, z: 0}; +var grabStartRotation = { x: 0, y: 0, z: 0, w: 1}; +var grabCurrentRotation = { x: 0, y: 0, z: 0, w: 1}; +var grabbingWithRightHand = false; +var wasGrabbingWithRightHand = false; +var grabbingWithLeftHand = false; +var wasGrabbingWithLeftHand = false; +var EPSILON = 0.000001; //smallish positive number - used as margin of error for some computations +var velocity = { x: 0, y: 0, z: 0}; + + +var LEFT_PALM = 0; +var LEFT_BUTTON_4 = 4; +var RIGHT_PALM = 2; +var RIGHT_BUTTON_4 = 10; + +function getAndResetGrabDelta() { + var HAND_GRAB_SCALE_DISTANCE = 2.0; + var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE)); + grabDelta = { x: 0, y: 0, z: 0}; + var avatarRotation = MyAvatar.orientation; + var result = Vec3.multiplyQbyV(avatarRotation, Vec3.multiply(delta, -1)); + return result; +} + +function getAndResetGrabDeltaVelocity() { + var HAND_GRAB_SCALE_VELOCITY = 5.0; + var delta = Vec3.multiply(grabDeltaVelocity, (MyAvatar.scale * HAND_GRAB_SCALE_VELOCITY)); + grabDeltaVelocity = { x: 0, y: 0, z: 0}; + var avatarRotation = MyAvatar.orientation; + var result = Quat.multiply(avatarRotation, Vec3.multiply(delta, -1)); + return result; +} + +function getAndResetGrabRotation() { + var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation)); + grabStartRotation = grabCurrentRotation; + return quatDiff; +} function flyWithHydra() { var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call @@ -70,6 +110,54 @@ function flyWithHydra() { var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime); MyAvatar.headPitch = newPitch; } + + // check for and handle grab behaviors + grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4); + grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4); + + if (grabbingWithRightHand) { + grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime)); + grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + if (!grabbingWithRightHand && wasGrabbingWithRightHand) { + // Just ending grab, capture velocity + grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM); + } + if (grabbingWithRightHand && !wasGrabbingWithRightHand) { + // Just starting grab, capture starting rotation + grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + + grabbing = grabbingWithRightHand || grabbingWithLeftHand; + + if (grabbing) { + + // move position + var moveFromGrab = getAndResetGrabDelta(); + if (Vec3.length(moveFromGrab) > EPSILON) { + position = Vec3.sum(position, moveFromGrab); + velocity = { x: 0, y: 0, z: 0}; + } + + // add some velocity... + velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity()); + + // add some rotation... + var deltaRotation = getAndResetGrabRotation(); + var GRAB_CONTROLLER_TURN_SCALING = 0.5; + var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING); + + // Adjust body yaw by yaw from controller + var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation); + MyAvatar.orientation = orientation; + + // Adjust head pitch from controller + //getHead().setPitch(getHead().getPitch() - euler.x); + MyAvatar.headPitch = MyAvatar.headPitch - euler.x; + } + + wasGrabbingWithRightHand = grabbingWithRightHand; + wasGrabbingWithLeftHand = grabbingWithLeftHand; } Script.willSendVisualDataCallback.connect(flyWithHydra); diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index 8716116877..b3d6170bff 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -172,6 +172,21 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlInd return glm::vec3(0); // bad index } +glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { + int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; + int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; + const PalmData* palmData = getActivePalm(palmIndex); + if (palmData) { + switch (controlOfPalm) { + case PALM_SPATIALCONTROL: + return palmData->getRawRotation(); + case TIP_SPATIALCONTROL: + return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation + } + } + return glm::quat(); // bad index +} + glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const { int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h index e9fbd2d6d3..f0a50559f9 100644 --- a/interface/src/ControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -58,7 +58,7 @@ public slots: virtual glm::vec3 getSpatialControlPosition(int controlIndex) const; virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const; virtual glm::vec3 getSpatialControlNormal(int controlIndex) const; - + virtual glm::quat getSpatialControlRawRotation(int controlIndex) const; virtual void captureKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 302475df8a..291ed034ec 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -32,11 +32,7 @@ Hand::Hand(Avatar* owningAvatar) : _ballColor(0.0, 0.0, 0.4), _collisionCenter(0,0,0), _collisionAge(0), - _collisionDuration(0), - _grabDelta(0, 0, 0), - _grabDeltaVelocity(0, 0, 0), - _grabStartRotation(0, 0, 0, 1), - _grabCurrentRotation(0, 0, 0, 1) + _collisionDuration(0) { } @@ -53,28 +49,6 @@ void Hand::init() { void Hand::reset() { } -glm::vec3 Hand::getAndResetGrabDelta() { - const float HAND_GRAB_SCALE_DISTANCE = 2.f; - glm::vec3 delta = _grabDelta * _owningAvatar->getScale() * HAND_GRAB_SCALE_DISTANCE; - _grabDelta = glm::vec3(0,0,0); - glm::quat avatarRotation = _owningAvatar->getOrientation(); - return avatarRotation * -delta; -} - -glm::vec3 Hand::getAndResetGrabDeltaVelocity() { - const float HAND_GRAB_SCALE_VELOCITY = 5.f; - glm::vec3 delta = _grabDeltaVelocity * _owningAvatar->getScale() * HAND_GRAB_SCALE_VELOCITY; - _grabDeltaVelocity = glm::vec3(0,0,0); - glm::quat avatarRotation = _owningAvatar->getOrientation(); - return avatarRotation * -delta; - -} -glm::quat Hand::getAndResetGrabRotation() { - glm::quat diff = _grabCurrentRotation * glm::inverse(_grabStartRotation); - _grabStartRotation = _grabCurrentRotation; - return diff; -} - void Hand::simulate(float deltaTime, bool isMine) { if (_collisionAge > 0.f) { @@ -100,19 +74,6 @@ void Hand::simulate(float deltaTime, bool isMine) { _buckyBalls.grab(palm, fingerTipPosition, _owningAvatar->getOrientation(), deltaTime); - if (palm.getControllerButtons() & BUTTON_4) { - _grabDelta += palm.getRawVelocity() * deltaTime; - _grabCurrentRotation = palm.getRawRotation(); - } - if ((palm.getLastControllerButtons() & BUTTON_4) && !(palm.getControllerButtons() & BUTTON_4)) { - // Just ending grab, capture velocity - _grabDeltaVelocity = palm.getRawVelocity(); - } - if (!(palm.getLastControllerButtons() & BUTTON_4) && (palm.getControllerButtons() & BUTTON_4)) { - // Just starting grab, capture starting rotation - _grabStartRotation = palm.getRawRotation(); - } - if (palm.getControllerButtons() & BUTTON_1) { if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value(); diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index aec5cdb921..c2f49a15e5 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -58,11 +58,6 @@ public: const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} - // Get the drag distance to move - glm::vec3 getAndResetGrabDelta(); - glm::vec3 getAndResetGrabDeltaVelocity(); - glm::quat getAndResetGrabRotation(); - private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); @@ -96,11 +91,6 @@ private: void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); - - glm::vec3 _grabDelta; - glm::vec3 _grabDeltaVelocity; - glm::quat _grabStartRotation; - glm::quat _grabCurrentRotation; }; #endif diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4eec6e70f8..eab2207bd9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -323,22 +323,6 @@ void MyAvatar::simulate(float deltaTime) { updateChatCircle(deltaTime); - // TODO: this should be removed and turned into JS instead - // Get any position, velocity, or rotation update from Grab Drag controller - glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta(); - if (glm::length(moveFromGrab) > EPSILON) { - _position += moveFromGrab; - _velocity = glm::vec3(0, 0, 0); - } - _velocity += _hand.getAndResetGrabDeltaVelocity(); - glm::quat deltaRotation = _hand.getAndResetGrabRotation(); - const float GRAB_CONTROLLER_TURN_SCALING = 0.5f; - glm::vec3 euler = safeEulerAngles(deltaRotation) * GRAB_CONTROLLER_TURN_SCALING; - // Adjust body yaw by yaw from controller - setOrientation(glm::angleAxis(-euler.y, glm::vec3(0, 1, 0)) * getOrientation()); - // Adjust head pitch from controller - getHead().setPitch(getHead().getPitch() - euler.x); - _position += _velocity * deltaTime; // update avatar skeleton and simulate hand and head diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 4fad5f6edc..d9878d0b71 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -12,6 +12,7 @@ #include #include +#include #include "EventTypes.h" @@ -37,6 +38,7 @@ public slots: virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0; virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0; virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0; + virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0; virtual void captureKeyEvents(const KeyEvent& event) = 0; virtual void releaseKeyEvents(const KeyEvent& event) = 0; diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index dceb1e40df..2f1c39f9e3 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -9,6 +9,8 @@ // // +#include + #include #include #include "Quat.h" @@ -25,6 +27,11 @@ glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll))); } +glm::quat Quat::inverse(const glm::quat& q) { + return glm::inverse(q); +} + + glm::vec3 Quat::getFront(const glm::quat& orientation) { return orientation * IDENTITY_FRONT; } @@ -38,5 +45,10 @@ glm::vec3 Quat::getUp(const glm::quat& orientation) { } glm::vec3 Quat::safeEulerAngles(const glm::quat& orientation) { - return safeEulerAngles(orientation); + return ::safeEulerAngles(orientation); } + +glm::quat Quat::angleAxis(float angle, const glm::vec3& v) { + return glm::angleAxis(angle, v); +} + diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 7e29c41833..985dd0a00f 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -23,10 +23,12 @@ public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); glm::quat fromVec3(const glm::vec3& vec3); glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); + glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); glm::vec3 getUp(const glm::quat& orientation); glm::vec3 safeEulerAngles(const glm::quat& orientation); + glm::quat angleAxis(float angle, const glm::vec3& v); }; diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 87b1b510a4..2d6a5b2316 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -19,6 +19,14 @@ glm::vec3 Vec3::multiply(const glm::vec3& v1, float f) { return v1 * f; } +glm::vec3 Vec3::multiplyQbyV(const glm::quat& q, const glm::vec3& v) { + return q * v; +} + glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; } + +float Vec3::length(const glm::vec3& v) { + return glm::length(v); +} diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 1cc44f3061..bf883f3e5a 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -23,7 +23,9 @@ class Vec3 : public QObject { public slots: glm::vec3 multiply(const glm::vec3& v1, const glm::vec3& v2); glm::vec3 multiply(const glm::vec3& v1, float f); + glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v); glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2); + float length(const glm::vec3& v); }; From 49292a478e92435e5baa672d318ed55a4940a891 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 10 Feb 2014 17:28:24 -0800 Subject: [PATCH 09/41] =?UTF-8?q?EditVoxels.js:=20Added=20new=20voxel=20ma?= =?UTF-8?q?king=20in=20front=20of=20camera=20with=20=E2=80=989=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/editVoxels.js | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 7210a07e1b..81f5e09ddd 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -11,6 +11,7 @@ // right click or control + click = delete this voxel // shift + click = recolor this voxel // 1 - 8 = pick new color from palette +// 9 = create a new voxel in front of the camera // // Click and drag to create more new voxels in the same direction // @@ -24,6 +25,9 @@ function vMinus(a, b) { return rval; } +var NEW_VOXEL_SIZE = 1.0; +var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; + var key_alt = false; var key_shift = false; var isAdding = false; @@ -54,12 +58,23 @@ var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-publ var audioOptions = new AudioInjectionOptions();
 audioOptions.volume = 0.5; +function setAudioPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + audioOptions.position = Vec3.sum(camera, forwardVector); +} + +function getNewVoxelPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA)); + return newPosition; +} + function mousePressEvent(event) { var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - audioOptions.position = { x: pickRay.origin.x + pickRay.direction.x, - y: pickRay.origin.y + pickRay.direction.y, - z: pickRay.origin.z + pickRay.direction.z }; + audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); if (intersection.intersects) { if (event.isRightButton || event.isControl) { @@ -136,6 +151,22 @@ function keyPressEvent(event) { whichColor = nVal - 1; print("Color = " + (whichColor + 1)); Audio.playSound(clickSound, audioOptions); + } else if (event.text == "9") { + // Create a brand new 1 meter voxel in front of your avatar + var color = whichColor; + if (color == -1) color = 0; + var newPosition = getNewVoxelPosition(); + var newVoxel = { + x: newPosition.x, + y: newPosition.y , + z: newPosition.z, + s: NEW_VOXEL_SIZE, + red: colors[color].red, + green: colors[color].green, + blue: colors[color].blue }; + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); + setAudioPosition(); + Audio.playSound(addSound, audioOptions); } } From 4b5e633258bd293ad8b0b936b275639fa6522690 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 19:48:51 -0800 Subject: [PATCH 10/41] tweaks to hydraMove.js, added scale to MyAvatar JS --- examples/hydraMove.js | 178 +++++++++++++++++------------ libraries/avatars/src/AvatarData.h | 1 + 2 files changed, 109 insertions(+), 70 deletions(-) diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 252d3c7756..6223e6fe2c 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -1,8 +1,8 @@ // -// hydraThrustAndView.js +// hydraMove.js // hifi // -// Created by Brad Hefta-Gaub on 2/6/14. +// Created by Brad Hefta-Gaub on 2/10/14. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // // This is an example script that demonstrates use of the Controller and MyAvatar classes to implement @@ -27,8 +27,21 @@ var grabbingWithRightHand = false; var wasGrabbingWithRightHand = false; var grabbingWithLeftHand = false; var wasGrabbingWithLeftHand = false; -var EPSILON = 0.000001; //smallish positive number - used as margin of error for some computations +var EPSILON = 0.000001; var velocity = { x: 0, y: 0, z: 0}; +var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call +var THRUST_MAG_UP = 800.0; +var THRUST_MAG_DOWN = 300.0; +var THRUST_MAG_FWD = 500.0; +var THRUST_MAG_BACK = 300.0; +var THRUST_MAG_LATERAL = 250.0; +var THRUST_JUMP = 120.0; + +var YAW_MAG = 500.0; +var PITCH_MAG = 100.0; +var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; +var JOYSTICK_YAW_MAG = YAW_MAG; +var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5; var LEFT_PALM = 0; @@ -36,6 +49,7 @@ var LEFT_BUTTON_4 = 4; var RIGHT_PALM = 2; var RIGHT_BUTTON_4 = 10; +// Used by handleGrabBehavior() for managing the grab position changes function getAndResetGrabDelta() { var HAND_GRAB_SCALE_DISTANCE = 2.0; var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE)); @@ -45,8 +59,9 @@ function getAndResetGrabDelta() { return result; } +// Used by handleGrabBehavior() for managing the grab velocity feature function getAndResetGrabDeltaVelocity() { - var HAND_GRAB_SCALE_VELOCITY = 5.0; + var HAND_GRAB_SCALE_VELOCITY = 50.0; var delta = Vec3.multiply(grabDeltaVelocity, (MyAvatar.scale * HAND_GRAB_SCALE_VELOCITY)); grabDeltaVelocity = { x: 0, y: 0, z: 0}; var avatarRotation = MyAvatar.orientation; @@ -54,28 +69,96 @@ function getAndResetGrabDeltaVelocity() { return result; } +// Used by handleGrabBehavior() for managing the grab rotation feature function getAndResetGrabRotation() { var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation)); grabStartRotation = grabCurrentRotation; return quatDiff; } +// handles all the grab related behavior: position (crawl), velocity (flick), and rotate (twist) +function handleGrabBehavior() { + // check for and handle grab behaviors + grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4); + grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4); + stoppedGrabbingWithLeftHand = false; + stoppedGrabbingWithRightHand = false; + + if (grabbingWithRightHand && !wasGrabbingWithRightHand) { + // Just starting grab, capture starting rotation + grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + if (grabbingWithRightHand) { + grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime)); + grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + if (!grabbingWithRightHand && wasGrabbingWithRightHand) { + // Just ending grab, capture velocity + grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM); + stoppedGrabbingWithRightHand = true; + } + + if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) { + // Just starting grab, capture starting rotation + grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM); + } + + if (grabbingWithLeftHand) { + grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(LEFT_PALM), deltaTime)); + grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM); + } + if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) { + // Just ending grab, capture velocity + grabDeltaVelocity = Controller.getSpatialControlVelocity(LEFT_PALM); + stoppedGrabbingWithLeftHand = true; + } + + grabbing = grabbingWithRightHand || grabbingWithLeftHand; + stoppedGrabbing = stoppedGrabbingWithRightHand || stoppedGrabbingWithLeftHand; + + if (grabbing) { + + // move position + var moveFromGrab = getAndResetGrabDelta(); + if (Vec3.length(moveFromGrab) > EPSILON) { + MyAvatar.position = Vec3.sum(MyAvatar.position, moveFromGrab); + velocity = { x: 0, y: 0, z: 0}; + } + + // add some rotation... + var deltaRotation = getAndResetGrabRotation(); + var GRAB_CONTROLLER_TURN_SCALING = 0.5; + var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING); + + // Adjust body yaw by yaw from controller + var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation); + MyAvatar.orientation = orientation; + + // Adjust head pitch from controller + MyAvatar.headPitch = MyAvatar.headPitch - euler.x; + } + + //print("velocity=" +velocity.x +"," +velocity.y +"," +velocity.z + " length=" + Vec3.length(velocity)); + + // add some velocity... + if (stoppedGrabbing) { + velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity()); + } + + // handle residual velocity + if(Vec3.length(velocity) > EPSILON) { + MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(velocity, deltaTime)); + // damp velocity + velocity = Vec3.multiply(velocity, damping); + } + + + wasGrabbingWithRightHand = grabbingWithRightHand; + wasGrabbingWithLeftHand = grabbingWithLeftHand; +} + +// Main update function that handles flying and grabbing behaviort function flyWithHydra() { - var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call - var THRUST_MAG_UP = 800.0; - var THRUST_MAG_DOWN = 300.0; - var THRUST_MAG_FWD = 500.0; - var THRUST_MAG_BACK = 300.0; - var THRUST_MAG_LATERAL = 250.0; - var THRUST_JUMP = 120.0; - var scale = 1.0; - - var YAW_MAG = 500.0; - var PITCH_MAG = 100.0; - var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; - var JOYSTICK_YAW_MAG = YAW_MAG; - var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5; - var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER); if (thrustJoystickPosition.x != 0 || thrustJoystickPosition.y != 0) { @@ -88,9 +171,11 @@ function flyWithHydra() { var right = Quat.getRight(currentOrientation); var up = Quat.getUp(currentOrientation); - var thrustFront = Vec3.multiply(front, scale * THRUST_MAG_HAND_JETS * thrustJoystickPosition.y * thrustMultiplier * deltaTime); + var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS * + thrustJoystickPosition.y * thrustMultiplier * deltaTime); MyAvatar.addThrust(thrustFront); - var thrustRight = Vec3.multiply(right, scale * THRUST_MAG_HAND_JETS * thrustJoystickPosition.x * thrustMultiplier * deltaTime); + var thrustRight = Vec3.multiply(right, MyAvatar.scale * THRUST_MAG_HAND_JETS * + thrustJoystickPosition.x * thrustMultiplier * deltaTime); MyAvatar.addThrust(thrustRight); } else { thrustMultiplier = INITIAL_THRUST_MULTPLIER; @@ -110,56 +195,9 @@ function flyWithHydra() { var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime); MyAvatar.headPitch = newPitch; } - - // check for and handle grab behaviors - grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4); - grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4); - - if (grabbingWithRightHand) { - grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime)); - grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); - } - if (!grabbingWithRightHand && wasGrabbingWithRightHand) { - // Just ending grab, capture velocity - grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM); - } - if (grabbingWithRightHand && !wasGrabbingWithRightHand) { - // Just starting grab, capture starting rotation - grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); - } - - grabbing = grabbingWithRightHand || grabbingWithLeftHand; - - if (grabbing) { - - // move position - var moveFromGrab = getAndResetGrabDelta(); - if (Vec3.length(moveFromGrab) > EPSILON) { - position = Vec3.sum(position, moveFromGrab); - velocity = { x: 0, y: 0, z: 0}; - } - - // add some velocity... - velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity()); - - // add some rotation... - var deltaRotation = getAndResetGrabRotation(); - var GRAB_CONTROLLER_TURN_SCALING = 0.5; - var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING); - - // Adjust body yaw by yaw from controller - var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation); - MyAvatar.orientation = orientation; - - // Adjust head pitch from controller - //getHead().setPitch(getHead().getPitch() - euler.x); - MyAvatar.headPitch = MyAvatar.headPitch - euler.x; - } - - wasGrabbingWithRightHand = grabbingWithRightHand; - wasGrabbingWithLeftHand = grabbingWithLeftHand; + handleGrabBehavior(); } - + Script.willSendVisualDataCallback.connect(flyWithHydra); Controller.captureJoystick(THRUST_CONTROLLER); Controller.captureJoystick(VIEW_CONTROLLER); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 46d92c0f2e..08604a95f1 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -67,6 +67,7 @@ class AvatarData : public NodeData { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale) Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) From 4b2ddc90214b2400f2871b9ac3cbd0e338ab0282 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 19:53:34 -0800 Subject: [PATCH 11/41] remove dead comment --- examples/hydraMove.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 6223e6fe2c..6ce0ad884e 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -138,8 +138,6 @@ function handleGrabBehavior() { MyAvatar.headPitch = MyAvatar.headPitch - euler.x; } - //print("velocity=" +velocity.x +"," +velocity.y +"," +velocity.z + " length=" + Vec3.length(velocity)); - // add some velocity... if (stoppedGrabbing) { velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity()); From 9244180cb45ca69175ad7f99e53971c4e85a7a2c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 10 Feb 2014 20:27:39 -0800 Subject: [PATCH 12/41] removed debug --- examples/cameraExample.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/cameraExample.js b/examples/cameraExample.js index 65cffb17dd..d55f376b76 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -75,7 +75,6 @@ function checkCamera() { if (yaw < -360) { yaw += 360; } - print("pitch="+ pitch + " yaw="+ yaw + " roll=" + roll); var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); Camera.setOrientation(orientation); } From 7840b351dd65d4ba8aba1155bb2cb06326ca5a54 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 08:43:56 -0800 Subject: [PATCH 13/41] Fix for #1968: head does not roll --- interface/src/avatar/FaceModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index b9803c17cd..b041f5bc2d 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -58,7 +58,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation))); - state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) * + state.rotation = glm::angleAxis(-_owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) * glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) * glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation; } From 861778347f615b843c13b4040270e6cfb2990dd4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 08:54:40 -0800 Subject: [PATCH 14/41] Fixing windows compile warnings about signed vs unsigned compare. --- interface/src/avatar/Hand.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index c2ea3f8f31..53f023f370 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -223,7 +223,7 @@ void Hand::updateCollisions() { } } if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { - for (size_t j = 0; j < collisions.size(); ++j) { + for (int j = 0; j < collisions.size(); ++j) { if (!avatar->poke(collisions[j])) { totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } @@ -240,7 +240,7 @@ void Hand::updateCollisions() { skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { - for (size_t j = 0; j < collisions.size(); ++j) { + for (int j = 0; j < collisions.size(); ++j) { totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } From 887fa0c93888bf054365b138ead8ab95070a3d21 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 09:23:40 -0800 Subject: [PATCH 15/41] Only resolve our hand collisions that would not move the other avatar. This helps us only penetrate the moveable parts of other avatars. --- interface/src/avatar/Avatar.cpp | 11 +++++++++-- interface/src/avatar/Avatar.h | 3 +++ interface/src/avatar/Hand.cpp | 3 ++- interface/src/renderer/Model.cpp | 14 ++++++++++++++ interface/src/renderer/Model.h | 3 +++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c299c0c617..9cb69e170e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -443,9 +443,16 @@ float Avatar::getHeight() const { return extents.maximum.y - extents.minimum.y; } -bool Avatar::poke(ModelCollisionInfo& collision) { - // ATM poke() can only affect the Skeleton (not the head) +bool Avatar::isPokeable(ModelCollisionInfo& collision) const { + // ATM only the Skeleton is pokeable // TODO: make poke affect head + if (collision._model == &_skeletonModel && collision._jointIndex != -1) { + return _skeletonModel.isPokeable(collision); + } + return false; +} + +bool Avatar::poke(ModelCollisionInfo& collision) { if (collision._model == &_skeletonModel && collision._jointIndex != -1) { return _skeletonModel.poke(collision); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 8290115240..7e8a1d8f64 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -128,6 +128,9 @@ public: float getHeight() const; + /// \return true if we expect the avatar would move as a result of the collision + bool isPokeable(ModelCollisionInfo& collision) const; + /// \param collision a data structure for storing info about collisions against Models /// \return true if the collision affects the Avatar models bool poke(ModelCollisionInfo& collision); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 53f023f370..4dac42a02e 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -224,7 +224,8 @@ void Hand::updateCollisions() { } if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { for (int j = 0; j < collisions.size(); ++j) { - if (!avatar->poke(collisions[j])) { + // we don't resolve penetrations that would poke the other avatar + if (!avatar->isPokeable(collisions[j])) { totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e1652b1237..b74882de5f 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -713,6 +713,20 @@ void Model::renderCollisionProxies(float alpha) { glPopMatrix(); } +bool Model::isPokeable(ModelCollisionInfo& collision) const { + // the joint is pokable by a collision if it exists and is free to move + const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex]; + if (joint.parentIndex == -1 || + _jointStates.isEmpty()) + { + return false; + } + // an empty freeLineage means the joint can't move + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const QVector& freeLineage = geometry.joints.at(collision._jointIndex).freeLineage; + return !freeLineage.isEmpty(); +} + bool Model::poke(ModelCollisionInfo& collision) { // This needs work. At the moment it can wiggle joints that are free to move (such as arms) // but unmovable joints (such as torso) cannot be influenced at all. diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f99e46c5f4..9ef9625b01 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -164,6 +164,9 @@ public: void renderCollisionProxies(float alpha); + /// \return true if the collision would move the model + bool isPokeable(ModelCollisionInfo& collision) const; + /// \param collisionInfo info about the collision /// \return true if collision affects the Model bool poke(ModelCollisionInfo& collisionInfo); From 6e31f1692437095894dd4edc301cb158e467e01c Mon Sep 17 00:00:00 2001 From: stojce Date: Tue, 11 Feb 2014 19:25:03 +0100 Subject: [PATCH 16/41] fix for Firefox --- interface/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 846df5e493..8e96006828 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -95,6 +95,8 @@ if (APPLE) SET_TARGET_PROPERTIES( ${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in ) set(MACOSX_BUNDLE_BUNDLE_NAME Interface) + set(MACOSX_BUNDLE_GUI_IDENTIFIER io.highfidelity.Interface) + # set how the icon shows up in the Info.plist file SET(MACOSX_BUNDLE_ICON_FILE interface.icns) From 1fca763b9d5ebca51913fe754d67d891678b14b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Feb 2014 12:43:48 -0800 Subject: [PATCH 17/41] removed whitespace to get build to run --- libraries/script-engine/src/Quat.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 985dd0a00f..867069d6d6 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -31,6 +31,4 @@ public slots: glm::quat angleAxis(float angle, const glm::vec3& v); }; - - #endif /* defined(__hifi__Quat__) */ From d0f9b7871062be9ea6590b2893987c8d87dc574e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 13:48:48 -0800 Subject: [PATCH 18/41] Adding avatar body-body collisions to prevent near-clipping. --- interface/src/avatar/MyAvatar.cpp | 66 +++++++++++++++++++++++++--- interface/src/renderer/FBXReader.cpp | 9 ++++ interface/src/renderer/FBXReader.h | 1 + interface/src/renderer/Model.cpp | 9 ++++ interface/src/renderer/Model.h | 3 ++ 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5628740770..5a4512419d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -225,8 +225,6 @@ void MyAvatar::simulate(float deltaTime) { updateCollisionWithVoxels(deltaTime, radius); } if (_collisionFlags & COLLISION_GROUP_AVATARS) { - // Note, hand-vs-avatar collisions are done elsewhere - // This is where we avatar-vs-avatar bounding capsule updateCollisionWithAvatars(deltaTime); } } @@ -974,7 +972,43 @@ void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTim } } -const float DEFAULT_HAND_RADIUS = 0.1f; +bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float heightA, + const glm::vec3 positionB, float radiusB, float heightB, glm::vec3& penetration) { + glm::vec3 positionBA = positionB - positionA; + float xzDistance = sqrt(positionBA.x * positionBA.x + positionBA.z * positionBA.z); + if (xzDistance < (radiusA + radiusB)) { + float yDistance = fabs(positionBA.y); + float halfHeights = 0.5 * (heightA + heightB); + if (yDistance < halfHeights) { + // cylinders collide + if (xzDistance > 0.f) { + positionBA.y = 0.f; + // note, penetration should point from A into B + penetration = positionBA * ((radiusA + radiusB - xzDistance) / xzDistance); + return true; + } else { + // exactly coaxial -- we'll return false for this case + return false; + } + } else if (yDistance < halfHeights + radiusA + radiusB) { + // caps collide + if (positionBA.y < 0.f) { + // A is above B + positionBA.y += halfHeights; + float BA = glm::length(positionBA); + penetration = positionBA * (radiusA + radiusB - BA) / BA; + return true; + } else { + // A is below B + positionBA.y -= halfHeights; + float BA = glm::length(positionBA); + penetration = positionBA * (radiusA + radiusB - BA) / BA; + return true; + } + } + } + return false; +} void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // Reset detector for nearest avatar @@ -984,7 +1018,14 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // no need to compute a bunch of stuff if we have one or fewer avatars return; } - float myRadius = getHeight(); + float myBoundingRadius = 0.5f * getHeight(); + + // HACK: body-body collision uses two coaxial capsules with axes parallel to y-axis + // TODO: make the collision work without assuming avatar orientation + Extents myStaticExtents = _skeletonModel.getStaticExtents(); + glm::vec3 staticScale = myStaticExtents.maximum - myStaticExtents.minimum; + float myCapsuleRadius = 0.25f * (staticScale.x + staticScale.z); + float myCapsuleHeight = staticScale.y; CollisionInfo collisionInfo; foreach (const AvatarSharedPointer& avatarPointer, avatars) { @@ -997,9 +1038,20 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { if (_distanceToNearestAvatar > distance) { _distanceToNearestAvatar = distance; } - float theirRadius = avatar->getHeight(); - if (distance < myRadius + theirRadius) { - // TODO: Andrew to make avatar-avatar capsule collisions work here + float theirBoundingRadius = 0.5f * avatar->getHeight(); + if (distance < myBoundingRadius + theirBoundingRadius) { + Extents theirStaticExtents = _skeletonModel.getStaticExtents(); + glm::vec3 staticScale = theirStaticExtents.maximum - theirStaticExtents.minimum; + float theirCapsuleRadius = 0.25f * (staticScale.x + staticScale.z); + float theirCapsuleHeight = staticScale.y; + + glm::vec3 penetration(0.f); + if (findAvatarAvatarPenetration(_position, myCapsuleRadius, myCapsuleHeight, + avatar->getPosition(), theirCapsuleRadius, theirCapsuleHeight, penetration)) { + // move the avatar out by half the penetration + setPosition(_position - 0.5f * penetration); + glm::vec3 pushOut = 0.5f * penetration; + } } } } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 237ba7196d..b0bdf420f2 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1268,6 +1268,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) geometry.bindExtents.minimum = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX); geometry.bindExtents.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + geometry.staticExtents.minimum = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX); + geometry.staticExtents.maximum = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); QVariantHash springs = mapping.value("spring").toHash(); QVariant defaultSpring = springs.value("default"); @@ -1424,6 +1426,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) boneDirection /= boneLength; } } + bool jointIsStatic = joint.freeLineage.isEmpty(); + glm::vec3 jointTranslation = extractTranslation(geometry.offset * joint.bindTransform); float radiusScale = extractUniformScale(joint.transform * fbxCluster.inverseBindMatrix); float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { @@ -1441,6 +1445,11 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) joint.boneRadius = glm::max(joint.boneRadius, radiusScale * glm::distance( vertex, boneEnd + boneDirection * proj)); } + if (jointIsStatic) { + // expand the extents of static (nonmovable) joints + geometry.staticExtents.minimum = glm::min(geometry.staticExtents.minimum, vertex + jointTranslation); + geometry.staticExtents.maximum = glm::max(geometry.staticExtents.maximum, vertex + jointTranslation); + } } // look for an unused slot in the weights vector diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index d700439460..eb4c5bac41 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -159,6 +159,7 @@ public: glm::vec3 neckPivot; Extents bindExtents; + Extents staticExtents; QVector attachments; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b74882de5f..ae1fb203d1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -305,6 +305,15 @@ Extents Model::getBindExtents() const { return scaledExtents; } +Extents Model::getStaticExtents() const { + if (!isActive()) { + return Extents(); + } + const Extents& staticExtents = _geometry->getFBXGeometry().staticExtents; + Extents scaledExtents = { staticExtents.minimum * _scale, staticExtents.maximum * _scale }; + return scaledExtents; +} + int Model::getParentJointIndex(int jointIndex) const { return (isActive() && jointIndex != -1) ? _geometry->getFBXGeometry().joints.at(jointIndex).parentIndex : -1; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 9ef9625b01..ddf80b8b21 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -66,6 +66,9 @@ public: /// Returns the extents of the model in its bind pose. Extents getBindExtents() const; + + /// Returns the extents of the unmovable joints of the model. + Extents getStaticExtents() const; /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } From 6c4ecb024654aadf9764a8cf427d9f5c3b00c675 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 14:38:31 -0800 Subject: [PATCH 19/41] Splitting hand collisions between other avatars and ourself. --- interface/src/avatar/Hand.cpp | 149 ++++++++++++++++-------------- interface/src/avatar/Hand.h | 3 + interface/src/avatar/MyAvatar.cpp | 3 + 3 files changed, 88 insertions(+), 67 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4dac42a02e..b62e88289f 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -167,91 +167,106 @@ void Hand::simulate(float deltaTime, bool isMine) { } void Hand::updateCollisions() { - // use position to obtain the left and right palm indices - int leftPalmIndex, rightPalmIndex; - getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - + collideAgainstOtherAvatars(); + collideAgainstOurself(); +} + +void Hand::collideAgainstOtherAvatars() { + if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { + return; + } ModelCollisionList collisions; - // check for collisions + float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; if (!palm.isActive()) { continue; } - float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); glm::vec3 totalPenetration; - - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { - // check other avatars - foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (avatar == _owningAvatar) { - // don't collid with our own hands - continue; - } - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { - // Check for palm collisions - glm::vec3 myPalmPosition = palm.getPosition(); - float palmCollisionDistance = 0.1f; - bool wasColliding = palm.getIsCollidingWithPalm(); - palm.setIsCollidingWithPalm(false); - // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound - for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { - PalmData& otherPalm = avatar->getHand().getPalms()[j]; - if (!otherPalm.isActive()) { - continue; - } - glm::vec3 otherPalmPosition = otherPalm.getPosition(); - if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { - palm.setIsCollidingWithPalm(true); - if (!wasColliding) { - const float PALM_COLLIDE_VOLUME = 1.f; - const float PALM_COLLIDE_FREQUENCY = 1000.f; - const float PALM_COLLIDE_DURATION_MAX = 0.75f; - const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; - Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, - PALM_COLLIDE_FREQUENCY, - PALM_COLLIDE_DURATION_MAX, - PALM_COLLIDE_DECAY_PER_SAMPLE); - // If the other person's palm is in motion, move mine downward to show I was hit - const float MIN_VELOCITY_FOR_SLAP = 0.05f; - if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { - // add slapback here - } + // check other avatars + foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { + Avatar* avatar = static_cast(avatarPointer.data()); + if (avatar == _owningAvatar) { + // don't collid with our own hands + continue; + } + collisions.clear(); + if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + // Check for palm collisions + glm::vec3 myPalmPosition = palm.getPosition(); + float palmCollisionDistance = 0.1f; + bool wasColliding = palm.getIsCollidingWithPalm(); + palm.setIsCollidingWithPalm(false); + // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound + for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { + PalmData& otherPalm = avatar->getHand().getPalms()[j]; + if (!otherPalm.isActive()) { + continue; + } + glm::vec3 otherPalmPosition = otherPalm.getPosition(); + if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { + palm.setIsCollidingWithPalm(true); + if (!wasColliding) { + const float PALM_COLLIDE_VOLUME = 1.f; + const float PALM_COLLIDE_FREQUENCY = 1000.f; + const float PALM_COLLIDE_DURATION_MAX = 0.75f; + const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; + Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, + PALM_COLLIDE_FREQUENCY, + PALM_COLLIDE_DURATION_MAX, + PALM_COLLIDE_DECAY_PER_SAMPLE); + // If the other person's palm is in motion, move mine downward to show I was hit + const float MIN_VELOCITY_FOR_SLAP = 0.05f; + if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { + // add slapback here } } } } - if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { - for (int j = 0; j < collisions.size(); ++j) { - // we don't resolve penetrations that would poke the other avatar - if (!avatar->isPokeable(collisions[j])) { - totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); - } + } + if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { + for (int j = 0; j < collisions.size(); ++j) { + // we don't resolve penetrations that would poke the other avatar + if (!avatar->isPokeable(collisions[j])) { + totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } } } - - if (Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { - // and the current avatar (ignoring everything below the parent of the parent of the last free joint) - collisions.clear(); - const Model& skeletonModel = _owningAvatar->getSkeletonModel(); - int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( - skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : - (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); - if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { - for (int j = 0; j < collisions.size(); ++j) { - totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); - } + // resolve penetration + palm.addToPosition(-totalPenetration); + } +} + +void Hand::collideAgainstOurself() { + if (!Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { + return; + } + + ModelCollisionList collisions; + int leftPalmIndex, rightPalmIndex; + getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); + float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); + + for (size_t i = 0; i < getNumPalms(); i++) { + PalmData& palm = getPalms()[i]; + if (!palm.isActive()) { + continue; + } + glm::vec3 totalPenetration; + // and the current avatar (ignoring everything below the parent of the parent of the last free joint) + collisions.clear(); + const Model& skeletonModel = _owningAvatar->getSkeletonModel(); + int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( + skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : + (i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); + if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { + for (int j = 0; j < collisions.size(); ++j) { + totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } - - // un-penetrate + // resolve penetration palm.addToPosition(-totalPenetration); - - // we recycle the collisions container, so we clear it for the next loop - collisions.clear(); } } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 3c8ec2d562..5a8e3d0e6f 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -97,6 +97,9 @@ private: void renderLeapFingerTrails(); void updateCollisions(); + void collideAgainstOtherAvatars(); + void collideAgainstOurself(); + void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5a4512419d..31437182bc 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1052,6 +1052,9 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { setPosition(_position - 0.5f * penetration); glm::vec3 pushOut = 0.5f * penetration; } + + // collide their hands against our movable limbs + } } } From b6edd7be7bb27302daba61b8b549b2c57ec641c3 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Feb 2014 15:07:25 -0800 Subject: [PATCH 20/41] add Vec3::subtract in JS --- examples/editVoxels.js | 52 ++++++++++++++++++++++++++-- libraries/script-engine/src/Vec3.cpp | 4 +++ libraries/script-engine/src/Vec3.h | 1 + 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 81f5e09ddd..cf7736c5bc 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -27,16 +27,30 @@ function vMinus(a, b) { var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; +var ORBIT_RATE_ALTITUDE = 100.0; +var ORBIT_RATE_AZIMUTH = 60.0; + +var oldMode = Camera.getMode(); var key_alt = false; var key_shift = false; var isAdding = false; +var isOrbiting = false; +var orbitAzimuth = 0.0; +var orbitAltitude = 0.0; +var orbitCenter = { x: 0, y: 0, z: 0 }; +var orbitPosition = { x: 0, y: 0, z: 0 }; +var orbitRadius = 0.0; var lastVoxelPosition = { x: 0, y: 0, z: 0 }; var lastVoxelColor = { red: 0, green: 0, blue: 0 }; var lastVoxelScale = 0; var dragStart = { x: 0, y: 0 }; +var mouseX = 0; +var mouseY = 0; + + // Create a table of the different colors you can choose var colors = new Array(); colors[0] = { red: 237, green: 175, blue: 0 }; @@ -72,12 +86,28 @@ function getNewVoxelPosition() { } function mousePressEvent(event) { + mouseX = event.x; + mouseY = event.y; var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); - if (intersection.intersects) { - if (event.isRightButton || event.isControl) { + if (event.isAlt) { + // start orbit camera! + oldMode = Camera.getMode(); + Camera.setMode("independent"); + isOrbiting = true; + Camera.keepLookingAt(intersection.intersection); + // get position for initial azimuth, elevation + orbitCenter = intersection.intersection; + var cameraPosition = Camera.getPosition(); + var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); + orbitRadius = vLength(orbitVector); + print("Orbit radius = " + orbitRadius); + orbitAzimuth = Math.atan(orbitVector.z / orbitVector.x); + orbitAltitude = Math.atan(orbitVector.y / orbitVector.x); + + } else if (event.isRightButton || event.isControl) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); @@ -175,6 +205,20 @@ function keyReleaseEvent(event) { key_shift = false; } function mouseMoveEvent(event) { + if (isOrbiting) { + var dx = event.x - mouseX; + var dy = event.y - mouseY; + orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; + orbitAltitude += dy / ORBIT_RATE_ALTITUDE; + //print("Azimuth, Altitude: " + orbitAzimuth + ", " + orbitAltitude); + var orbitVector = { x:(Math.cos(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius, + y:Math.sin(orbitAltitude) * orbitRadius, + z:(Math.sin(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius }; + orbitPosition = Vec3.sum(orbitCenter, orbitVector); + Camera.setPosition(orbitPosition); + mouseX = event.x; + mouseY = event.y; + } if (isAdding) { var pickRay = Camera.computePickRay(event.x, event.y); var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, @@ -218,6 +262,10 @@ function mouseMoveEvent(event) { function mouseReleaseEvent(event) { isAdding = false; + isOrbiting = false; + MyAvatar.position = orbitPosition; + Camera.stopLooking(); + Camera.setMode(oldMode); } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 87b1b510a4..6520e62a34 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -22,3 +22,7 @@ glm::vec3 Vec3::multiply(const glm::vec3& v1, float f) { glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; } + +glm::vec3 Vec3::subtract(const glm::vec3& v1, const glm::vec3& v2) { + return v1 - v2; +} diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 1cc44f3061..c6f05fb6aa 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -24,6 +24,7 @@ public slots: glm::vec3 multiply(const glm::vec3& v1, const glm::vec3& v2); glm::vec3 multiply(const glm::vec3& v1, float f); glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2); }; From 66dc4e17ad5b60ea1728dc6fd95e02731c315e6a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 11 Feb 2014 15:59:35 -0800 Subject: [PATCH 21/41] Fixing formatting to be KR --- interface/src/renderer/Model.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ae1fb203d1..32963cb703 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -725,9 +725,7 @@ void Model::renderCollisionProxies(float alpha) { bool Model::isPokeable(ModelCollisionInfo& collision) const { // the joint is pokable by a collision if it exists and is free to move const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex]; - if (joint.parentIndex == -1 || - _jointStates.isEmpty()) - { + if (joint.parentIndex == -1 || _jointStates.isEmpty()) { return false; } // an empty freeLineage means the joint can't move From 0322c8b9343a1bd84c7db865e656a0fe6ced28b4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Feb 2014 23:44:22 -0800 Subject: [PATCH 22/41] Added minimum sample counting method for noise reduction --- examples/editVoxels.js | 26 +++++++++++++++--------- interface/src/Audio.cpp | 45 +++++++++++++++++++++++++++++++++++++---- interface/src/Audio.h | 2 ++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index cf7736c5bc..62ce968180 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -65,10 +65,10 @@ var numColors = 8; var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels -var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw"); -var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw"); +var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh1.raw"); +var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh2.raw"); var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw"); -var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Collisions-ballhitsandcatches/ballcatch2.raw"); +var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); var audioOptions = new AudioInjectionOptions();
 audioOptions.volume = 0.5; @@ -94,18 +94,18 @@ function mousePressEvent(event) { if (intersection.intersects) { if (event.isAlt) { // start orbit camera! + var cameraPosition = Camera.getPosition(); oldMode = Camera.getMode(); Camera.setMode("independent"); isOrbiting = true; Camera.keepLookingAt(intersection.intersection); // get position for initial azimuth, elevation orbitCenter = intersection.intersection; - var cameraPosition = Camera.getPosition(); var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); orbitRadius = vLength(orbitVector); - print("Orbit radius = " + orbitRadius); orbitAzimuth = Math.atan(orbitVector.z / orbitVector.x); - orbitAltitude = Math.atan(orbitVector.y / orbitVector.x); + orbitAltitude = Math.atan(orbitVector.y / Math.sqrt(orbitVector.z * orbitVector.z + orbitVector.x * orbitVector.x)); + print("start: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); } else if (event.isRightButton || event.isControl) { // Delete voxel @@ -210,6 +210,7 @@ function mouseMoveEvent(event) { var dy = event.y - mouseY; orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; orbitAltitude += dy / ORBIT_RATE_ALTITUDE; + print("drag: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); //print("Azimuth, Altitude: " + orbitAzimuth + ", " + orbitAltitude); var orbitVector = { x:(Math.cos(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, @@ -261,11 +262,18 @@ function mouseMoveEvent(event) { } function mouseReleaseEvent(event) { + if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var eulers = Quat.safeEulerAngles(cameraOrientation); + Camera.stopLooking(); + print("pitch, yaw " + eulers.x + ", " + eulers.y); + MyAvatar.headPitch = eulers.x; + MyAvatar.bodyYaw = eulers.y; + MyAvatar.position = Camera.getPosition(); + Camera.setMode(oldMode); + } isAdding = false; isOrbiting = false; - MyAvatar.position = orbitPosition; - Camera.stopLooking(); - Camera.setMode(oldMode); } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6eee4453d4..22a1444f9f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -37,6 +37,8 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDI static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; +static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 100; + // Mute icon configration static const int ICON_SIZE = 24; static const int ICON_LEFT = 0; @@ -66,6 +68,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), _averageInputLoudness(0), + _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), _noiseGateFramesToClose(0), @@ -82,6 +85,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + // Create the noise sample array + _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; } void Audio::init(QGLWidget *parent) { @@ -355,9 +360,17 @@ void Audio::handleAudioInput() { float thisSample = 0; int samplesOverNoiseGate = 0; - const float NOISE_GATE_HEIGHT = 3.f; +#define NOISE_MIN_SAMPLE +#ifdef NOISE_MIN_SAMPLE + const float NOISE_GATE_HEIGHT = 12.f; const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 30; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; +#else + const float NOISE_GATE_HEIGHT = 6.f; + const int NOISE_GATE_WIDTH = 5; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; +#endif + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { thisSample = fabsf(monoAudioSamples[i]); @@ -368,8 +381,32 @@ void Audio::handleAudioInput() { } } _lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + //qDebug("%.1f", _lastInputLoudness); + +#ifdef NOISE_MIN_SAMPLE + _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + float smallestSample = MAXFLOAT; + for (int i = 0; i < NUMBER_OF_NOISE_SAMPLE_FRAMES; i++) { + if (_noiseSampleFrames[i] < smallestSample) { + smallestSample = _noiseSampleFrames[i]; + } + } + _averageInputLoudness = smallestSample; + _noiseGateSampleCounter = 0; + qDebug("smallest sample = %.1f", _averageInputLoudness); + } +#else + _noiseGateSampleCounter++; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + qDebug("average loudness = %.1f", _averageInputLoudness); + _noiseGateSampleCounter = 0; + } + const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds _averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness; +#endif + if (_noiseGateEnabled) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { @@ -487,7 +524,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { // we don't have any audio data left in the output buffer // we just starved - qDebug() << "Audio output just starved."; + //qDebug() << "Audio output just starved."; _ringBuffer.setIsStarved(true); _numFramesDisplayStarve = 10; } @@ -505,7 +542,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2))) { // starved and we don't have enough to start, keep waiting - qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; + //qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; } else { // We are either already playing back, or we have enough audio to start playing back. _ringBuffer.setIsStarved(false); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 88e2731006..5028024a0c 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -110,6 +110,8 @@ private: int16_t _jitterBufferSamples; float _lastInputLoudness; float _averageInputLoudness; + float* _noiseSampleFrames; + int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; int _noiseGateFramesToClose; From 04bc05cfe65a989994c987dbefcf27246ad97e44 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 12 Feb 2014 08:29:22 -0800 Subject: [PATCH 23/41] Moving hand-avatar collision trigger calls into MyAvatar Also renaming some methods in Model to be more descriptive. --- interface/src/avatar/Avatar.cpp | 9 ++- interface/src/avatar/Avatar.h | 5 +- interface/src/avatar/Hand.cpp | 101 +++++++++++++++--------------- interface/src/avatar/Hand.h | 7 +-- interface/src/avatar/MyAvatar.cpp | 9 ++- interface/src/renderer/Model.cpp | 7 +-- interface/src/renderer/Model.h | 8 +-- 7 files changed, 71 insertions(+), 75 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5b2a142ac2..487f72a1e5 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -445,20 +445,19 @@ float Avatar::getHeight() const { return extents.maximum.y - extents.minimum.y; } -bool Avatar::isPokeable(ModelCollisionInfo& collision) const { +bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const { // ATM only the Skeleton is pokeable // TODO: make poke affect head if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.isPokeable(collision); + return _skeletonModel.collisionHitsMoveableJoint(collision); } return false; } -bool Avatar::poke(ModelCollisionInfo& collision) { +void Avatar::applyCollision(ModelCollisionInfo& collision) { if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.poke(collision); + _skeletonModel.applyCollision(collision); } - return false; } float Avatar::getPelvisFloatingHeight() const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 7e8a1d8f64..2fc26a36b5 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -129,11 +129,10 @@ public: float getHeight() const; /// \return true if we expect the avatar would move as a result of the collision - bool isPokeable(ModelCollisionInfo& collision) const; + bool collisionWouldMoveAvatar(ModelCollisionInfo& collision) const; /// \param collision a data structure for storing info about collisions against Models - /// \return true if the collision affects the Avatar models - bool poke(ModelCollisionInfo& collision); + void applyCollision(ModelCollisionInfo& collision); public slots: void updateCollisionFlags(); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index b62e88289f..7e47b0a0d5 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -84,7 +84,6 @@ void Hand::simulate(float deltaTime, bool isMine) { if (isMine) { _buckyBalls.simulate(deltaTime); - updateCollisions(); } calculateGeometry(); @@ -166,16 +165,11 @@ void Hand::simulate(float deltaTime, bool isMine) { } } -void Hand::updateCollisions() { - collideAgainstOtherAvatars(); - collideAgainstOurself(); -} - -void Hand::collideAgainstOtherAvatars() { - if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { +void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { + if (!avatar || avatar == _owningAvatar) { + // don't collide with our own hands (that is done elsewhere) return; } - ModelCollisionList collisions; float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale(); for (size_t i = 0; i < getNumPalms(); i++) { PalmData& palm = getPalms()[i]; @@ -183,58 +177,61 @@ void Hand::collideAgainstOtherAvatars() { continue; } glm::vec3 totalPenetration; - // check other avatars - foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (avatar == _owningAvatar) { - // don't collid with our own hands - continue; - } - collisions.clear(); - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { - // Check for palm collisions - glm::vec3 myPalmPosition = palm.getPosition(); - float palmCollisionDistance = 0.1f; - bool wasColliding = palm.getIsCollidingWithPalm(); - palm.setIsCollidingWithPalm(false); - // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound - for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { - PalmData& otherPalm = avatar->getHand().getPalms()[j]; - if (!otherPalm.isActive()) { - continue; - } - glm::vec3 otherPalmPosition = otherPalm.getPosition(); - if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { - palm.setIsCollidingWithPalm(true); - if (!wasColliding) { - const float PALM_COLLIDE_VOLUME = 1.f; - const float PALM_COLLIDE_FREQUENCY = 1000.f; - const float PALM_COLLIDE_DURATION_MAX = 0.75f; - const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; - Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, - PALM_COLLIDE_FREQUENCY, - PALM_COLLIDE_DURATION_MAX, - PALM_COLLIDE_DECAY_PER_SAMPLE); - // If the other person's palm is in motion, move mine downward to show I was hit - const float MIN_VELOCITY_FOR_SLAP = 0.05f; - if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { - // add slapback here - } + ModelCollisionList collisions; + if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + // Check for palm collisions + glm::vec3 myPalmPosition = palm.getPosition(); + float palmCollisionDistance = 0.1f; + bool wasColliding = palm.getIsCollidingWithPalm(); + palm.setIsCollidingWithPalm(false); + // If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound + for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { + PalmData& otherPalm = avatar->getHand().getPalms()[j]; + if (!otherPalm.isActive()) { + continue; + } + glm::vec3 otherPalmPosition = otherPalm.getPosition(); + if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { + palm.setIsCollidingWithPalm(true); + if (!wasColliding) { + const float PALM_COLLIDE_VOLUME = 1.f; + const float PALM_COLLIDE_FREQUENCY = 1000.f; + const float PALM_COLLIDE_DURATION_MAX = 0.75f; + const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f; + Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME, + PALM_COLLIDE_FREQUENCY, + PALM_COLLIDE_DURATION_MAX, + PALM_COLLIDE_DECAY_PER_SAMPLE); + // If the other person's palm is in motion, move mine downward to show I was hit + const float MIN_VELOCITY_FOR_SLAP = 0.05f; + if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) { + // add slapback here } } } } - if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { - for (int j = 0; j < collisions.size(); ++j) { - // we don't resolve penetrations that would poke the other avatar - if (!avatar->isPokeable(collisions[j])) { + } + if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) { + for (int j = 0; j < collisions.size(); ++j) { + if (isMyHand) { + if (!avatar->collisionWouldMoveAvatar(collisions[j])) { + // we resolve the hand from collision when it belongs to MyAvatar AND the other Avatar is + // not expected to respond to the collision (hand hit unmovable part of their Avatar) totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } + } else { + // when this !isMyHand then avatar is MyAvatar and we apply the collision + // which might not do anything (hand hit unmovable part of MyAvatar) however + // we don't resolve the hand's penetration (we expect their simulation + // to do the right thing). + avatar->applyCollision(collisions[j]); } } } - // resolve penetration - palm.addToPosition(-totalPenetration); + if (isMyHand) { + // resolve penetration + palm.addToPosition(-totalPenetration); + } } } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 5a8e3d0e6f..9413d024c3 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -67,6 +67,9 @@ public: glm::vec3 getAndResetGrabDeltaVelocity(); glm::quat getAndResetGrabRotation(); + void collideAgainstAvatar(Avatar* avatar, bool isMyHand); + void collideAgainstOurself(); + private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); @@ -96,10 +99,6 @@ private: void renderLeapHands(bool isMine); void renderLeapFingerTrails(); - void updateCollisions(); - void collideAgainstOtherAvatars(); - void collideAgainstOurself(); - void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 31437182bc..e0d9db43aa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -344,6 +344,7 @@ void MyAvatar::simulate(float deltaTime) { _position += _velocity * deltaTime; // update avatar skeleton and simulate hand and head + _hand.collideAgainstOurself(); _hand.simulate(deltaTime, true); _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); @@ -1050,11 +1051,13 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { avatar->getPosition(), theirCapsuleRadius, theirCapsuleHeight, penetration)) { // move the avatar out by half the penetration setPosition(_position - 0.5f * penetration); - glm::vec3 pushOut = 0.5f * penetration; } - // collide their hands against our movable limbs - + // collide our hands against them + _hand.collideAgainstAvatar(avatar, true); + + // collide their hands against us + avatar->getHand().collideAgainstAvatar(this, false); } } } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index de48be8694..f899e76ef4 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -722,7 +722,7 @@ void Model::renderCollisionProxies(float alpha) { glPopMatrix(); } -bool Model::isPokeable(ModelCollisionInfo& collision) const { +bool Model::collisionHitsMoveableJoint(ModelCollisionInfo& collision) const { // the joint is pokable by a collision if it exists and is free to move const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex]; if (joint.parentIndex == -1 || @@ -736,7 +736,7 @@ bool Model::isPokeable(ModelCollisionInfo& collision) const { return !freeLineage.isEmpty(); } -bool Model::poke(ModelCollisionInfo& collision) { +void Model::applyCollision(ModelCollisionInfo& collision) { // This needs work. At the moment it can wiggle joints that are free to move (such as arms) // but unmovable joints (such as torso) cannot be influenced at all. glm::vec3 jointPosition(0.f); @@ -760,11 +760,10 @@ bool Model::poke(ModelCollisionInfo& collision) { getJointPosition(jointIndex, end); glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start); // try to move it - return setJointPosition(jointIndex, newEnd, -1, true); + setJointPosition(jointIndex, newEnd, -1, true); } } } - return false; } void Model::deleteGeometry() { diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 003cdfe3e5..bab25bed7a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -167,12 +167,12 @@ public: void renderCollisionProxies(float alpha); - /// \return true if the collision would move the model - bool isPokeable(ModelCollisionInfo& collision) const; + /// \return true if the collision is against a moveable joint + bool collisionHitsMoveableJoint(ModelCollisionInfo& collision) const; /// \param collisionInfo info about the collision - /// \return true if collision affects the Model - bool poke(ModelCollisionInfo& collisionInfo); + /// Use the collisionInfo to affect the model + void applyCollision(ModelCollisionInfo& collisionInfo); protected: From 3a807c1914077ce74ce5ad766b2acc18470b82e5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 17:57:52 -0800 Subject: [PATCH 24/41] comment out debugging spam, improved EditVoxels --- examples/editVoxels.js | 124 +++++++++++++++++++++++----------------- interface/src/Audio.cpp | 2 +- 2 files changed, 73 insertions(+), 53 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 62ce968180..c1f0c8dc49 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -27,21 +27,24 @@ function vMinus(a, b) { var NEW_VOXEL_SIZE = 1.0; var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; -var ORBIT_RATE_ALTITUDE = 100.0; -var ORBIT_RATE_AZIMUTH = 60.0; +var ORBIT_RATE_ALTITUDE = 200.0; +var ORBIT_RATE_AZIMUTH = 90.0; +var PIXELS_PER_EXTRUDE_VOXEL = 16; var oldMode = Camera.getMode(); var key_alt = false; var key_shift = false; var isAdding = false; +var isExtruding = false; var isOrbiting = false; var orbitAzimuth = 0.0; var orbitAltitude = 0.0; var orbitCenter = { x: 0, y: 0, z: 0 }; var orbitPosition = { x: 0, y: 0, z: 0 }; var orbitRadius = 0.0; - +var extrudeDirection = { x: 0, y: 0, z: 0 }; +var extrudeScale = 0.0; var lastVoxelPosition = { x: 0, y: 0, z: 0 }; var lastVoxelColor = { red: 0, green: 0, blue: 0 }; var lastVoxelScale = 0; @@ -51,6 +54,7 @@ var mouseX = 0; var mouseY = 0; + // Create a table of the different colors you can choose var colors = new Array(); colors[0] = { red: 237, green: 175, blue: 0 }; @@ -65,9 +69,9 @@ var numColors = 8; var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels -var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh1.raw"); -var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/slider+-+whoosh2.raw"); -var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw"); +var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create.raw"); +var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete.raw"); +var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit.raw"); var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); var audioOptions = new AudioInjectionOptions();
 audioOptions.volume = 0.5; @@ -85,6 +89,18 @@ function getNewVoxelPosition() { return newPosition; } +function fixEulerAngles(eulers) { + var rVal = { x: 0, y: 0, z: eulers.z }; + if (eulers.x >= 90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } else if (eulers.x <= -90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } + return rVal; +} + function mousePressEvent(event) { mouseX = event.x; mouseY = event.y; @@ -102,10 +118,9 @@ function mousePressEvent(event) { // get position for initial azimuth, elevation orbitCenter = intersection.intersection; var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); - orbitRadius = vLength(orbitVector); - orbitAzimuth = Math.atan(orbitVector.z / orbitVector.x); - orbitAltitude = Math.atan(orbitVector.y / Math.sqrt(orbitVector.z * orbitVector.z + orbitVector.x * orbitVector.x)); - print("start: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); + orbitRadius = vLength(orbitVector); + orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); + orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); } else if (event.isRightButton || event.isControl) { // Delete voxel @@ -197,6 +212,11 @@ function keyPressEvent(event) { Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); setAudioPosition(); Audio.playSound(addSound, audioOptions); + } else if (event.text == " ") { + // Reset my orientation! + var orientation = { x:0, y:0, z:0, w:1 }; + Camera.setOrientation(orientation); + MyAvatar.orientation = orientation; } } @@ -206,57 +226,57 @@ function keyReleaseEvent(event) { } function mouseMoveEvent(event) { if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var origEulers = Quat.safeEulerAngles(cameraOrientation); + var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); var dx = event.x - mouseX; var dy = event.y - mouseY; orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; orbitAltitude += dy / ORBIT_RATE_ALTITUDE; - print("drag: radius, azimuth, altitude = " + orbitRadius + ", " + orbitAzimuth + ", " + orbitAltitude); - //print("Azimuth, Altitude: " + orbitAzimuth + ", " + orbitAltitude); - var orbitVector = { x:(Math.cos(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius, + var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, y:Math.sin(orbitAltitude) * orbitRadius, - z:(Math.sin(orbitAzimuth) * Math.cos(orbitAltitude)) * orbitRadius }; + z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; orbitPosition = Vec3.sum(orbitCenter, orbitVector); Camera.setPosition(orbitPosition); mouseX = event.x; mouseY = event.y; } if (isAdding) { - var pickRay = Camera.computePickRay(event.x, event.y); - var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, + // Watch the drag direction to tell which way to 'extrude' this voxel + if (!isExtruding) { + var pickRay = Camera.computePickRay(event.x, event.y); + var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, y: pickRay.origin.y - lastVoxelPosition.y, z: pickRay.origin.z - lastVoxelPosition.z }; - var distance = vLength(lastVoxelDistance); - var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; - mouseSpot.x += pickRay.origin.x; - mouseSpot.y += pickRay.origin.y; - mouseSpot.z += pickRay.origin.z; - var dx = mouseSpot.x - lastVoxelPosition.x; - var dy = mouseSpot.y - lastVoxelPosition.y; - var dz = mouseSpot.z - lastVoxelPosition.z; - if (dx > lastVoxelScale) { - lastVoxelPosition.x += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dx < -lastVoxelScale) { - lastVoxelPosition.x -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy > lastVoxelScale) { - lastVoxelPosition.y += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy < -lastVoxelScale) { - lastVoxelPosition.y -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz > lastVoxelScale) { - lastVoxelPosition.z += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz < -lastVoxelScale) { - lastVoxelPosition.z -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + var distance = vLength(lastVoxelDistance); + var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; + mouseSpot.x += pickRay.origin.x; + mouseSpot.y += pickRay.origin.y; + mouseSpot.z += pickRay.origin.z; + var dx = mouseSpot.x - lastVoxelPosition.x; + var dy = mouseSpot.y - lastVoxelPosition.y; + var dz = mouseSpot.z - lastVoxelPosition.z; + extrudeScale = lastVoxelScale; + extrudeDirection = { x: 0, y: 0, z: 0 }; + isExtruding = true; + if (dx > lastVoxelScale) extrudeDirection.x = extrudeScale; + else if (dx < -lastVoxelScale) extrudeDirection.x = -extrudeScale; + else if (dy > lastVoxelScale) extrudeDirection.y = extrudeScale; + else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale; + else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale; + else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale; + else isExtruding = false; + } else { + // We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel + var dx = event.x - mouseX; + var dy = event.y - mouseY; + if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { + lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); + Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, + extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + mouseX = event.x; + mouseY = event.y; + } } } } @@ -265,15 +285,15 @@ function mouseReleaseEvent(event) { if (isOrbiting) { var cameraOrientation = Camera.getOrientation(); var eulers = Quat.safeEulerAngles(cameraOrientation); - Camera.stopLooking(); - print("pitch, yaw " + eulers.x + ", " + eulers.y); - MyAvatar.headPitch = eulers.x; - MyAvatar.bodyYaw = eulers.y; MyAvatar.position = Camera.getPosition(); + MyAvatar.orientation = cameraOrientation; + Camera.stopLooking(); Camera.setMode(oldMode); + Camera.setOrientation(cameraOrientation); } isAdding = false; isOrbiting = false; + isExtruding = false; } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 22a1444f9f..76da290591 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -394,7 +394,7 @@ void Audio::handleAudioInput() { } _averageInputLoudness = smallestSample; _noiseGateSampleCounter = 0; - qDebug("smallest sample = %.1f", _averageInputLoudness); + //qDebug("smallest sample = %.1f", _averageInputLoudness); } #else _noiseGateSampleCounter++; From be7d1a57236c846510aaf4e09d97f969b7089277 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 22:53:46 -0800 Subject: [PATCH 25/41] Adjustments to noise gate, commit to min sampling method --- interface/src/Audio.cpp | 70 +++++++++++++++++++++++------------------ interface/src/Audio.h | 4 +-- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 76da290591..30352639c0 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -37,7 +37,7 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDI static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; -static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 100; +static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; // Mute icon configration static const int ICON_SIZE = 24; @@ -67,7 +67,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _measuredJitter(0), _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), - _averageInputLoudness(0), + _noiseGateMeasuredFloor(0), _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), @@ -356,58 +356,66 @@ void Audio::handleAudioInput() { NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, _inputFormat, _desiredInputFormat); + // + // Impose Noise Gate + // + // The Noise Gate is used to reject constant background noise by measuring the noise + // floor observed at the microphone and then opening the 'gate' to allow microphone + // signals to be transmitted when the microphone samples average level exceeds a multiple + // of the noise floor. + // + // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. + // Make this value lower for more sensitivity and less rejection of noise. + // NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded + // to open the gate. + // NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames + // will we wait before closing the gate. + // NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. + // More means better rejection but also can reject continuous things like singing. + // NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? + + float loudness = 0; float thisSample = 0; int samplesOverNoiseGate = 0; -#define NOISE_MIN_SAMPLE -#ifdef NOISE_MIN_SAMPLE - const float NOISE_GATE_HEIGHT = 12.f; + const float NOISE_GATE_HEIGHT = 7.f; const int NOISE_GATE_WIDTH = 5; const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; -#else - const float NOISE_GATE_HEIGHT = 6.f; - const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; -#endif - + const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { thisSample = fabsf(monoAudioSamples[i]); loudness += thisSample; // Noise Reduction: Count peaks above the average loudness - if (thisSample > (_averageInputLoudness * NOISE_GATE_HEIGHT)) { + if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) { samplesOverNoiseGate++; } } _lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - //qDebug("%.1f", _lastInputLoudness); -#ifdef NOISE_MIN_SAMPLE + float averageOfAllSampleFrames = 0.f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { float smallestSample = MAXFLOAT; - for (int i = 0; i < NUMBER_OF_NOISE_SAMPLE_FRAMES; i++) { - if (_noiseSampleFrames[i] < smallestSample) { - smallestSample = _noiseSampleFrames[i]; + for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) { + float thisAverage = 0.0f; + for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { + thisAverage += _noiseSampleFrames[j]; + averageOfAllSampleFrames += _noiseSampleFrames[j]; + } + thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; + + if (thisAverage < smallestSample) { + smallestSample = thisAverage; } } - _averageInputLoudness = smallestSample; + averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; + _noiseGateMeasuredFloor = smallestSample; _noiseGateSampleCounter = 0; - //qDebug("smallest sample = %.1f", _averageInputLoudness); + qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); } -#else - _noiseGateSampleCounter++; - if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { - qDebug("average loudness = %.1f", _averageInputLoudness); - _noiseGateSampleCounter = 0; - } - - const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds - _averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness; -#endif - - + if (_noiseGateEnabled) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { _noiseGateOpen = true; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 5028024a0c..34a3daad30 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -45,7 +45,7 @@ public: void render(int screenWidth, int screenHeight); - float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _averageInputLoudness, 0.f); } + float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); } void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; } @@ -109,7 +109,7 @@ private: float _measuredJitter; int16_t _jitterBufferSamples; float _lastInputLoudness; - float _averageInputLoudness; + float _noiseGateMeasuredFloor; float* _noiseSampleFrames; int _noiseGateSampleCounter; bool _noiseGateOpen; From 595eb38c72b12ba4c825274eceece2d37a45d24a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 22:57:13 -0800 Subject: [PATCH 26/41] comment out debug --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 30352639c0..75d2a5751c 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -413,7 +413,7 @@ void Audio::handleAudioInput() { averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; _noiseGateMeasuredFloor = smallestSample; _noiseGateSampleCounter = 0; - qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); + //qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); } if (_noiseGateEnabled) { From 50df17dc10060c571697926053669b3b18881965 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Feb 2014 23:37:19 -0800 Subject: [PATCH 27/41] fix windows build buster --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 75d2a5751c..0cf67be2bf 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -397,7 +397,7 @@ void Audio::handleAudioInput() { float averageOfAllSampleFrames = 0.f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { - float smallestSample = MAXFLOAT; + float smallestSample = FLT_MAX; for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) { float thisAverage = 0.0f; for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { From 3a8aa0c47e4f9556d9401be67cf551b41b8e147f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:02:16 -0800 Subject: [PATCH 28/41] Removing HeadData::findSpherePenetration() as unused cruft. --- libraries/avatars/src/HeadData.cpp | 7 ------- libraries/avatars/src/HeadData.h | 7 ------- 2 files changed, 14 deletions(-) diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index f863d6b592..62e8276bd3 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -45,10 +45,3 @@ void HeadData::addLean(float sideways, float forwards) { _leanForward += forwards; } -bool HeadData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const { - // we would like to update this to determine collisions/penetrations with the Avatar's head sphere... - // but right now it does not appear as if the HeadData has a position and radius. - // this is a placeholder for now. - return false; -} - diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index fde684bbf1..0f096059c0 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -58,13 +58,6 @@ public: void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } friend class AvatarData; - - /// Checks for penetration between the described sphere and the hand. - /// \param penetratorCenter the center of the penetration test sphere - /// \param penetratorRadius the radius of the penetration test sphere - /// \param penetration[out] the vector in which to store the penetration - /// \return whether or not the sphere penetrated - bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const; protected: float _yaw; From e793c207f9fd15f2ad70266a154b51e7d9348ab1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:03:14 -0800 Subject: [PATCH 29/41] Minor whitespace removal. --- interface/src/avatar/MyAvatar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e0d9db43aa..560f1a6fd4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -837,7 +837,6 @@ void MyAvatar::updateThrust(float deltaTime) { } } } - } // Update speed brake status @@ -903,7 +902,6 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { } } - void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { const float VOXEL_ELASTICITY = 0.4f; const float VOXEL_DAMPING = 0.0f; From 9523ea7d03a3b402a860b294b0b2883251f9818f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:03:39 -0800 Subject: [PATCH 30/41] Only do slaps for MyAvatar. --- interface/src/avatar/Hand.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 7e47b0a0d5..5749da5f14 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -178,7 +178,7 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { } glm::vec3 totalPenetration; ModelCollisionList collisions; - if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { + if (isMyHand && Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { // Check for palm collisions glm::vec3 myPalmPosition = palm.getPosition(); float palmCollisionDistance = 0.1f; @@ -220,10 +220,10 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); } } else { - // when this !isMyHand then avatar is MyAvatar and we apply the collision + // when !isMyHand then avatar is MyAvatar and we apply the collision // which might not do anything (hand hit unmovable part of MyAvatar) however - // we don't resolve the hand's penetration (we expect their simulation - // to do the right thing). + // we don't resolve the hand's penetration because we expect the remote + // simulation to do the right thing. avatar->applyCollision(collisions[j]); } } From 312bc7521f5d13a698773c99351b0a2aebbc234a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 10:04:58 -0800 Subject: [PATCH 31/41] Making arm restoration rate independent of FPS and easier to tune. --- interface/src/avatar/SkeletonModel.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ac08c52b49..ff4de8c41e 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -36,23 +36,24 @@ void SkeletonModel::simulate(float deltaTime) { HandData& hand = _owningAvatar->getHand(); hand.getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); - const float HAND_RESTORATION_RATE = 0.25f; + const float HAND_RESTORATION_PERIOD = 1.f; // seconds + float handRestorePercent = glm::clamp(deltaTime / HAND_RESTORATION_PERIOD, 0.f, 1.f); const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (leftPalmIndex == -1) { // no Leap data; set hands from mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { - restoreRightHandPosition(HAND_RESTORATION_RATE); + restoreRightHandPosition(handRestorePercent); } else { applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); } - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(handRestorePercent); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices, hand.getPalms()[leftPalmIndex]); - restoreLeftHandPosition(HAND_RESTORATION_RATE); + restoreLeftHandPosition(handRestorePercent); } else { applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices, From 6d75efd2b01d56fe8d236de1985fc9de824927d6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 10:46:28 -0800 Subject: [PATCH 32/41] tweaks to default menus for alpha, make Gravity false so we don't fall into abyss --- interface/src/Menu.cpp | 8 ++++---- interface/src/Menu.h | 2 +- interface/src/avatar/Hand.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7eb5807c6f..2e026f216f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,7 +161,7 @@ Menu::Menu() : #endif addDisabledActionAndSeparator(editMenu, "Physics"); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, true); + addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); @@ -339,14 +339,14 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FaceshiftTCP, 0, false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); @@ -356,7 +356,7 @@ Menu::Menu() : true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 742b9fc66f..2f0c65413c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -183,7 +183,7 @@ namespace MenuOption { const QString DisableDeltaSending = "Disable Delta Sending"; const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisplayFrustum = "Display Frustum"; - const QString DisplayLeapHands = "Display Leap Hands"; + const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; const QString FilterSixense = "Smooth Sixense Movement"; const QString DontRenderVoxels = "Don't call _voxels.render()"; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 8edb455a75..1239e38818 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -304,7 +304,7 @@ void Hand::render(bool isMine) { } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderLeapHands(isMine); } From 156fa6dc5aaa57465c585b6b6cda7dfc0a98c9a3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 11:03:35 -0800 Subject: [PATCH 33/41] more tweaks, removed old clouds --- interface/src/Application.cpp | 14 ------ interface/src/Application.h | 4 -- interface/src/Cloud.cpp | 85 ----------------------------------- interface/src/Cloud.h | 32 ------------- interface/src/Menu.cpp | 17 +++---- interface/src/Menu.h | 1 - 6 files changed, 5 insertions(+), 148 deletions(-) delete mode 100644 interface/src/Cloud.cpp delete mode 100644 interface/src/Cloud.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 004b71074b..f51360cca1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2146,15 +2146,6 @@ void Application::updateThreads(float deltaTime) { } } -void Application::updateParticles(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateParticles()"); - - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.simulate(deltaTime); - } -} - void Application::updateMetavoxels(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); @@ -2276,7 +2267,6 @@ void Application::update(float deltaTime) { updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... - updateParticles(deltaTime); // Simulate particle cloud movements updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present @@ -2711,10 +2701,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // disable specular lighting for ground and voxels glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); - // Draw Cloud Particles - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.render(); - } // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), diff --git a/interface/src/Application.h b/interface/src/Application.h index ff6e08758b..c5aafc4e9d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -32,7 +32,6 @@ #include "BandwidthMeter.h" #include "Camera.h" -#include "Cloud.h" #include "DatagramProcessor.h" #include "Environment.h" #include "GLCanvas.h" @@ -284,7 +283,6 @@ private: void updateSixense(float deltaTime); void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); - void updateParticles(float deltaTime); void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); void updateDialogs(float deltaTime); @@ -351,8 +349,6 @@ private: Stars _stars; - Cloud _cloud; - VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste VoxelImporter* _voxelImporter; diff --git a/interface/src/Cloud.cpp b/interface/src/Cloud.cpp deleted file mode 100644 index a89ee04810..0000000000 --- a/interface/src/Cloud.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Cloud.cpp -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include "Cloud.h" -#include "Util.h" -#include "Field.h" - -const int NUM_PARTICLES = 100000; -const float FIELD_COUPLE = 0.001f; -const bool RENDER_FIELD = false; - -Cloud::Cloud() { - glm::vec3 box = glm::vec3(PARTICLE_WORLD_SIZE); - _bounds = box; - _count = NUM_PARTICLES; - _particles = new Particle[_count]; - _field = new Field(PARTICLE_WORLD_SIZE, FIELD_COUPLE); - - for (unsigned int i = 0; i < _count; i++) { - _particles[i].position = randVector() * box; - const float INIT_VEL_SCALE = 0.03f; - _particles[i].velocity = randVector() * ((float)PARTICLE_WORLD_SIZE * INIT_VEL_SCALE); - _particles[i].color = randVector(); - } -} - -void Cloud::render() { - if (RENDER_FIELD) { - _field->render(); - } - - glPointSize(3.0f); - glDisable(GL_TEXTURE_2D); - glEnable(GL_POINT_SMOOTH); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].position); - glColorPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].color); - glDrawArrays(GL_POINTS, 0, NUM_PARTICLES); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - -} - -void Cloud::simulate (float deltaTime) { - unsigned int i; - _field->simulate(deltaTime); - for (i = 0; i < _count; ++i) { - - // Update position - _particles[i].position += _particles[i].velocity * deltaTime; - - // Decay Velocity (Drag) - const float CONSTANT_DAMPING = 0.15f; - _particles[i].velocity *= (1.f - CONSTANT_DAMPING * deltaTime); - - // Interact with Field - _field->interact(deltaTime, _particles[i].position, _particles[i].velocity); - - // Update color to velocity - _particles[i].color = (glm::normalize(_particles[i].velocity) * 0.5f) + 0.5f; - - // Bounce at bounds - if ((_particles[i].position.x > _bounds.x) || (_particles[i].position.x < 0.f)) { - _particles[i].position.x = glm::clamp(_particles[i].position.x, 0.f, _bounds.x); - _particles[i].velocity.x *= -1.f; - } - if ((_particles[i].position.y > _bounds.y) || (_particles[i].position.y < 0.f)) { - _particles[i].position.y = glm::clamp(_particles[i].position.y, 0.f, _bounds.y); - _particles[i].velocity.y *= -1.f; - } - if ((_particles[i].position.z > _bounds.z) || (_particles[i].position.z < 0.f)) { - _particles[i].position.z = glm::clamp(_particles[i].position.z, 0.f, _bounds.z); - _particles[i].velocity.z *= -1.f; - } - } - } diff --git a/interface/src/Cloud.h b/interface/src/Cloud.h deleted file mode 100644 index fcf414b62e..0000000000 --- a/interface/src/Cloud.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Cloud.h -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__Cloud__ -#define __interface__Cloud__ - -#include "Field.h" - -#define PARTICLE_WORLD_SIZE 256.0 - -class Cloud { -public: - Cloud(); - void simulate(float deltaTime); - void render(); - -private: - struct Particle { - glm::vec3 position, velocity, color; - }* _particles; - - unsigned int _count; - glm::vec3 _bounds; - Field* _field; -}; - -#endif diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2e026f216f..4a3733f760 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -238,9 +238,9 @@ Menu::Menu() : SLOT(setFullscreen(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, appInstance,SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H,false, - appInstance,SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, + appInstance, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false, @@ -266,14 +266,8 @@ Menu::Menu() : appInstance->getAvatar(), SLOT(resetSize())); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::OffAxisProjection, - 0, - true); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::TurnWithHead, - 0, - true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); @@ -298,7 +292,6 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2f0c65413c..19e9fbf49f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -223,7 +223,6 @@ namespace MenuOption { const QString KillLocalVoxels = "Kill Local Voxels"; const QString GoHome = "Go Home"; const QString Gravity = "Use Gravity"; - const QString ParticleCloud = "Particle Cloud"; const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; From d9b50359a6818434ea7a6c22a3bb1642efb6a7f3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:21:28 -0800 Subject: [PATCH 34/41] Hand-face collisions now work (sorta). --- interface/src/avatar/Avatar.cpp | 25 ++++++++++++++++++++++--- interface/src/avatar/Head.cpp | 28 ++++++++++++++++++++++++++++ interface/src/avatar/Head.h | 2 ++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 487f72a1e5..f36c03cba6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -162,6 +162,7 @@ void Avatar::render(bool forceRenderHead) { // render body if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { _skeletonModel.renderCollisionProxies(1.f); + //_head.getFaceModel().renderCollisionProxies(0.5f); } if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { @@ -276,11 +277,14 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet bool didPenetrate = false; glm::vec3 skeletonPenetration; ModelCollisionInfo collisionInfo; + /* Temporarily disabling collisions against the skeleton because the collision proxies up + * near the neck are bad and prevent the hand from hitting the face. if (_skeletonModel.findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo, 1.0f, skeletonSkipIndex)) { collisionInfo._model = &_skeletonModel; collisions.push_back(collisionInfo); didPenetrate = true; } + */ if (_head.getFaceModel().findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo)) { collisionInfo._model = &(_head.getFaceModel()); collisions.push_back(collisionInfo); @@ -448,16 +452,31 @@ float Avatar::getHeight() const { bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const { // ATM only the Skeleton is pokeable // TODO: make poke affect head + if (!collision._model) { + return false; + } if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - return _skeletonModel.collisionHitsMoveableJoint(collision); + // collision response of skeleton is temporarily disabled + return false; + //return _skeletonModel.collisionHitsMoveableJoint(collision); + } + if (collision._model == &(_head.getFaceModel())) { + return true; } return false; } void Avatar::applyCollision(ModelCollisionInfo& collision) { - if (collision._model == &_skeletonModel && collision._jointIndex != -1) { - _skeletonModel.applyCollision(collision); + if (!collision._model) { + return; } + if (collision._model == &(_head.getFaceModel())) { + _head.applyCollision(collision); + } + // TODO: make skeleton respond to collisions + //if (collision._model == &_skeletonModel && collision._jointIndex != -1) { + // _skeletonModel.applyCollision(collision); + //} } float Avatar::getPelvisFloatingHeight() const { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index e5d4724bb5..bb88530aa7 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -219,6 +219,34 @@ float Head::getTweakedRoll() const { return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } +void Head::applyCollision(ModelCollisionInfo& collisionInfo) { + // HACK: the collision proxies for the FaceModel are bad. As a temporary workaround + // we collide against a hard coded collision proxy. + // TODO: get a better collision proxy here. + const float HEAD_RADIUS = 0.15f; + const glm::vec3 HEAD_CENTER = _position; + + // collide the contactPoint against the collision proxy to obtain a new penetration + // NOTE: that penetration is in opposite direction (points the way out for the point, not the sphere) + glm::vec3 penetration; + if (findPointSpherePenetration(collisionInfo._contactPoint, HEAD_CENTER, HEAD_RADIUS, penetration)) { + // compute lean angles + Avatar* owningAvatar = static_cast(_owningAvatar); + glm::quat bodyRotation = owningAvatar->getOrientation(); + glm::vec3 neckPosition; + if (owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) { + glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f); + glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f); + float neckLength = glm::length(_position - neckPosition); + if (neckLength > 0.f) { + float forward = glm::dot(collisionInfo._penetration, zAxis) / neckLength; + float sideways = - glm::dot(collisionInfo._penetration, xAxis) / neckLength; + addLean(sideways, forward); + } + } + } +} + void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { Application::getInstance()->getGlowEffect()->begin(); diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 19f9efd8e6..eae8223903 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -79,6 +79,8 @@ public: float getTweakedPitch() const; float getTweakedYaw() const; float getTweakedRoll() const; + + void applyCollision(ModelCollisionInfo& collisionInfo); private: // disallow copies of the Head, copy of owning Avatar is disallowed too From b75de42802ca858c9e9ce7c398fc2aba3ec2b931 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:22:40 -0800 Subject: [PATCH 35/41] Making the lean recovery use more tuneable parameters. --- interface/src/avatar/MyAvatar.cpp | 33 +++++++++---------------------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 560f1a6fd4..8a4d734072 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -112,23 +112,7 @@ void MyAvatar::updateTransmitter(float deltaTime) { void MyAvatar::update(float deltaTime) { updateTransmitter(deltaTime); - // TODO: resurrect touch interactions between avatars - //// rotate body yaw for yaw received from multitouch - //setOrientation(getOrientation() * glm::quat(glm::vec3(0, _yawFromTouch, 0))); - //_yawFromTouch = 0.f; - // - //// apply pitch from touch - //_head.setPitch(_head.getPitch() + _pitchFromTouch); - //_pitchFromTouch = 0.0f; - // - //float TOUCH_YAW_SCALE = -0.25f; - //float TOUCH_PITCH_SCALE = -12.5f; - //float FIXED_TOUCH_TIMESTEP = 0.016f; - //_yawFromTouch += ((_touchAvgX - _lastTouchAvgX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP); - //_pitchFromTouch += ((_touchAvgY - _lastTouchAvgY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP); - - // Update my avatar's state from gyros - updateFromGyros(Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)); + updateFromGyros(deltaTime); // Update head mouse from faceshift if active Faceshift* faceshift = Application::getInstance()->getFaceshift(); @@ -364,7 +348,7 @@ void MyAvatar::simulate(float deltaTime) { const float MAX_PITCH = 90.0f; // Update avatar head rotation with sensor data -void MyAvatar::updateFromGyros(bool turnWithHead) { +void MyAvatar::updateFromGyros(float deltaTime) { Faceshift* faceshift = Application::getInstance()->getFaceshift(); glm::vec3 estimatedPosition, estimatedRotation; @@ -372,7 +356,7 @@ void MyAvatar::updateFromGyros(bool turnWithHead) { estimatedPosition = faceshift->getHeadTranslation(); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); // Rotate the body if the head is turned beyond the screen - if (turnWithHead) { + if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) { const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f; const float FACESHIFT_MIN_YAW_TURN = 15.f; const float FACESHIFT_MAX_YAW_TURN = 50.f; @@ -387,11 +371,12 @@ void MyAvatar::updateFromGyros(bool turnWithHead) { } } else { // restore rotation, lean to neutral positions - const float RESTORE_RATE = 0.05f; - _head.setYaw(glm::mix(_head.getYaw(), 0.0f, RESTORE_RATE)); - _head.setRoll(glm::mix(_head.getRoll(), 0.0f, RESTORE_RATE)); - _head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, RESTORE_RATE)); - _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, RESTORE_RATE)); + const float RESTORE_PERIOD = 1.f; // seconds + float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); + _head.setYaw(glm::mix(_head.getYaw(), 0.0f, restorePercentage)); + _head.setRoll(glm::mix(_head.getRoll(), 0.0f, restorePercentage)); + _head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, restorePercentage)); + _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, restorePercentage)); return; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index b912f6b0a7..0130cc9ca2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -34,7 +34,7 @@ public: void reset(); void update(float deltaTime); void simulate(float deltaTime); - void updateFromGyros(bool turnWithHead); + void updateFromGyros(float deltaTime); void updateTransmitter(float deltaTime); void render(bool forceRenderHead); From ee4733d0bd8ce8801e5ea7622b62ea0a198f4b95 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 12:41:23 -0800 Subject: [PATCH 36/41] Fixing a comment. --- libraries/avatars/src/AvatarHashMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 72ada7d421..82485691c5 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -2,7 +2,7 @@ // AvatarHashMap.cpp // hifi // -// Created by Stephen AndrewMeadows on 1/28/2014. +// Created by AndrewMeadows on 1/28/2014. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // From ab4164a6dfeea9888ee8468aa6b008983188ef1c Mon Sep 17 00:00:00 2001 From: stojce Date: Thu, 13 Feb 2014 22:44:10 +0100 Subject: [PATCH 37/41] #19505 - Add domain & orientation parsing to hifi:// protocol handler --- interface/src/Application.cpp | 21 +++++++++++++-- interface/src/Menu.cpp | 50 ++++++++++++++++++++++++++++++----- interface/src/Menu.h | 2 ++ 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eeb9d4a73a..57f66e68b2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -687,8 +687,25 @@ bool Application::event(QEvent* event) { if (event->type() == QEvent::FileOpen) { QFileOpenEvent* fileEvent = static_cast(event); if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) { - QString destination = fileEvent->url().toLocalFile().remove(QRegExp(CUSTOM_URL_SCHEME + "|/")); - Menu::getInstance()->goToDestination(destination); + QString destination = fileEvent->url().toLocalFile().remove(CUSTOM_URL_SCHEME); + QStringList urlParts = destination.split('/', QString::SkipEmptyParts); + + if (urlParts.count() > 1) { + // if url has 2 or more parts, the first one is domain name + Menu::getInstance()->goToDomain(urlParts[0]); + + // location coordinates + Menu::getInstance()->goToDestination(urlParts[1]); + if (urlParts.count() > 2) { + + // location orientation + Menu::getInstance()->goToOrientation(urlParts[2]); + } + } else if (urlParts.count() == 1) { + + // location coordinates + Menu::getInstance()->goToDestination(urlParts[0]); + } } return false; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9854a8b97f..e064c4bd20 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -889,6 +889,17 @@ void Menu::editPreferences() { sendFakeEnterEvent(); } +void Menu::goToDomain(const QString newDomain) { + if (NodeList::getInstance()->getDomainHostname() != newDomain) { + + // send a node kill request, indicating to other clients that they should play the "disappeared" effect + Application::getInstance()->getAvatar()->sendKillAvatar(); + + // give our nodeList the new domain-server hostname + NodeList::getInstance()->setDomainHostname(newDomain); + } +} + void Menu::goToDomain() { QString currentDomainHostname = NodeList::getInstance()->getDomainHostname(); @@ -913,17 +924,44 @@ void Menu::goToDomain() { // the user input a new hostname, use that newHostname = domainDialog.textValue(); } - - // send a node kill request, indicating to other clients that they should play the "disappeared" effect - Application::getInstance()->getAvatar()->sendKillAvatar(); - - // give our nodeList the new domain-server hostname - NodeList::getInstance()->setDomainHostname(domainDialog.textValue()); + + goToDomain(newHostname); } sendFakeEnterEvent(); } +void Menu::goToOrientation(QString orientation) { + + if (orientation.isEmpty()) { + return; + } + + QStringList orientationItems = orientation.split(QRegExp("_|,"), QString::SkipEmptyParts); + + const int NUMBER_OF_ORIENTATION_ITEMS = 4; + const int W_ITEM = 0; + const int X_ITEM = 1; + const int Y_ITEM = 2; + const int Z_ITEM = 3; + + if (orientationItems.size() == NUMBER_OF_ORIENTATION_ITEMS) { + + double w = replaceLastOccurrence('-', '.', orientationItems[W_ITEM].trimmed()).toDouble(); + double x = replaceLastOccurrence('-', '.', orientationItems[X_ITEM].trimmed()).toDouble(); + double y = replaceLastOccurrence('-', '.', orientationItems[Y_ITEM].trimmed()).toDouble(); + double z = replaceLastOccurrence('-', '.', orientationItems[Z_ITEM].trimmed()).toDouble(); + + glm::quat newAvatarOrientation(w, x, y, z); + + MyAvatar* myAvatar = Application::getInstance()->getAvatar(); + glm::quat avatarOrientation = myAvatar->getOrientation(); + if (newAvatarOrientation != avatarOrientation) { + myAvatar->setOrientation(newAvatarOrientation); + } + } +} + bool Menu::goToDestination(QString destination) { QStringList coordinateItems = destination.split(QRegExp("_|,"), QString::SkipEmptyParts); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9ccc5466e8..378c022ae0 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -85,6 +85,8 @@ public: QAction::MenuRole role = QAction::NoRole); virtual void removeAction(QMenu* menu, const QString& actionName); bool goToDestination(QString destination); + void goToOrientation(QString orientation); + void goToDomain(const QString newDomain); public slots: void bandwidthDetails(); From 50d864901e742ba3cb7e0b338855474dbf13af10 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Feb 2014 14:02:25 -0800 Subject: [PATCH 38/41] Improved comment about limitation of collision check. --- interface/src/renderer/Model.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index ce11ee3d71..7686b1ac7f 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -477,7 +477,10 @@ bool Model::findSphereCollision(const glm::vec3& penetratorCenter, float penetra if (findSphereCapsuleConePenetration(relativeCenter, penetratorRadius, start, end, startRadius, endRadius, bonePenetration)) { totalPenetration = addPenetrations(totalPenetration, bonePenetration); - // TODO: Andrew to try to keep the joint furthest toward the root + // BUG: we currently overwrite the jointIndex with the last one found + // which can cause incorrect collisions when colliding against more than + // one joint. + // TODO: fix this. jointIndex = i; } outerContinue: ; From 9d841ce918f505a82a2f83f68d471f5ec78df268 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 18:19:20 -0800 Subject: [PATCH 39/41] add Stop All Scripts and Reload All Scripts --- interface/src/Application.cpp | 24 ++++++++++++++++++++++++ interface/src/Application.h | 2 ++ interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 6 ++++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f51360cca1..80c2dc7feb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3984,6 +3984,30 @@ void Application::saveScripts() { settings->endArray(); } +void Application::stopAllScripts() { + // stops all current running scripts + QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); + foreach (QAction* scriptAction, scriptActions) { + scriptAction->activate(QAction::Trigger); + qDebug() << "stopping script..." << scriptAction->text(); + } +} + +void Application::reloadAllScripts() { + // reloads all current running scripts + QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); + foreach (QAction* scriptAction, scriptActions) { + scriptAction->activate(QAction::Trigger); + qDebug() << "stopping script..." << scriptAction->text(); + } + QStringList reloadList = _activeScripts; + _activeScripts.clear(); + foreach (QString scriptName, reloadList){ + qDebug() << "reloading script..." << scriptName; + loadScript(scriptName); + } +} + void Application::removeScriptName(const QString& fileNameString) { _activeScripts.removeOne(fileNameString); } diff --git a/interface/src/Application.h b/interface/src/Application.h index c5aafc4e9d..3153150457 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -231,6 +231,8 @@ public slots: void loadDialog(); void toggleLogDialog(); void initAvatarAndViewFrustum(); + void stopAllScripts(); + void reloadAllScripts(); private slots: void timer(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4a3733f760..f16a276653 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -93,6 +93,8 @@ Menu::Menu() : addDisabledActionAndSeparator(fileMenu, "Scripts"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts())); + addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts())); _activeScriptsMenu = fileMenu->addMenu("Running Scripts"); addDisabledActionAndSeparator(fileMenu, "Voxels"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 19e9fbf49f..31b19a64c6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -243,8 +243,10 @@ namespace MenuOption { const QString PasteVoxels = "Paste"; const QString PasteToVoxel = "Paste to Voxel..."; const QString PipelineWarnings = "Show Render Pipeline Warnings"; + const QString PlaySlaps = "Play Slaps"; const QString Preferences = "Preferences..."; const QString RandomizeVoxelColors = "Randomize Voxel TRUE Colors"; + const QString ReloadAllScripts = "Reload All Scripts"; const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetSwatchColors = "Reset Swatch Colors"; const QString RunTimingTests = "Run Timing Tests"; @@ -253,11 +255,10 @@ namespace MenuOption { const QString SettingsExport = "Export Settings"; const QString ShowAllLocalVoxels = "Show All Local Voxels"; const QString ShowTrueColors = "Show TRUE Colors"; - const QString VoxelDrumming = "Voxel Drumming"; - const QString PlaySlaps = "Play Slaps"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString Stars = "Stars"; const QString Stats = "Stats"; + const QString StopAllScripts = "Stop All Scripts"; const QString TestPing = "Test Ping"; const QString TreeStats = "Calculate Tree Stats"; const QString TransmitterDrive = "Transmitter Drive"; @@ -268,6 +269,7 @@ namespace MenuOption { const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode"; const QString VoxelDeleteMode = "Delete Voxel Mode"; + const QString VoxelDrumming = "Voxel Drumming"; const QString VoxelGetColorMode = "Get Color Mode"; const QString VoxelMode = "Cycle Voxel Mode"; const QString VoxelPaintColor = "Voxel Paint Color"; From dbd6cb71c9aadc491fa667becf566be2a6fc3d06 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 20:55:16 -0800 Subject: [PATCH 40/41] fixed crash on shutdown with multiple scripts --- libraries/octree/src/OctreeScriptingInterface.cpp | 13 +++++++++++-- libraries/octree/src/OctreeScriptingInterface.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 553ab961df..89bf5ceb62 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -11,13 +11,19 @@ #include "OctreeScriptingInterface.h" OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender, - JurisdictionListener* jurisdictionListener) + JurisdictionListener* jurisdictionListener) : + _packetSender(NULL), + _jurisdictionListener(NULL), + _managedPacketSender(false), + _managedJurisdictionListener(false), + _initialized(false) { setPacketSender(packetSender); setJurisdictionListener(jurisdictionListener); } OctreeScriptingInterface::~OctreeScriptingInterface() { +qDebug() << "OctreeScriptingInterface::~OctreeScriptingInterface() this=" << this; cleanupManagedObjects(); } @@ -45,6 +51,9 @@ void OctreeScriptingInterface::setJurisdictionListener(JurisdictionListener* jur } void OctreeScriptingInterface::init() { + if (_initialized) { + return; + } if (_jurisdictionListener) { _managedJurisdictionListener = false; } else { @@ -64,5 +73,5 @@ void OctreeScriptingInterface::init() { if (QCoreApplication::instance()) { connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(cleanupManagedObjects())); } - + _initialized = true; } diff --git a/libraries/octree/src/OctreeScriptingInterface.h b/libraries/octree/src/OctreeScriptingInterface.h index 34eddd8bed..3c832cbae8 100644 --- a/libraries/octree/src/OctreeScriptingInterface.h +++ b/libraries/octree/src/OctreeScriptingInterface.h @@ -93,6 +93,7 @@ protected: JurisdictionListener* _jurisdictionListener; bool _managedPacketSender; bool _managedJurisdictionListener; + bool _initialized; }; #endif /* defined(__hifi__OctreeScriptingInterface__) */ From cd137b2b12bca1c450fb9eb23db4326e670cfdcf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Feb 2014 21:00:20 -0800 Subject: [PATCH 41/41] tweak to reload scripts --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80c2dc7feb..96ace9076a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3991,16 +3991,18 @@ void Application::stopAllScripts() { scriptAction->activate(QAction::Trigger); qDebug() << "stopping script..." << scriptAction->text(); } + _activeScripts.clear(); } void Application::reloadAllScripts() { + // remember all the current scripts so we can reload them + QStringList reloadList = _activeScripts; // reloads all current running scripts QList scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions(); foreach (QAction* scriptAction, scriptActions) { scriptAction->activate(QAction::Trigger); qDebug() << "stopping script..." << scriptAction->text(); } - QStringList reloadList = _activeScripts; _activeScripts.clear(); foreach (QString scriptName, reloadList){ qDebug() << "reloading script..." << scriptName;