diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 21726bdd6a..b531473a1c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1480,6 +1480,54 @@ void Application::doKillLocalVoxels() { _wantToKillLocalVoxels = true; } +void Application::removeVoxel(glm::vec3 position, + float scale) { + VoxelDetail voxel; + voxel.x = position.x / TREE_SCALE; + voxel.y = position.y / TREE_SCALE; + voxel.z = position.z / TREE_SCALE; + voxel.s = scale / TREE_SCALE; + _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxel); + + // delete it locally to see the effect immediately (and in case no voxel server is present) + _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); +} + +void Application::makeVoxel(glm::vec3 position, + float scale, + unsigned char red, + unsigned char green, + unsigned char blue, + bool isDestructive) { + VoxelDetail voxel; + voxel.x = position.x / TREE_SCALE; + voxel.y = position.y / TREE_SCALE; + voxel.z = position.z / TREE_SCALE; + voxel.s = scale / TREE_SCALE; + voxel.red = red; + voxel.green = green; + voxel.blue = blue; + PACKET_TYPE message = isDestructive ? PACKET_TYPE_SET_VOXEL_DESTRUCTIVE : PACKET_TYPE_SET_VOXEL; + _voxelEditSender.sendVoxelEditMessage(message, voxel); + + // create the voxel locally so it appears immediately + + _voxels.createVoxel(voxel.x, voxel.y, voxel.z, voxel.s, + voxel.red, voxel.green, voxel.blue, + isDestructive); + + // Implement voxel fade effect + VoxelFade fade(VoxelFade::FADE_OUT, 1.0f, 1.0f, 1.0f); + const float VOXEL_BOUNDS_ADJUST = 0.01f; + float slightlyBigger = voxel.s * VOXEL_BOUNDS_ADJUST; + fade.voxelDetails.x = voxel.x - slightlyBigger; + fade.voxelDetails.y = voxel.y - slightlyBigger; + fade.voxelDetails.z = voxel.z - slightlyBigger; + fade.voxelDetails.s = voxel.s + slightlyBigger + slightlyBigger; + _voxelFades.push_back(fade); + +} + const glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel) { return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE, (_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE, @@ -2214,11 +2262,11 @@ void Application::updateLeap(float deltaTime) { LeapManager::nextFrame(); } -void Application::updateSixense() { +void Application::updateSixense(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateSixense()"); - _sixenseManager.update(); + _sixenseManager.update(deltaTime); } void Application::updateSerialDevices(float deltaTime) { @@ -2428,7 +2476,7 @@ void Application::update(float deltaTime) { updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels updateHandAndTouch(deltaTime); // Update state for touch sensors updateLeap(deltaTime); // Leap finger-sensing device - updateSixense(); // Razer Hydra controllers + updateSixense(deltaTime); // Razer Hydra controllers updateSerialDevices(deltaTime); // Read serial port interface devices updateAvatar(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... @@ -3945,29 +3993,18 @@ bool Application::maybeEditVoxelUnderCursor() { if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode) || Menu::getInstance()->isOptionChecked(MenuOption::VoxelColorMode)) { if (_mouseVoxel.s != 0) { - PACKET_TYPE message = Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel) - ? PACKET_TYPE_SET_VOXEL_DESTRUCTIVE - : PACKET_TYPE_SET_VOXEL; - _voxelEditSender.sendVoxelEditMessage(message, _mouseVoxel); - - // create the voxel locally so it appears immediately - _voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, - _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue, - Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel)); - - // Implement voxel fade effect - VoxelFade fade(VoxelFade::FADE_OUT, 1.0f, 1.0f, 1.0f); - const float VOXEL_BOUNDS_ADJUST = 0.01f; - float slightlyBigger = _mouseVoxel.s * VOXEL_BOUNDS_ADJUST; - fade.voxelDetails.x = _mouseVoxel.x - slightlyBigger; - fade.voxelDetails.y = _mouseVoxel.y - slightlyBigger; - fade.voxelDetails.z = _mouseVoxel.z - slightlyBigger; - fade.voxelDetails.s = _mouseVoxel.s + slightlyBigger + slightlyBigger; - _voxelFades.push_back(fade); - + makeVoxel(glm::vec3(_mouseVoxel.x * TREE_SCALE, + _mouseVoxel.y * TREE_SCALE, + _mouseVoxel.z * TREE_SCALE), + _mouseVoxel.s * TREE_SCALE, + _mouseVoxel.red, + _mouseVoxel.green, + _mouseVoxel.blue, + Menu::getInstance()->isOptionChecked(MenuOption::DestructiveAddVoxel)); + // inject a sound effect injectVoxelAddedSoundEffect(); - + // remember the position for drag detection _justEditedVoxel = true; diff --git a/interface/src/Application.h b/interface/src/Application.h index bf1137828b..3e798c10e8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -117,6 +117,15 @@ public: void wheelEvent(QWheelEvent* event); + void makeVoxel(glm::vec3 position, + float scale, + unsigned char red, + unsigned char green, + unsigned char blue, + bool isDestructive); + + void removeVoxel(glm::vec3 position, float scale); + const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); QGLWidget* getGLWidget() { return _glWidget; } @@ -249,7 +258,7 @@ private: glm::vec3& eyePosition); void updateHandAndTouch(float deltaTime); void updateLeap(float deltaTime); - void updateSixense(); + void updateSixense(float deltaTime); void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); void updateMyAvatarSimulation(float deltaTime); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 43fc8cc0de..f733a40c9f 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -61,6 +61,33 @@ void Hand::simulate(float deltaTime, bool isMine) { updateRaveGloveParticles(deltaTime); } + + // Create a voxel at fingertip if controller button is pressed + const float FINGERTIP_VOXEL_SIZE = 0.0125; + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (palm.isActive()) { + FingerData& finger = palm.getFingers()[0]; + glm::vec3 newVoxelPosition = finger.getTipPosition(); + if (palm.getControllerButtons() & BUTTON_1) { + if (glm::length(newVoxelPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { + QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value(); + Application::getInstance()->makeVoxel(newVoxelPosition, + FINGERTIP_VOXEL_SIZE, + paintColor.red(), + paintColor.green(), + paintColor.blue(), + true); + _lastFingerAddVoxel = newVoxelPosition; + } + } else if (palm.getControllerButtons() & BUTTON_2) { + if (glm::length(newVoxelPosition - _lastFingerDeleteVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { + Application::getInstance()->removeVoxel(newVoxelPosition, FINGERTIP_VOXEL_SIZE); + _lastFingerDeleteVoxel = newVoxelPosition; + } + } + } + } } void Hand::calculateGeometry() { @@ -157,6 +184,45 @@ void Hand::render() { } } + // If hand controller buttons pressed, render stuff as needed + if (getPalms().size() > 0) { + for (size_t i = 0; i < getPalms().size(); ++i) { + PalmData& palm = getPalms()[i]; + // If trigger pulled, thrust in that direction and draw beam + const float MAX_THRUSTER_BEAM_LENGTH = 5.f; + const float THRUSTER_MARKER_SIZE = 0.0125f; + if (palm.getJoystickY() != 0.f) { + FingerData& finger = palm.getFingers()[0]; + if (finger.isActive()) { + if (palm.getJoystickY() > 0.f) { + glColor3f(0, 1, 0); + } else { + glColor3f(1, 0, 0); + } + glm::vec3 palmPosition = palm.getPosition(); + glm::vec3 pointerPosition = palmPosition + + glm::normalize(finger.getTipPosition() - palmPosition) * + MAX_THRUSTER_BEAM_LENGTH; + glPushMatrix(); + glm::vec3 markerPosition = palmPosition + + glm::normalize(finger.getTipPosition() - palmPosition) * + MAX_THRUSTER_BEAM_LENGTH * + (0.5f + palm.getJoystickY() / 2.f); + + glTranslatef(markerPosition.x, markerPosition.y, markerPosition.z); + glutSolidSphere(THRUSTER_MARKER_SIZE, 10, 10); + glPopMatrix(); + glLineWidth(2.0); + glBegin(GL_LINES); + glVertex3f(palmPosition.x, palmPosition.y, palmPosition.z); + glVertex3f(pointerPosition.x, pointerPosition.y, pointerPosition.z); + glEnd(); + } + } + } + } + + glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); @@ -227,8 +293,8 @@ void Hand::renderLeapHands() { //const glm::vec3 handColor = _ballColor; const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); glPushMatrix(); // Draw the leap balls for (size_t i = 0; i < _leapFingerTipBalls.size(); i++) { diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 36573cfc86..aea03f4cc1 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -30,6 +30,7 @@ enum RaveLightsSetting { RAVE_LIGHTS_PARTICLES }; + class Avatar; class ProgramObject; @@ -46,7 +47,7 @@ public: bool isCollidable; // whether or not the ball responds to collisions float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; - + void init(); void reset(); void simulate(float deltaTime, bool isMine); @@ -62,7 +63,7 @@ public: // getters const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} - + private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); @@ -72,6 +73,8 @@ private: float _raveGloveClock; bool _raveGloveInitialized; int _raveGloveEmitter[NUM_FINGERS]; + + int _controllerButtons; /// Button states read from hand-held controllers Avatar* _owningAvatar; float _renderAlpha; @@ -79,6 +82,8 @@ private: std::vector _leapFingerTipBalls; std::vector _leapFingerRootBalls; + glm::vec3 _lastFingerAddVoxel, _lastFingerDeleteVoxel; + // private methods void setLeapHands(const std::vector& handPositions, const std::vector& handNormals); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index baedb1bc6b..1b1caac90f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -848,7 +848,25 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { up; } } - + // Add thrust and rotation from hand controllers + const float THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; + const float JOYSTICK_YAW_MAG = YAW_MAG; + for (size_t i = 0; i < getHand().getPalms().size(); ++i) { + PalmData& palm = getHand().getPalms()[i]; + if (palm.isActive()) { + if (palm.getJoystickY() != 0.f) { + FingerData& finger = palm.getFingers()[0]; + if (finger.isActive()) { + } + glm::vec3 thrustDirection = glm::normalize(finger.getTipPosition() - palm.getPosition()); + _thrust += thrustDirection * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickY() * _thrustMultiplier * deltaTime; + } + if (palm.getJoystickX() != 0.f) { + _bodyYawDelta -= palm.getJoystickX() * JOYSTICK_YAW_MAG * deltaTime; + } + } + } + // Update speed brake status const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f; if ((glm::length(_thrust) == 0.0f) && _isThrustOn && (glm::length(_velocity) > MIN_SPEED_BRAKE_VELOCITY)) { diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index dfeab1f309..8055e8112d 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -25,7 +25,7 @@ SixenseManager::~SixenseManager() { #endif } -void SixenseManager::update() { +void SixenseManager::update(float deltaTime) { #ifdef HAVE_SIXENSE if (sixenseGetNumActiveControllers() == 0) { return; @@ -42,27 +42,19 @@ void SixenseManager::update() { sixenseControllerData data; sixenseGetNewestData(i, &data); - // drive avatar with joystick and triggers - if (data.controller_index) { - avatar->setDriveKeys(ROT_LEFT, qMax(0.0f, -data.joystick_x)); - avatar->setDriveKeys(ROT_RIGHT, qMax(0.0f, data.joystick_x)); - avatar->setDriveKeys(ROT_UP, qMax(0.0f, data.joystick_y)); - avatar->setDriveKeys(ROT_DOWN, qMax(0.0f, -data.joystick_y)); - avatar->setDriveKeys(UP, data.trigger); - - } else { - avatar->setDriveKeys(FWD, qMax(0.0f, data.joystick_y)); - avatar->setDriveKeys(BACK, qMax(0.0f, -data.joystick_y)); - avatar->setDriveKeys(LEFT, qMax(0.0f, -data.joystick_x)); - avatar->setDriveKeys(RIGHT, qMax(0.0f, data.joystick_x)); - avatar->setDriveKeys(DOWN, data.trigger); - } - // Set palm position and normal based on Hydra position/orientation PalmData palm(&hand); palm.setActive(true); glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); + // Compute current velocity from position change + palm.setVelocity((position - palm.getPosition()) / deltaTime); + + // Read controller buttons and joystick into the hand + palm.setControllerButtons(data.buttons); + palm.setTrigger(data.trigger); + palm.setJoystick(data.joystick_x, data.joystick_y); + // Adjust for distance between acquisition 'orb' and the user's torso // (distance to the right of body center, distance below torso, distance behind torso) const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 90b8cf988f..43e11b682f 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -16,7 +16,7 @@ public: SixenseManager(); ~SixenseManager(); - void update(); + void update(float deltaTime); }; #endif /* defined(__interface__SixenseManager__) */ diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index f00dbff327..cfa43725b8 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -37,6 +37,8 @@ PalmData& HandData::addNewPalm() { PalmData::PalmData(HandData* owningHandData) : _rawPosition(0, 0, 0), _rawNormal(0, 1, 0), +_velocity(0, 0, 0), +_controllerButtons(0), _isActive(false), _leapID(LEAPID_INVALID), _numFramesWithoutData(0), diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index c871c568bb..b8a06d53ad 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -41,6 +41,12 @@ enum RaveGloveEffectsMode NUM_RAVE_GLOVE_EFFECTS_MODES }; +const int BUTTON_1 = 32; +const int BUTTON_2 = 64; +const int BUTTON_3 = 8; +const int BUTTON_4 = 16; +const int BUTTON_FWD = 128; + class HandData { public: HandData(AvatarData* owningAvatar); @@ -144,17 +150,34 @@ public: void setLeapID(int id) { _leapID = id; } void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; } + void setVelocity(const glm::vec3& velocity) { _velocity = velocity; } + const glm::vec3& getVelocity() const { return _velocity; } void incrementFramesWithoutData() { _numFramesWithoutData++; } void resetFramesWithoutData() { _numFramesWithoutData = 0; } int getFramesWithoutData() const { return _numFramesWithoutData; } + + // Controller buttons + void setControllerButtons(int controllerButtons) { _controllerButtons = controllerButtons; } + int getControllerButtons() { return _controllerButtons; } + + void setTrigger(float trigger) { _trigger = trigger; } + float getTrigger() { return _trigger; } + void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; } + float getJoystickX() { return _joystickX; } + float getJoystickY() { return _joystickY; } private: std::vector _fingers; glm::vec3 _rawPosition; glm::vec3 _rawNormal; - bool _isActive; // This has current valid data - int _leapID; // the Leap's serial id for this tracked object + glm::vec3 _velocity; + int _controllerButtons; + float _trigger; + float _joystickX, _joystickY; + + bool _isActive; // This has current valid data + int _leapID; // the Leap's serial id for this tracked object int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost. HandData* _owningHandData; };