From 6e69c4fbbb21da0baa98c235430fad03c22756ff Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 5 Aug 2013 11:28:10 -0700 Subject: [PATCH 1/4] improved particle rainbow color cycle mode --- interface/src/ParticleSystem.cpp | 39 +++++++-- interface/src/ParticleSystem.h | 1 + interface/src/avatar/Hand.cpp | 37 ++------ interface/src/avatar/Head.cpp | 140 +++++++------------------------ interface/src/avatar/Head.h | 17 +--- 5 files changed, 72 insertions(+), 162 deletions(-) diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index fcea8ca270..c3e24a3d9f 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -322,27 +322,48 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply color modulation if (myEmitter.particleAttributes[lifeStage ].modulationAmplitude > 0.0f) { - float modulation = 0.0f; + float redModulation = 0.0f; + float greenModulation = 0.0f; + float bueModulation = 0.0f; float radian = _timer * myEmitter.particleAttributes[lifeStage ].modulationRate * PI_TIMES_TWO; + if (myEmitter.particleAttributes[lifeStage ].modulationStyle == COLOR_MODULATION_STYLE_LIGHNTESS_PULSE) { if (sinf(radian) > 0.0f) { - modulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + redModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + greenModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + bueModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude; } + } else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_LIGHTNESS_WAVE) { - float a = myEmitter.particleAttributes[lifeStage].modulationAmplitude; - modulation = a * ONE_HALF + sinf(radian) * a * ONE_HALF; + float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude; + float brightness = amp * ONE_HALF + sinf(radian) * amp * ONE_HALF; + redModulation = brightness; + greenModulation = brightness; + bueModulation = brightness; + + } else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_RAINBOW_CYCLE) { + + float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude * ONE_HALF; + redModulation = sinf(radian * 0.5f) * amp; + greenModulation = sinf(radian * 0.7f) * amp; + bueModulation = sinf(radian * 1.0f) * amp; } - _particle[p].color.r += modulation; - _particle[p].color.g += modulation; - _particle[p].color.b += modulation; - _particle[p].color.a += modulation; + _particle[p].color.r += redModulation; + _particle[p].color.g += greenModulation; + _particle[p].color.b += bueModulation; + _particle[p].color.a = 1.0f; if (_particle[p].color.r > 1.0f) {_particle[p].color.r = 1.0f;} if (_particle[p].color.g > 1.0f) {_particle[p].color.g = 1.0f;} if (_particle[p].color.b > 1.0f) {_particle[p].color.b = 1.0f;} if (_particle[p].color.a > 1.0f) {_particle[p].color.a = 1.0f;} - } + + if (_particle[p].color.r < 0.0f) {_particle[p].color.r = 0.0f;} + if (_particle[p].color.g < 0.0f) {_particle[p].color.g = 0.0f;} + if (_particle[p].color.b < 0.0f) {_particle[p].color.b = 0.0f;} + if (_particle[p].color.a < 0.0f) {_particle[p].color.a = 0.0f;} + } // do this at the end... _particle[p].age += deltaTime; diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index a0131883a1..840c1e63cc 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -28,6 +28,7 @@ enum ColorModulationStyle COLOR_MODULATION_STYLE_NULL = -1, COLOR_MODULATION_STYLE_LIGHNTESS_PULSE, COLOR_MODULATION_STYLE_LIGHTNESS_WAVE, + COLOR_MODULATION_STYLE_RAINBOW_CYCLE, NUM_COLOR_MODULATION_STYLES }; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index eabd9e7ffc..c6075b965a 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -345,29 +345,6 @@ void Hand::updateRaveGloveParticles(float deltaTime) { _raveGloveParticleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); _raveGloveInitialized = true; } else { - - _raveGloveClock += deltaTime; - - // this rave glove effect oscillates though various colors and radii that are meant to show off some effects - if (_raveGloveMode == RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR) { - ParticleSystem::ParticleAttributes attributes; - float red = 0.5f + 0.5f * sinf(_raveGloveClock * 2.4f); - float green = 0.5f + 0.5f * cosf(_raveGloveClock * 2.7f); - float blue = 0.5f + 0.5f * sinf(_raveGloveClock * 3.0f); - float alpha = 1.0f; - - attributes.color = glm::vec4(red, green, blue, alpha); - attributes.radius = 0.01f + 0.003f * sinf(_raveGloveClock * 50.0f); - attributes.modulationAmplitude = 0.0f; - - for ( int f = 0; f< NUM_FINGERS; f ++ ) { - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes); - _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes); - } - } - _raveGloveParticleSystem.simulate(deltaTime); } } @@ -397,11 +374,15 @@ void Hand::setRaveGloveMode(int mode) { _raveGloveParticleSystem.setParticleAttributesToDefault(&attributes); - attributes.radius = 0.02f; - attributes.gravity = 0.0f; - attributes.airFriction = 0.0f; - attributes.jitter = 0.0f; - attributes.bounce = 0.0f; + attributes.modulationAmplitude = 1.0; + attributes.modulationRate = 0.33; + attributes.modulationStyle = COLOR_MODULATION_STYLE_RAINBOW_CYCLE; + attributes.color = glm::vec4( 0.5f, 0.5f, 0.5f, 1.0f); + attributes.radius = 0.02f; + attributes.gravity = 0.0f; + attributes.airFriction = 0.0f; + attributes.jitter = 0.0f; + attributes.bounce = 0.0f; _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes); _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes); _raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6f6afb550c..b09cd1f701 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -30,9 +30,9 @@ const float MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is const float EYEBALL_RADIUS = 0.017; const float EYELID_RADIUS = 0.019; const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f }; -const float HAIR_SPRING_FORCE = 10.0f; +const float HAIR_SPRING_FORCE = 7.0f; const float HAIR_TORQUE_FORCE = 0.1f; -const float HAIR_GRAVITY_FORCE = 0.05f; +const float HAIR_GRAVITY_FORCE = 0.02f; const float HAIR_DRAG = 10.0f; const float HAIR_LENGTH = 0.09f; const float HAIR_THICKNESS = 0.03f; @@ -90,7 +90,7 @@ Head::Head(Avatar* owningAvatar) : _cameraFollowHeadRate(0.0f), _face(this) { - if (USING_PHYSICAL_MOHAWK) { + if (USING_PHYSICAL_MOHAWK) { resetHairPhysics(); } } @@ -105,7 +105,7 @@ void Head::init() { _irisProgram->setUniformValue("texture", 0); _eyePositionLocation = _irisProgram->uniformLocation("eyePosition"); - + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_ARGB32); glGenTextures(1, &_irisTextureID); @@ -127,20 +127,20 @@ void Head::reset() { } } - - - void Head::resetHairPhysics() { - glm::vec3 up = getUpDirection(); + //glm::vec3 up = getUpDirection(); for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - - _hairTuft[t].length = _scale * HAIR_LENGTH; - _hairTuft[t].thickness = _scale * HAIR_THICKNESS; - _hairTuft[t].basePosition = _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f; - _hairTuft[t].midPosition = _hairTuft[t].basePosition + up * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].endPosition = _hairTuft[t].midPosition + up * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { + + _hairTuft[t].setSpringForce (HAIR_SPRING_FORCE); + _hairTuft[t].setTorqueForce (HAIR_TORQUE_FORCE); + _hairTuft[t].setGravityForce (HAIR_GRAVITY_FORCE * _gravity); + _hairTuft[t].setDrag (HAIR_DRAG); + _hairTuft[t].setLength (_scale * HAIR_LENGTH ); + _hairTuft[t].setThickness (_scale * HAIR_THICKNESS); + _hairTuft[t].setBaseDirection(getUpDirection()); + _hairTuft[t].reset(); + } } } @@ -223,6 +223,7 @@ void Head::simulate(float deltaTime, bool isMine) { // based on the nature of the lookat position, determine if the eyes can look / are looking at it. if (USING_PHYSICAL_MOHAWK) { updateHairPhysics(deltaTime); + } // Update camera pitch and yaw independently from motion of head (for gyro-based interface) @@ -376,17 +377,17 @@ void Head::renderMohawk() { if (USING_PHYSICAL_MOHAWK) { for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - glm::vec3 viewVector = _hairTuft[t].basePosition - Application::getInstance()->getCamera()->getPosition(); + glm::vec3 baseAxis = _hairTuft[t].getMidPosition() - _hairTuft[t].getBasePosition(); + glm::vec3 midAxis = _hairTuft[t].getEndPosition() - _hairTuft[t].getMidPosition(); + glm::vec3 viewVector = _hairTuft[t].getBasePosition() - Application::getInstance()->getCamera()->getPosition(); glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector)); glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector)); - glm::vec3 base1 = _hairTuft[t].basePosition - basePerpendicular * _hairTuft[t].thickness * ONE_HALF; - glm::vec3 base2 = _hairTuft[t].basePosition + basePerpendicular * _hairTuft[t].thickness * ONE_HALF; - glm::vec3 mid1 = _hairTuft[t].midPosition - midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF; - glm::vec3 mid2 = _hairTuft[t].midPosition + midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF; + glm::vec3 base1 = _hairTuft[t].getBasePosition() - basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF; + glm::vec3 base2 = _hairTuft[t].getBasePosition() + basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF; + glm::vec3 mid1 = _hairTuft[t].getMidPosition() - midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF; + glm::vec3 mid2 = _hairTuft[t].getMidPosition() + midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF; glColor3f(_mohawkColors[t].x, _mohawkColors[t].y, _mohawkColors[t].z); @@ -399,7 +400,7 @@ void Head::renderMohawk() { glVertex3f(mid2.x, mid2.y, mid2.z ); glVertex3f(mid1.x, mid1.y, mid1.z ); glVertex3f(mid2.x, mid2.y, mid2.z ); - glVertex3f(_hairTuft[t].endPosition.x, _hairTuft[t].endPosition.y, _hairTuft[t].endPosition.z ); + glVertex3f(_hairTuft[t].getEndPosition().x, _hairTuft[t].getEndPosition().y, _hairTuft[t].getEndPosition().z ); glEnd(); } } else { @@ -735,100 +736,17 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi glEnd(); } - void Head::updateHairPhysics(float deltaTime) { - glm::quat orientation = getOrientation(); glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 front = orientation * IDENTITY_FRONT; - for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { - float fraction = (float)t / (float)(NUM_HAIR_TUFTS - 1); - float angle = -20.0f + 40.0f * fraction; - float radian = angle * PI_OVER_180; - glm::vec3 baseDirection - = front * sinf(radian) - + up * cosf(radian); - - _hairTuft[t].basePosition = _position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection; - - glm::vec3 midAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 endAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - - float midLength = glm::length(midAxis); - float endLength = glm::length(endAxis); - - glm::vec3 midDirection; - glm::vec3 endDirection; - - if (midLength > 0.0f) { - midDirection = midAxis / midLength; - } else { - midDirection = up; - } - - if (endLength > 0.0f) { - endDirection = endAxis / endLength; - } else { - endDirection = up; - } - - // add spring force - float midForce = midLength - _hairTuft[t].length * ONE_HALF; - float endForce = endLength - _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midVelocity -= midDirection * midForce * HAIR_SPRING_FORCE * deltaTime; - _hairTuft[t].endVelocity -= endDirection * endForce * HAIR_SPRING_FORCE * deltaTime; - - // add gravity force - glm::vec3 gravityForce = _gravity * HAIR_GRAVITY_FORCE * deltaTime; - _hairTuft[t].midVelocity += gravityForce; - _hairTuft[t].endVelocity += gravityForce; - - // add torque force - _hairTuft[t].midVelocity += baseDirection * HAIR_TORQUE_FORCE * deltaTime; - _hairTuft[t].endVelocity += midDirection * HAIR_TORQUE_FORCE * deltaTime; - - // add drag force - float momentum = 1.0f - (HAIR_DRAG * deltaTime); - if (momentum < 0.0f) { - _hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - _hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); - } else { - _hairTuft[t].midVelocity *= momentum; - _hairTuft[t].endVelocity *= momentum; - } - - // update position by velocity - _hairTuft[t].midPosition += _hairTuft[t].midVelocity; - _hairTuft[t].endPosition += _hairTuft[t].endVelocity; - - // clamp lengths - glm::vec3 newMidVector = _hairTuft[t].midPosition - _hairTuft[t].basePosition; - glm::vec3 newEndVector = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - - float newMidLength = glm::length(newMidVector); - float newEndLength = glm::length(newEndVector); - - glm::vec3 newMidDirection; - glm::vec3 newEndDirection; - - if (newMidLength > 0.0f) { - newMidDirection = newMidVector/newMidLength; - } else { - newMidDirection = up; - } - - if (newEndLength > 0.0f) { - newEndDirection = newEndVector/newEndLength; - } else { - newEndDirection = up; - } - - _hairTuft[t].endPosition = _hairTuft[t].midPosition + newEndDirection * _hairTuft[t].length * ONE_HALF; - _hairTuft[t].midPosition = _hairTuft[t].basePosition + newMidDirection * _hairTuft[t].length * ONE_HALF; + glm::vec3 baseDirection = front * sinf(radian) + up * cosf(radian); + _hairTuft[t].setBasePosition (_position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection); + _hairTuft[t].setBaseDirection(baseDirection); + _hairTuft[t].update(deltaTime); } } - diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 58414fd8be..259786fb6a 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -18,6 +18,7 @@ #include #include "Face.h" +#include "BendyLine.h" #include "InterfaceConfig.h" #include "SerialInterface.h" #include "world.h" @@ -29,7 +30,7 @@ enum eyeContactTargets MOUTH }; -const int NUM_HAIR_TUFTS = 4; +const int NUM_HAIR_TUFTS = 4; class Avatar; class ProgramObject; @@ -80,18 +81,6 @@ private: Head(const Head&); Head& operator= (const Head&); - struct HairTuft - { - float length; - float thickness; - - glm::vec3 basePosition; - glm::vec3 midPosition; - glm::vec3 endPosition; - glm::vec3 midVelocity; - glm::vec3 endVelocity; - }; - struct Nose { glm::vec3 top; @@ -123,7 +112,7 @@ private: float _returnSpringScale; //strength of return springs glm::vec3 _bodyRotation; bool _renderLookatVectors; - HairTuft _hairTuft[NUM_HAIR_TUFTS]; + BendyLine _hairTuft[NUM_HAIR_TUFTS]; glm::vec3* _mohawkTriangleFan; glm::vec3* _mohawkColors; glm::vec3 _saccade; From 76931655785e31eee47a55f5066f7573fa62351d Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 5 Aug 2013 11:28:59 -0700 Subject: [PATCH 2/4] merge --- CMakeLists.txt | 1 + assignment-server/CMakeLists.txt | 13 + assignment-server/src/main.cpp | 57 ++++ audio-mixer/src/main.cpp | 2 +- eve/CMakeLists.txt | 2 +- hifi.podspec | 15 +- interface/src/Application.cpp | 264 ++++++++++++++---- interface/src/Application.h | 4 + interface/src/Audio.cpp | 53 +++- interface/src/Audio.h | 18 +- interface/src/ToolsPalette.cpp | 9 + interface/src/ToolsPalette.h | 2 + interface/src/Util.cpp | 47 ++-- interface/src/Util.h | 2 +- interface/src/VoxelSystem.cpp | 44 ++- interface/src/VoxelSystem.h | 1 + interface/src/Webcam.cpp | 170 +++++------ interface/src/Webcam.h | 48 ++-- interface/src/avatar/Avatar.cpp | 19 +- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/AvatarVoxelSystem.h | 2 +- interface/src/avatar/Face.cpp | 24 +- interface/src/avatar/Head.cpp | 4 +- interface/src/avatar/Head.h | 4 +- interface/src/world.h | 1 - libraries/audio/src/AudioInjectionManager.cpp | 2 + libraries/audio/src/AudioInjector.cpp | 28 +- libraries/audio/src/AudioInjector.h | 6 +- libraries/avatars/src/Agent.cpp | 88 ++++++ libraries/avatars/src/Agent.h | 32 +++ libraries/avatars/src/AvatarData.cpp | 19 +- libraries/avatars/src/AvatarData.h | 9 +- libraries/avatars/src/HandData.h | 2 +- libraries/shared/CMakeLists.txt | 3 + libraries/shared/src/Node.cpp | 3 +- libraries/shared/src/Node.h | 2 +- libraries/shared/src/NodeData.h | 5 +- libraries/shared/src/NodeList.cpp | 11 +- libraries/shared/src/NodeList.h | 14 +- libraries/shared/src/OctalCode.cpp | 2 +- libraries/shared/src/PacketHeaders.cpp | 2 +- libraries/shared/src/PacketHeaders.h | 4 + libraries/shared/src/PerfStat.cpp | 2 +- libraries/shared/src/SharedUtil.cpp | 2 +- libraries/shared/src/SharedUtil.h | 2 +- libraries/shared/src/UDPSocket.cpp | 13 +- libraries/shared/src/UDPSocket.h | 1 + libraries/voxels/src/JurisdictionMap.cpp | 18 +- libraries/voxels/src/JurisdictionMap.h | 1 + voxel-server/src/README | 6 + voxel-server/src/main.cpp | 19 +- 51 files changed, 849 insertions(+), 254 deletions(-) create mode 100644 assignment-server/CMakeLists.txt create mode 100644 assignment-server/src/main.cpp create mode 100644 libraries/avatars/src/Agent.cpp create mode 100644 libraries/avatars/src/Agent.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d803ff373e..77ae85589d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) add_subdirectory(animation-server) +add_subdirectory(assignment-server) add_subdirectory(avatar-mixer) add_subdirectory(audio-mixer) add_subdirectory(domain-server) diff --git a/assignment-server/CMakeLists.txt b/assignment-server/CMakeLists.txt new file mode 100644 index 0000000000..c551cbf0a5 --- /dev/null +++ b/assignment-server/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.8) + +set(TARGET_NAME assignment-server) + +set(ROOT_DIR ..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +include(${MACRO_DIR}/SetupHifiProject.cmake) +setup_hifi_project(${TARGET_NAME} TRUE) + +# link in the shared library +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/assignment-server/src/main.cpp b/assignment-server/src/main.cpp new file mode 100644 index 0000000000..6cf7ddc952 --- /dev/null +++ b/assignment-server/src/main.cpp @@ -0,0 +1,57 @@ +// +// main.cpp +// assignment-server +// +// Created by Stephen Birarda on 7/1/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include +#include +#include + +#include +#include +#include + +const int MAX_PACKET_SIZE_BYTES = 1400; + +struct Assignment {}; + +int main(int argc, const char* argv[]) { + + std::queue assignmentQueue; + + sockaddr_in senderSocket; + unsigned char senderData[MAX_PACKET_SIZE_BYTES] = {}; + ssize_t receivedBytes = 0; + + UDPSocket serverSocket(ASSIGNMENT_SERVER_PORT); + + int numHeaderBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_SEND_ASSIGNMENT); + unsigned char assignmentPacket[numHeaderBytes + sizeof(char)]; + populateTypeAndVersion(assignmentPacket, PACKET_TYPE_SEND_ASSIGNMENT); + + while (true) { + if (serverSocket.receive((sockaddr*) &senderSocket, &senderData, &receivedBytes)) { + + // int numHeaderBytes = numBytesForPacketHeader(senderData); + + if (senderData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) { + // grab the FI assignment in the queue, if it exists + if (assignmentQueue.size() > 0) { + // Assignment firstAssignment = assignmentQueue.front(); + assignmentQueue.pop(); + + // send the assignment + serverSocket.send((sockaddr*) &senderSocket, assignmentPacket, sizeof(assignmentPacket)); + } + } else if (senderData[0] == PACKET_TYPE_SEND_ASSIGNMENT) { + Assignment newAssignment; + + // add this assignment to the queue + assignmentQueue.push(newAssignment); + } + } + } +} diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 9fc088a8bf..29c3fb7225 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -375,7 +375,7 @@ int main(int argc, const char* argv[]) { InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) node->getLinkedData(); if (memcmp(ringBuffer->getStreamIdentifier(), - packetData + 1, + packetData + numBytesForPacketHeader(packetData), STREAM_IDENTIFIER_NUM_BYTES) == 0) { // this is the matching stream, assign to matchingInjector and stop looking matchingInjector = &*node; diff --git a/eve/CMakeLists.txt b/eve/CMakeLists.txt index 0a7691b781..2b281f2783 100644 --- a/eve/CMakeLists.txt +++ b/eve/CMakeLists.txt @@ -18,4 +18,4 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) diff --git a/hifi.podspec b/hifi.podspec index 42ac7ac1aa..a14381ffb4 100644 --- a/hifi.podspec +++ b/hifi.podspec @@ -35,17 +35,24 @@ Pod::Spec.new do |s| # s.exclude_files = 'Classes/Exclude' s.subspec "shared" do |sp| - sp.source_files = "libraries/shared/src" - sp.public_header_files = "librares/shared/src" + sp.source_files = 'libraries/shared/src', 'libraries/shared/moc_*' sp.exclude_files = "libraries/shared/src/UrlReader.*" + sp.dependency 'glm' + sp.xcconfig = { 'CLANG_CXX_LIBRARY' => "libc++" } end s.subspec "audio" do |sp| sp.source_files = "libraries/audio/src" - sp.public_header_files = "libraries/audio/src" - sp.xcconfig = { 'CLANG_CXX_LIBRARY' => "libc++" } sp.dependency 'glm' end + + s.subspec "avatars" do |sp| + sp.source_files = 'libraries/avatars/src', 'libraries/avatars/moc_*' + sp.dependency 'glm' + end + + s.xcconfig = { 'HEADER_SEARCH_PATHS' => '${PODS_ROOT}/../../qt5-device/qtbase/include' } + s.libraries = 'libQtCoreCombined', 'libQt5Network', 'libQt5Script' # A list of file patterns which select the header files that should be # made available to the application. If the pattern is a directory then the diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aacd9f0667..a3bd6c4718 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -570,8 +570,9 @@ void Application::keyPressEvent(QKeyEvent* event) { if (_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()) { _myAvatar.getHand().setRaveGloveEffectsMode((QKeyEvent*)event); } - - bool shifted = event->modifiers().testFlag(Qt::ShiftModifier); + + bool isMeta = event->modifiers().testFlag(Qt::MetaModifier); + bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); switch (event->key()) { case Qt::Key_BracketLeft: _viewFrustumOffsetYaw -= 0.5; @@ -644,7 +645,13 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_C: - _myAvatar.setDriveKeys(DOWN, 1); + if (isShifted) { + _occlusionCulling->trigger(); + } else if (isMeta) { + chooseVoxelPaintColor(); + } else { + _myAvatar.setDriveKeys(DOWN, 1); + } break; case Qt::Key_W: @@ -652,7 +659,11 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_S: - _myAvatar.setDriveKeys(BACK, 1); + if (isShifted) { + doTreeStats(); + } else { + _myAvatar.setDriveKeys(BACK, 1); + } break; case Qt::Key_Space: @@ -661,11 +672,19 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_G: - goHome(); + if (isShifted) { + _gravityUse->trigger(); + } else { + _eyedropperMode->trigger(); + } break; case Qt::Key_A: - _myAvatar.setDriveKeys(ROT_LEFT, 1); + if (isShifted) { + _renderAtmosphereOn->trigger(); + } else { + _myAvatar.setDriveKeys(ROT_LEFT, 1); + } break; case Qt::Key_D: @@ -681,23 +700,23 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Up: - _myAvatar.setDriveKeys(shifted ? UP : FWD, 1); + _myAvatar.setDriveKeys(isShifted ? UP : FWD, 1); break; case Qt::Key_Down: - _myAvatar.setDriveKeys(shifted ? DOWN : BACK, 1); + _myAvatar.setDriveKeys(isShifted ? DOWN : BACK, 1); break; case Qt::Key_Left: - _myAvatar.setDriveKeys(shifted ? LEFT : ROT_LEFT, 1); + _myAvatar.setDriveKeys(isShifted ? LEFT : ROT_LEFT, 1); break; case Qt::Key_Right: - _myAvatar.setDriveKeys(shifted ? RIGHT : ROT_RIGHT, 1); + _myAvatar.setDriveKeys(isShifted ? RIGHT : ROT_RIGHT, 1); break; case Qt::Key_I: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -707,7 +726,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_K: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(-0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -717,7 +736,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_J: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(0, 0.002f, 0)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -727,7 +746,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_M: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(0, -0.002f, 0)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -737,7 +756,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_U: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(0, 0, -0.002f)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -747,7 +766,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_Y: - if (shifted) { + if (isShifted) { _myCamera.setEyeOffsetOrientation(glm::normalize( glm::quat(glm::vec3(0, 0, 0.002f)) * _myCamera.getEyeOffsetOrientation())); } else { @@ -755,12 +774,62 @@ void Application::keyPressEvent(QKeyEvent* event) { } resizeGL(_glWidget->width(), _glWidget->height()); break; + case Qt::Key_N: + _noise->trigger(); + break; + case Qt::Key_H: + _lookingInMirror->trigger(); + break; + case Qt::Key_F: + if (isShifted) { + _frustumOn->trigger(); + } else { + _fullScreenMode->trigger(); + } + break; + case Qt::Key_V: + if (isShifted) { + _renderVoxels->trigger(); + } else { + _addVoxelMode->trigger(); + } + break; + case Qt::Key_P: + _manualFirstPerson->trigger(); + break; + case Qt::Key_R: + if (isShifted) { + _frustumRenderModeAction->trigger(); + } else { + _deleteVoxelMode->trigger(); + } + break; + case Qt::Key_B: + _colorVoxelMode->trigger(); + break; + case Qt::Key_O: + if (isShifted) { + _viewFrustumFromOffset->trigger(); + } else { + _selectVoxelMode->trigger(); + } + break; + case Qt::Key_Slash: + _renderStatsOn->trigger(); + break; case Qt::Key_Backspace: case Qt::Key_Delete: if (_selectVoxelMode->isChecked()) { deleteVoxelUnderCursor(); } break; + case Qt::Key_Plus: + increaseAvatarSize(); + break; + case Qt::Key_Minus: + decreaseAvatarSize(); + break; + case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: @@ -859,7 +928,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { const bool MAKE_SOUND_ON_VOXEL_HOVER = false; const bool MAKE_SOUND_ON_VOXEL_CLICK = true; -const float HOVER_VOXEL_FREQUENCY = 14080.f; +const float HOVER_VOXEL_FREQUENCY = 7040.f; const float HOVER_VOXEL_DECAY = 0.999f; void Application::mousePressEvent(QMouseEvent* event) { @@ -872,8 +941,9 @@ void Application::mousePressEvent(QMouseEvent* event) { _mouseVoxelDragging = _mouseVoxel; _mousePressed = true; + maybeEditVoxelUnderCursor(); - if (!maybeEditVoxelUnderCursor()) { + if (!_palette.isActive()) { _pieMenu.mousePressEvent(_mouseX, _mouseY); } @@ -1617,14 +1687,25 @@ void Application::importVoxels() { const int SVO_TYPE_NAME_LENGTH = 4; const int SCH_TYPE_NAME_LENGTH = 10; + // assume this is where we'll place it if filename doesn't have tiling + int unspecifiedColumnNum = 1; + int unspecifiedRowNum = 1; + + // if they select multiple files, but they don't specify the tiling, we + // will tile them to this size + int unspecifiedSquare = (sqrt(fileNameStringList.size()) + 0.5); + qDebug("unspecifiedSquare: %d\n", unspecifiedSquare); + for (int i = 0; i < fileNameStringList.size(); i++) { QString fileNameString = fileNameStringList.at(i); + QString extension; QByteArray fileNameAscii = fileNameString.toLocal8Bit(); const char* fileName = fileNameAscii.data(); int fileTypeNameLength = 0; VoxelTree importVoxels; if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { + extension = QString(".png"); QImage pngImage = QImage(fileName); fileTypeNameLength = PNG_TYPE_NAME_LENGTH; if (pngImage.height() != pngImage.width()) { @@ -1642,25 +1723,67 @@ void Application::importVoxels() { importVoxels.readFromSquareARGB32Pixels(pixels, pngImage.height()); } else if (fileNameString.endsWith(".svo", Qt::CaseInsensitive)) { + extension = QString(".svo"); importVoxels.readFromSVOFile(fileName); fileTypeNameLength = SVO_TYPE_NAME_LENGTH; } else if (fileNameString.endsWith(".schematic", Qt::CaseInsensitive)) { + extension = QString(".schematic"); importVoxels.readFromSchematicFile(fileName); fileTypeNameLength = SCH_TYPE_NAME_LENGTH; } + + // Where we plan to place this + int columnNum = 1; + int rowNum = 1; + bool isTileLocationUnspecified = false; - int indexOfFirstPeriod = fileNameString.indexOf('.'); + // If we're in multi-file mode, then look for tiling specification in the file name + if (fileNameStringList.size() > 1) { + int indexOfFirstPeriod = fileNameString.indexOf('.'); - QString fileCoord = fileNameString.mid(indexOfFirstPeriod + 1, - fileNameString.length() - indexOfFirstPeriod - fileTypeNameLength - 1); + //qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod); - indexOfFirstPeriod = fileCoord.indexOf('.'); - QString columnNumString = fileCoord.right(fileCoord.length() - indexOfFirstPeriod - 1); - QString rowNumString = fileCoord.left(indexOfFirstPeriod); + // If the first period, is the extension, then this is not a grid name; + if (fileNameString.mid(indexOfFirstPeriod, fileNameString.length() - indexOfFirstPeriod) == extension) { + qDebug("not a valid grid name... treat like tile Location Unspecified\n"); + isTileLocationUnspecified = true; + } else { + QString fileCoord = fileNameString.mid(indexOfFirstPeriod + 1, + fileNameString.length() - indexOfFirstPeriod - fileTypeNameLength - 1); - int columnNum = columnNumString.toFloat(); - int rowNum = rowNumString.toFloat(); + //qDebug() << "fileCoord: " << fileCoord << "\n"; + indexOfFirstPeriod = fileCoord.indexOf('.'); + + //qDebug("indexOfFirstPeriod: %d\n", indexOfFirstPeriod); + + QString columnNumString = fileCoord.right(fileCoord.length() - indexOfFirstPeriod - 1); + QString rowNumString = fileCoord.left(indexOfFirstPeriod); + + //qDebug() << "columnNumString: " << columnNumString << "\n"; + //qDebug() << "rowNumString: " << rowNumString << "\n"; + + columnNum = columnNumString.toFloat(); + rowNum = rowNumString.toFloat(); + + // If there are no "grid sections" in the filename, then we're going to get + if (columnNum < 1 || rowNum < 1) { + qDebug("not a valid grid name... treat like tile Location Unspecified\n"); + isTileLocationUnspecified = true; + } + } + } + + if (isTileLocationUnspecified) { + qDebug("tile Location is Unspecified... \n"); + columnNum = unspecifiedColumnNum; + rowNum = unspecifiedRowNum; + unspecifiedColumnNum++; + if (unspecifiedColumnNum > unspecifiedSquare) { + unspecifiedColumnNum = 1; + unspecifiedRowNum++; + } + } qDebug("columnNum: %d\t rowNum: %d\n", columnNum, rowNum); _mouseVoxel.x = originalX + (columnNum - 1) * _mouseVoxel.s; @@ -1791,19 +1914,21 @@ void Application::initMenu() { _window->setMenuBar(menuBar); QMenu* fileMenu = menuBar->addMenu("File"); - fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q); + QAction* quitAction = fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q); + quitAction->setMenuRole(QAction::QuitRole); QMenu* editMenu = menuBar->addMenu("Edit"); - editMenu->addAction("Preferences...", this, SLOT(editPreferences())); + QAction* preferencesAction = editMenu->addAction("Preferences...", this, SLOT(editPreferences()), Qt::CTRL | Qt::Key_Comma); + preferencesAction->setMenuRole(QAction::PreferencesRole); QMenu* pairMenu = menuBar->addMenu("Pair"); pairMenu->addAction("Pair", this, SLOT(pair())); QMenu* optionsMenu = menuBar->addMenu("Options"); (_lookingInMirror = optionsMenu->addAction("Mirror", this, SLOT(setRenderMirrored(bool)), Qt::Key_H))->setCheckable(true); - (_echoAudioMode = optionsMenu->addAction("Echo Audio"))->setCheckable(true); - optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N)->setCheckable(true); + + (_noise = optionsMenu->addAction("Noise", this, SLOT(setNoise(bool)), Qt::Key_N))->setCheckable(true); (_gyroLook = optionsMenu->addAction("Smooth Gyro Look"))->setCheckable(true); _gyroLook->setChecked(true); (_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true); @@ -1819,7 +1944,11 @@ void Application::initMenu() { optionsMenu->addAction("Webcam", &_webcam, SLOT(setEnabled(bool)))->setCheckable(true); optionsMenu->addAction("Toggle Skeleton Tracking", &_webcam, SLOT(setSkeletonTrackingOn(bool)))->setCheckable(true); optionsMenu->addAction("Cycle Webcam Send Mode", _webcam.getGrabber(), SLOT(cycleVideoSendMode())); - optionsMenu->addAction("Go Home", this, SLOT(goHome())); + optionsMenu->addAction("Go Home", this, SLOT(goHome()), Qt::CTRL | Qt::Key_G); + + QMenu* audioMenu = menuBar->addMenu("Audio"); + (_echoAudioMode = audioMenu->addAction("Echo Audio"))->setCheckable(true); + _rawAudioMicrophoneMix = audioMenu->addAction("Mix RAW Song", this, SLOT(toggleMixedSong())); QMenu* renderMenu = menuBar->addMenu("Render"); (_renderVoxels = renderMenu->addAction("Voxels", this, SLOT(setRenderVoxels(bool)), Qt::SHIFT | Qt::Key_V))->setCheckable(true); @@ -1850,8 +1979,8 @@ void Application::initMenu() { "First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true); (_manualThirdPerson = renderMenu->addAction( "Third Person", this, SLOT(setRenderThirdPerson(bool))))->setCheckable(true); - renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::ALT | Qt::Key_Plus); - renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::ALT | Qt::Key_Minus); + renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::Key_Plus); + renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::Key_Minus); QMenu* toolsMenu = menuBar->addMenu("Tools"); @@ -1888,8 +2017,8 @@ void Application::initMenu() { "Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_G))->setCheckable(true); _voxelModeActions->addAction(_eyedropperMode); - voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); - voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn); voxelMenu->addAction("Reset Swatch Colors", this, SLOT(resetSwatchColors())); _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, @@ -1916,7 +2045,7 @@ void Application::initMenu() { (_viewFrustumFromOffset = frustumMenu->addAction( "Use Offset Camera", this, SLOT(setFrustumOffset(bool)), Qt::SHIFT | Qt::Key_O))->setCheckable(true); _frustumRenderModeAction = frustumMenu->addAction( - "Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R); + "Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R); updateFrustumRenderModeAction(); debugMenu->addAction("Run Timing Tests", this, SLOT(runTests())); @@ -1940,8 +2069,8 @@ void Application::initMenu() { debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); debugMenu->addAction("Use Lower Resolution While Moving", this, SLOT(setWantsLowResMoving(bool)))->setCheckable(true); debugMenu->addAction("Disable Delta Sending", this, SLOT(disableDeltaSending(bool)))->setCheckable(true); - debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)), - Qt::SHIFT | Qt::Key_C)->setCheckable(true); + (_occlusionCulling = debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)), + Qt::SHIFT | Qt::Key_C))->setCheckable(true); (_renderCoverageMap = debugMenu->addAction("Render Coverage Map"))->setCheckable(true); _renderCoverageMap->setShortcut(Qt::SHIFT | Qt::CTRL | Qt::Key_O); @@ -1990,6 +2119,22 @@ void Application::setListenModeSingleSource() { } } +void Application::toggleMixedSong() { + if (_audio.getSongFileBytes() == 0) { + QString filename = QFileDialog::getOpenFileName(_glWidget, + tr("Choose RAW Audio file"), + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + tr("RAW Audio file (*.raw)")); + + QByteArray filenameArray = filename.toLocal8Bit(); + _audio.importSongToMixWithMicrophone(filenameArray.data()); + _rawAudioMicrophoneMix->setText("Stop Mixing Song"); + } else { + _audio.stopMixingSongWithMicrophone(); + _rawAudioMicrophoneMix->setText("Mix RAW Song"); + } +} + void Application::updateFrustumRenderModeAction() { switch (_frustumDrawingMode) { @@ -2100,7 +2245,7 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3 Avatar* avatar = (Avatar *) node->getLinkedData(); glm::vec3 headPosition = avatar->getHead().getPosition(); if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS)) { - eyePosition = avatar->getHead().getEyeLevelPosition(); + eyePosition = avatar->getHead().getEyePosition(); _lookatIndicatorScale = avatar->getScale(); _lookatOtherPosition = headPosition; nodeID = avatar->getOwningNode()->getNodeID(); @@ -2149,21 +2294,21 @@ void Application::update(float deltaTime) { _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); // Set where I am looking based on my mouse ray (so that other people can see) - glm::vec3 eyePosition; + glm::vec3 lookAtSpot; - _isLookingAtOtherAvatar = isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, eyePosition); + _isLookingAtOtherAvatar = isLookingAtOtherAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); if (_isLookingAtOtherAvatar) { // If the mouse is over another avatar's head... - glm::vec3 myLookAtFromMouse(eyePosition); - _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); + _myAvatar.getHead().setLookAtPosition(lookAtSpot); } else if (_isHoverVoxel) { // Look at the hovered voxel - glm::vec3 lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); + lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); _myAvatar.getHead().setLookAtPosition(lookAtSpot); } else { // Just look in direction of the mouse ray - glm::vec3 myLookAtFromMouse(mouseRayOrigin + mouseRayDirection); - _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); + const float FAR_AWAY_STARE = TREE_SCALE; + lookAtSpot = mouseRayOrigin + mouseRayDirection * FAR_AWAY_STARE; + _myAvatar.getHead().setLookAtPosition(lookAtSpot); } // Find the voxel we are hovering over, and respond if clicked @@ -2173,15 +2318,21 @@ void Application::update(float deltaTime) { // If we have clicked on a voxel, update it's color if (_isHoverVoxelSounding) { VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); - float bright = _audio.getCollisionSoundMagnitude(); - nodeColor clickColor = { 255 * bright + _hoverVoxelOriginalColor[0] * (1.f - bright), - _hoverVoxelOriginalColor[1] * (1.f - bright), - _hoverVoxelOriginalColor[2] * (1.f - bright), 1 }; - hoveredNode->setColor(clickColor); - if (bright < 0.01f) { - hoveredNode->setColor(_hoverVoxelOriginalColor); + if (hoveredNode) { + float bright = _audio.getCollisionSoundMagnitude(); + nodeColor clickColor = { 255 * bright + _hoverVoxelOriginalColor[0] * (1.f - bright), + _hoverVoxelOriginalColor[1] * (1.f - bright), + _hoverVoxelOriginalColor[2] * (1.f - bright), 1 }; + hoveredNode->setColor(clickColor); + if (bright < 0.01f) { + hoveredNode->setColor(_hoverVoxelOriginalColor); + _isHoverVoxelSounding = false; + } + } else { + // Voxel is not found, clear all _isHoverVoxelSounding = false; - } + _isHoverVoxel = false; + } } else { // Check for a new hover voxel glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); @@ -2732,7 +2883,7 @@ void Application::displaySide(Camera& whichCamera) { glRotatef(-glm::angle(rotation), axis.x, axis.y, axis.z); glTranslatef(-whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z); - + // Setup 3D lights (after the camera transform, so that they are positioned in world space) glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -2849,6 +3000,7 @@ void Application::displaySide(Camera& whichCamera) { _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); } _myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked()); + _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); if (_renderLookatIndicatorOn->isChecked() && _isLookingAtOtherAvatar) { renderLookatIndicator(_lookatOtherPosition, whichCamera); @@ -2862,7 +3014,7 @@ void Application::displaySide(Camera& whichCamera) { } // Render the world box - if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { render_world_box(); } + if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { renderWorldBox(); } // brad's frustum for debugging if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum); diff --git a/interface/src/Application.h b/interface/src/Application.h index dc2476cc86..4745196bf4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -177,6 +177,7 @@ private slots: void setListenModeNormal(); void setListenModePoint(); void setListenModeSingleSource(); + void toggleMixedSong(); void renderCoverageMap(); @@ -288,6 +289,9 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; QAction* _settingsAutosave; // Whether settings are saved automatically + QAction* _rawAudioMicrophoneMix; // Mixing of a RAW audio file with microphone stream for rave gloves + QAction* _noise; + QAction* _occlusionCulling; QAction* _renderCoverageMapV2; QAction* _renderCoverageMap; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a9aa61a34e..f5a6479985 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -8,13 +8,11 @@ #ifndef _WIN32 #include -#include #include #include #include - #include #include #include @@ -155,8 +153,38 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); currentPacketPtr += sizeof(headOrientation); + // check if we have a song to add to our audio + if (_songFileBytes > 0 && _songFileStream->tellg() <= _songFileBytes) { + // iterate over BUFFER_LENGTH_SAMPLES_PER_CHANNEL from the song file and add that to our audio + for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + int16_t songSample = 0; + + _songFileStream->read((char*) &songSample, sizeof(songSample)); + + // attenuate the song samples since they will be loud + const float SONG_SAMPLE_ATTENUATION = 0.25; + songSample *= SONG_SAMPLE_ATTENUATION; + + // add the song sample to the output and input buffersg + inputLeft[i] = inputLeft[i] + songSample; + outputLeft[i] = outputLeft[i] + songSample; + outputRight[i] = outputLeft[i] + songSample; + } + } else if (_songFileStream) { + // close the stream + _songFileStream->close(); + + // delete the _songFileStream + delete _songFileStream; + _songFileStream = NULL; + + // reset the _songFileBytes back to zero + _songFileBytes = 0; + } + // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); + nodeList->getNodeSocket()->send((sockaddr*) &audioSocket, dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); @@ -384,6 +412,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f), + _songFileStream(NULL), + _songFileBytes(0), _listenMode(AudioRingBuffer::NORMAL), _listenRadius(0.0f) { @@ -456,6 +486,25 @@ Audio::~Audio() { delete[] _echoSamplesLeft; } + +void Audio::importSongToMixWithMicrophone(const char* filename) { + _songFileStream = new std::ifstream(filename); + + long begin = _songFileStream->tellg(); + _songFileStream->seekg(0, std::ios::end); + long end = _songFileStream->tellg(); + + // go back to the beginning + _songFileStream->seekg(0); + + _songFileBytes = end - begin; +} + +void Audio::stopMixingSongWithMicrophone() { + qDebug("Stop mixing called!"); + _songFileBytes = 0; +} + void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes) { const int NUM_INITIAL_PACKETS_DISCARD = 3; const int STANDARD_DEVIATION_SAMPLE_COUNT = 500; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 2eb4e7ef70..249453c877 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -9,8 +9,13 @@ #ifndef __interface__Audio__ #define __interface__Audio__ +#include #include + +#include + #include + #include #include @@ -23,7 +28,8 @@ static const int PACKET_LENGTH_BYTES_PER_CHANNEL = PACKET_LENGTH_BYTES / 2; static const int PACKET_LENGTH_SAMPLES = PACKET_LENGTH_BYTES / sizeof(int16_t); static const int PACKET_LENGTH_SAMPLES_PER_CHANNEL = PACKET_LENGTH_SAMPLES / 2; -class Audio { +class Audio : public QObject { + Q_OBJECT public: // initializes audio I/O Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples); @@ -47,6 +53,7 @@ public: void startCollisionSound(float magnitude, float frequency, float noise, float duration); float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + int getSongFileBytes() { return _songFileBytes; } void ping(); @@ -60,8 +67,13 @@ public: void addListenSource(int sourceID); void removeListenSource(int sourceID); void clearListenSources(); + + void importSongToMixWithMicrophone(const char* filename); + +public slots: + void stopMixingSongWithMicrophone(); -private: +private: PaStream* _stream; AudioRingBuffer _ringBuffer; Oscilloscope* _scope; @@ -96,6 +108,8 @@ private: float _collisionSoundDuration; int _proceduralEffectSample; float _heartbeatMagnitude; + std::ifstream* _songFileStream; + int _songFileBytes; AudioRingBuffer::ListenMode _listenMode; float _listenRadius; diff --git a/interface/src/ToolsPalette.cpp b/interface/src/ToolsPalette.cpp index 341a128f8a..58ec12dc92 100644 --- a/interface/src/ToolsPalette.cpp +++ b/interface/src/ToolsPalette.cpp @@ -77,3 +77,12 @@ void ToolsPalette::render(int screenWidth, int screenHeight) { glPopMatrix(); } + +bool ToolsPalette::isActive() { + for (unsigned int i = 0; i < _tools.size(); ++i) { + if (_tools[i]->isActive()) { + return true; + } + } + return false; +} diff --git a/interface/src/ToolsPalette.h b/interface/src/ToolsPalette.h index 0b4ee95524..b6d446f51d 100644 --- a/interface/src/ToolsPalette.h +++ b/interface/src/ToolsPalette.h @@ -20,6 +20,8 @@ public: void addTool(Tool* tool); void render(int screenWidth, int screenHeight); + bool isActive(); + private: QImage _textureImage; GLuint _textureID; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 5d77c124f4..61b9b2d7ca 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -223,39 +223,54 @@ void noiseTest(int w, int h) { glEnd(); } -void render_world_box() { - // Show edge of world +void renderWorldBox() { + // Show edge of world + float red[] = {1, 0, 0}; + float green[] = {0, 1, 0}; + float blue[] = {0, 0, 1}; + float gray[] = {0.5, 0.5, 0.5}; + glDisable(GL_LIGHTING); - glColor4f(1.0, 1.0, 1.0, 1.0); glLineWidth(1.0); glBegin(GL_LINES); - glColor3f(1, 0, 0); + glColor3fv(red); glVertex3f(0, 0, 0); - glVertex3f(WORLD_SIZE, 0, 0); - glColor3f(0, 1, 0); + glVertex3f(TREE_SCALE, 0, 0); + glColor3fv(green); glVertex3f(0, 0, 0); - glVertex3f(0, WORLD_SIZE, 0); - glColor3f(0, 0, 1); + glVertex3f(0, TREE_SCALE, 0); + glColor3fv(blue); glVertex3f(0, 0, 0); - glVertex3f(0, 0, WORLD_SIZE); + glVertex3f(0, 0, TREE_SCALE); + glColor3fv(gray); + glVertex3f(0, 0, TREE_SCALE); + glVertex3f(TREE_SCALE, 0, TREE_SCALE); + glVertex3f(TREE_SCALE, 0, TREE_SCALE); + glVertex3f(TREE_SCALE, 0, 0); glEnd(); - // Draw little marker dots along the axis + // Draw marker dots at very end glEnable(GL_LIGHTING); glPushMatrix(); - glTranslatef(WORLD_SIZE, 0, 0); - glColor3f(1, 0, 0); + glTranslatef(TREE_SCALE, 0, 0); + glColor3fv(red); glutSolidSphere(0.125, 10, 10); glPopMatrix(); glPushMatrix(); - glTranslatef(0, WORLD_SIZE, 0); - glColor3f(0, 1, 0); + glTranslatef(0, TREE_SCALE, 0); + glColor3fv(green); glutSolidSphere(0.125, 10, 10); glPopMatrix(); glPushMatrix(); - glTranslatef(0, 0, WORLD_SIZE); - glColor3f(0, 0, 1); + glTranslatef(0, 0, TREE_SCALE); + glColor3fv(blue); glutSolidSphere(0.125, 10, 10); glPopMatrix(); + glPushMatrix(); + glColor3fv(gray); + glTranslatef(TREE_SCALE, 0, TREE_SCALE); + glutSolidSphere(0.125, 10, 10); + glPopMatrix(); + } double diffclock(timeval *clock1,timeval *clock2) diff --git a/interface/src/Util.h b/interface/src/Util.h index 67ffebf4b3..6fc797e3e3 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -33,7 +33,7 @@ float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float float randFloat(); const glm::vec3 randVector(); -void render_world_box(); +void renderWorldBox(); int widthText(float scale, int mono, char const* string); float widthChar(float scale, int mono, char ch); void drawtext(int x, int y, float scale, float rotate, float thick, int mono, diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2631e255fb..65d819eddc 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -73,10 +73,29 @@ void VoxelSystem::nodeDeleted(VoxelNode* node) { } } +// returns an available index, starts by reusing a previously freed index, but if there isn't one available +// it will use the end of the VBO array and grow our accounting of that array. +// and makes the index available for some other node to use +glBufferIndex VoxelSystem::getNextBufferIndex() { + glBufferIndex output = GLBUFFER_INDEX_UNKNOWN; + // if there's a free index, use it... + if (_freeIndexes.size() > 0) { + output = _freeIndexes.back(); + _freeIndexes.pop_back(); + } else { + output = _voxelsInWriteArrays; + _voxelsInWriteArrays++; + } + return output; +} + +// Doesn't actually clean up the VBOs for the index, but does release responsibility of the index from the VoxelNode, +// and makes the index available for some other node to use void VoxelSystem::freeBufferIndex(glBufferIndex index) { _freeIndexes.push_back(index); } +// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". void VoxelSystem::clearFreeBufferIndexes() { for (int i = 0; i < _freeIndexes.size(); i++) { glBufferIndex nodeIndex = _freeIndexes[i]; @@ -246,12 +265,13 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _callsToTreesToArrays++; if (_writeRenderFullVBO) { _voxelsInWriteArrays = 0; // reset our VBO + _freeIndexes.clear(); // reset our free indexes } _voxelsUpdated = newTreeToArrays(_tree->rootNode); _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean if (_writeRenderFullVBO) { - _abandonedVBOSlots = 0; // reset the count of our abandoned slots + _abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier???? } // since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are @@ -399,15 +419,13 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { if (node->getShouldRender()) { glm::vec3 startVertex = node->getCorner(); float voxelScale = node->getScale(); - glBufferIndex nodeIndex = _voxelsInWriteArrays; + glBufferIndex nodeIndex = getNextBufferIndex(); // populate the array with points for the 8 vertices // and RGB color for each added vertex updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); node->setBufferIndex(nodeIndex); node->setVoxelSystem(this); - _writeVoxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode - _voxelsInWriteArrays++; // our know vertices in the arrays return 1; // rendered } else { node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); @@ -444,10 +462,9 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { if (node->isKnownBufferIndex()) { nodeIndex = node->getBufferIndex(); } else { - nodeIndex = _voxelsInWriteArrays; + nodeIndex = getNextBufferIndex(); node->setBufferIndex(nodeIndex); node->setVoxelSystem(this); - _voxelsInWriteArrays++; } _writeVoxelDirtyArray[nodeIndex] = true; @@ -843,13 +860,18 @@ bool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraDat void VoxelSystem::falseColorizeBySource() { _nodeCount = 0; colorizeBySourceArgs args; - const int NUMBER_OF_COLOR_GROUPS = 3; + const int NUMBER_OF_COLOR_GROUPS = 6; const unsigned char MIN_COLOR = 128; int voxelServerCount = 0; - groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { groupColor(255, 0, 0), - groupColor(0, 255, 0), - groupColor(0, 0, 255)}; - + groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { + groupColor(255, 0, 0), + groupColor( 0, 255, 0), + groupColor( 0, 0, 255), + groupColor(255, 0, 255), + groupColor( 0, 255, 255), + groupColor(255, 255, 255) + }; + // create a bunch of colors we'll use during colorization NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index ef7c33ee43..6c6bf261f9 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -200,6 +200,7 @@ private: void freeBufferIndex(glBufferIndex index); void clearFreeBufferIndexes(); + glBufferIndex getNextBufferIndex(); bool _falseColorizeBySource; int _dataSourceID; diff --git a/interface/src/Webcam.cpp b/interface/src/Webcam.cpp index 8fdf5f8687..4d2edcac37 100644 --- a/interface/src/Webcam.cpp +++ b/interface/src/Webcam.cpp @@ -47,11 +47,11 @@ void Webcam::setEnabled(bool enabled) { _grabberThread.start(); _startTimestamp = 0; _frameCount = 0; - + // let the grabber know we're ready for the first frame QMetaObject::invokeMethod(_grabber, "reset"); QMetaObject::invokeMethod(_grabber, "grabFrame"); - + } else { QMetaObject::invokeMethod(_grabber, "shutdown"); _active = false; @@ -63,7 +63,7 @@ const float UNINITIALIZED_FACE_DEPTH = 0.0f; void Webcam::reset() { _initialFaceRect = RotatedRect(); _initialFaceDepth = UNINITIALIZED_FACE_DEPTH; - + if (_enabled) { // send a message to the grabber QMetaObject::invokeMethod(_grabber, "reset"); @@ -80,7 +80,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) { int previewWidth = _textureSize.width * PREVIEW_HEIGHT / _textureSize.height; int top = screenHeight - 600; int left = screenWidth - previewWidth - 10; - + glTexCoord2f(0, 0); glVertex2f(left, top); glTexCoord2f(1, 0); @@ -90,7 +90,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) { glTexCoord2f(0, 1); glVertex2f(left, top + PREVIEW_HEIGHT); glEnd(); - + if (_depthTextureID != 0) { glBindTexture(GL_TEXTURE_2D, _depthTextureID); glBegin(GL_QUADS); @@ -103,10 +103,10 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) { glTexCoord2f(0, 1); glVertex2f(left, top); glEnd(); - + glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); - + if (!_joints.isEmpty()) { glColor3f(1.0f, 0.0f, 0.0f); glPointSize(4.0f); @@ -125,7 +125,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) { glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } - + glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_LINE_LOOP); Point2f facePoints[4]; @@ -137,7 +137,7 @@ void Webcam::renderPreview(int screenWidth, int screenHeight) { glVertex2f(left + facePoints[2].x * xScale, top + facePoints[2].y * yScale); glVertex2f(left + facePoints[3].x * xScale, top + facePoints[3].y * yScale); glEnd(); - + const int MAX_FPS_CHARACTERS = 30; char fps[MAX_FPS_CHARACTERS]; sprintf(fps, "FPS: %d", (int)(roundf(_frameCount * 1000000.0f / (usecTimestampNow() - _startTimestamp)))); @@ -149,7 +149,7 @@ Webcam::~Webcam() { // stop the grabber thread _grabberThread.quit(); _grabberThread.wait(); - + delete _grabber; } @@ -166,13 +166,13 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF 0, format, GL_UNSIGNED_BYTE, colorImage.imageData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qDebug("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height); - + } else { glBindTexture(GL_TEXTURE_2D, _colorTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _textureSize.width, _textureSize.height, format, GL_UNSIGNED_BYTE, colorImage.imageData); } - + if (!depth.empty()) { IplImage depthImage = depth; glPixelStorei(GL_UNPACK_ROW_LENGTH, depthImage.widthStep); @@ -183,23 +183,23 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF GL_LUMINANCE, GL_UNSIGNED_BYTE, depthImage.imageData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - + } else { glBindTexture(GL_TEXTURE_2D, _depthTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _textureSize.width, _textureSize.height, GL_LUMINANCE, - GL_UNSIGNED_BYTE, depthImage.imageData); + GL_UNSIGNED_BYTE, depthImage.imageData); } } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glBindTexture(GL_TEXTURE_2D, 0); - + // store our various data, update our frame count for fps computation _aspectRatio = aspectRatio; _faceRect = faceRect; _sending = sending; _joints = _skeletonTrackingOn ? joints : JointVector(); _frameCount++; - + const int MAX_FPS = 60; const int MIN_FRAME_DELAY = 1000000 / MAX_FPS; uint64_t now = usecTimestampNow(); @@ -210,14 +210,14 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF remaining -= (now - _lastFrameTimestamp); } _lastFrameTimestamp = now; - + // see if we have joint data if (!_joints.isEmpty()) { _estimatedJoints.resize(NUM_AVATAR_JOINTS); glm::vec3 origin; if (_joints[AVATAR_JOINT_LEFT_HIP].isValid && _joints[AVATAR_JOINT_RIGHT_HIP].isValid) { origin = glm::mix(_joints[AVATAR_JOINT_LEFT_HIP].position, _joints[AVATAR_JOINT_RIGHT_HIP].position, 0.5f); - + } else if (_joints[AVATAR_JOINT_TORSO].isValid) { const glm::vec3 TORSO_TO_PELVIS = glm::vec3(0.0f, -0.09f, -0.01f); origin = _joints[AVATAR_JOINT_TORSO].position + TORSO_TO_PELVIS; @@ -235,27 +235,27 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF } _estimatedRotation = safeEulerAngles(_estimatedJoints[AVATAR_JOINT_HEAD_BASE].rotation); _estimatedPosition = _estimatedJoints[AVATAR_JOINT_HEAD_BASE].position; - + } else { // roll is just the angle of the face rect const float ROTATION_SMOOTHING = 0.95f; _estimatedRotation.z = glm::mix(_faceRect.angle, _estimatedRotation.z, ROTATION_SMOOTHING); - + // determine position based on translation and scaling of the face rect/mean face depth if (_initialFaceRect.size.area() == 0) { _initialFaceRect = _faceRect; _estimatedPosition = glm::vec3(); _initialFaceDepth = midFaceDepth; - + } else { float proportion, z; if (midFaceDepth == UNINITIALIZED_FACE_DEPTH) { proportion = sqrtf(_initialFaceRect.size.area() / (float)_faceRect.size.area()); const float INITIAL_DISTANCE_TO_CAMERA = 0.333f; - z = INITIAL_DISTANCE_TO_CAMERA * proportion - INITIAL_DISTANCE_TO_CAMERA; - + z = INITIAL_DISTANCE_TO_CAMERA * proportion - INITIAL_DISTANCE_TO_CAMERA; + } else { - z = (midFaceDepth - _initialFaceDepth) * METERS_PER_MM; + z = (midFaceDepth - _initialFaceDepth) * METERS_PER_MM; proportion = midFaceDepth / _initialFaceDepth; } const float POSITION_SCALE = 0.5f; @@ -265,10 +265,10 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, float midF z); } } - + // note that we have data _active = true; - + // let the grabber know we're ready for the next frame QTimer::singleShot(qMax((int)remaining / 1000, 0), _grabber, SLOT(grabFrame())); } @@ -289,21 +289,21 @@ static AvatarJointID xnToAvatarJoint(XnSkeletonJoint joint) { case XN_SKEL_HEAD: return AVATAR_JOINT_HEAD_TOP; case XN_SKEL_NECK: return AVATAR_JOINT_HEAD_BASE; case XN_SKEL_TORSO: return AVATAR_JOINT_CHEST; - + case XN_SKEL_LEFT_SHOULDER: return AVATAR_JOINT_RIGHT_ELBOW; case XN_SKEL_LEFT_ELBOW: return AVATAR_JOINT_RIGHT_WRIST; - + case XN_SKEL_RIGHT_SHOULDER: return AVATAR_JOINT_LEFT_ELBOW; case XN_SKEL_RIGHT_ELBOW: return AVATAR_JOINT_LEFT_WRIST; - + case XN_SKEL_LEFT_HIP: return AVATAR_JOINT_RIGHT_KNEE; case XN_SKEL_LEFT_KNEE: return AVATAR_JOINT_RIGHT_HEEL; case XN_SKEL_LEFT_FOOT: return AVATAR_JOINT_RIGHT_TOES; - + case XN_SKEL_RIGHT_HIP: return AVATAR_JOINT_LEFT_KNEE; case XN_SKEL_RIGHT_KNEE: return AVATAR_JOINT_LEFT_HEEL; case XN_SKEL_RIGHT_FOOT: return AVATAR_JOINT_LEFT_TOES; - + default: return AVATAR_JOINT_NULL; } } @@ -312,19 +312,19 @@ static int getParentJoint(XnSkeletonJoint joint) { switch (joint) { case XN_SKEL_HEAD: return XN_SKEL_NECK; case XN_SKEL_TORSO: return -1; - + case XN_SKEL_LEFT_ELBOW: return XN_SKEL_LEFT_SHOULDER; case XN_SKEL_LEFT_HAND: return XN_SKEL_LEFT_ELBOW; - + case XN_SKEL_RIGHT_ELBOW: return XN_SKEL_RIGHT_SHOULDER; case XN_SKEL_RIGHT_HAND: return XN_SKEL_RIGHT_ELBOW; - + case XN_SKEL_LEFT_KNEE: return XN_SKEL_LEFT_HIP; case XN_SKEL_LEFT_FOOT: return XN_SKEL_LEFT_KNEE; - + case XN_SKEL_RIGHT_KNEE: return XN_SKEL_RIGHT_HIP; case XN_SKEL_RIGHT_FOOT: return XN_SKEL_RIGHT_KNEE; - + default: return XN_SKEL_TORSO; } } @@ -359,7 +359,7 @@ static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability if (status == XN_CALIBRATION_STATUS_OK) { qDebug("Calibration completed for user %d.\n", id); capability.StartTracking(id); - + } else { qDebug("Calibration failed to user %d.\n", id); capability.RequestCalibration(id, true); @@ -370,7 +370,7 @@ static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability void FrameGrabber::cycleVideoSendMode() { _videoSendMode = (VideoSendMode)((_videoSendMode + 1) % VIDEO_SEND_MODE_COUNT); _searchWindow = cv::Rect(0, 0, 0, 0); - + destroyCodecs(); } @@ -391,7 +391,7 @@ void FrameGrabber::shutdown() { } destroyCodecs(); _initialized = false; - + thread()->quit(); } @@ -407,17 +407,17 @@ void FrameGrabber::grabFrame() { int format = GL_BGR; Mat color, depth; JointVector joints; - + #ifdef HAVE_OPENNI if (_depthGenerator.IsValid()) { _xnContext.WaitAnyUpdateAll(); color = Mat(_imageMetaData.YRes(), _imageMetaData.XRes(), CV_8UC3, (void*)_imageGenerator.GetImageMap()); format = GL_RGB; - + depth = Mat(_depthMetaData.YRes(), _depthMetaData.XRes(), CV_16UC1, (void*)_depthGenerator.GetDepthMap()); - + _userID = 0; - XnUInt16 userCount = 1; + XnUInt16 userCount = 1; _userGenerator.GetUsers(&_userID, userCount); if (userCount > 0 && _userGenerator.GetSkeletonCap().IsTracking(_userID)) { joints.resize(NUM_AVATAR_JOINTS); @@ -464,10 +464,13 @@ void FrameGrabber::grabFrame() { } color = image; } - + + const int ENCODED_FACE_WIDTH = 128; + const int ENCODED_FACE_HEIGHT = 128; int encodedWidth; int encodedHeight; - int depthBitrateMultiplier = 1; + float colorBitrateMultiplier = 1.0f; + float depthBitrateMultiplier = 1.0f; Mat faceTransform; float aspectRatio; if (_videoSendMode == FULL_FRAME_VIDEO) { @@ -476,7 +479,8 @@ void FrameGrabber::grabFrame() { encodedWidth = color.cols; encodedHeight = color.rows; aspectRatio = FULL_FRAME_ASPECT; - + colorBitrateMultiplier = 4.0f; + } else { // if we don't have a search window (yet), try using the face cascade int channels = 0; @@ -488,7 +492,7 @@ void FrameGrabber::grabFrame() { if (!faces.empty()) { _searchWindow = faces.front(); updateHSVFrame(color, format); - + Mat faceHsv(_hsvFrame, _searchWindow); Mat faceMask(_mask, _searchWindow); int sizes = 30; @@ -501,42 +505,40 @@ void FrameGrabber::grabFrame() { RotatedRect faceRect; if (_searchWindow.area() > 0) { updateHSVFrame(color, format); - + calcBackProject(&_hsvFrame, 1, &channels, _histogram, _backProject, &range); bitwise_and(_backProject, _mask, _backProject); - + faceRect = CamShift(_backProject, _searchWindow, TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1)); Rect faceBounds = faceRect.boundingRect(); Rect imageBounds(0, 0, color.cols, color.rows); _searchWindow = Rect(clip(faceBounds.tl(), imageBounds), clip(faceBounds.br(), imageBounds)); } - const int ENCODED_FACE_WIDTH = 128; - const int ENCODED_FACE_HEIGHT = 128; encodedWidth = ENCODED_FACE_WIDTH; encodedHeight = ENCODED_FACE_HEIGHT; - depthBitrateMultiplier = 2; - + depthBitrateMultiplier = 2.0f; + // correct for 180 degree rotations if (faceRect.angle < -90.0f) { faceRect.angle += 180.0f; - + } else if (faceRect.angle > 90.0f) { faceRect.angle -= 180.0f; } - + // compute the smoothed face rect if (_smoothedFaceRect.size.area() == 0) { _smoothedFaceRect = faceRect; - + } else { const float FACE_RECT_SMOOTHING = 0.9f; _smoothedFaceRect.center.x = glm::mix(faceRect.center.x, _smoothedFaceRect.center.x, FACE_RECT_SMOOTHING); _smoothedFaceRect.center.y = glm::mix(faceRect.center.y, _smoothedFaceRect.center.y, FACE_RECT_SMOOTHING); _smoothedFaceRect.size.width = glm::mix(faceRect.size.width, _smoothedFaceRect.size.width, FACE_RECT_SMOOTHING); - _smoothedFaceRect.size.height = glm::mix(faceRect.size.height, _smoothedFaceRect.size.height, FACE_RECT_SMOOTHING); + _smoothedFaceRect.size.height = glm::mix(faceRect.size.height, _smoothedFaceRect.size.height, FACE_RECT_SMOOTHING); _smoothedFaceRect.angle = glm::mix(faceRect.angle, _smoothedFaceRect.angle, FACE_RECT_SMOOTHING); } - + // use the face rect to compute the face transform, aspect ratio Point2f sourcePoints[4]; _smoothedFaceRect.points(sourcePoints); @@ -544,7 +546,7 @@ void FrameGrabber::grabFrame() { faceTransform = getAffineTransform(sourcePoints, destPoints); aspectRatio = _smoothedFaceRect.size.width / _smoothedFaceRect.size.height; } - + const ushort ELEVEN_BIT_MINIMUM = 0; const uchar EIGHT_BIT_MIDPOINT = 128; double depthOffset; @@ -553,12 +555,12 @@ void FrameGrabber::grabFrame() { // warp the face depth without interpolation (because it will contain invalid zero values) _faceDepth.create(encodedHeight, encodedWidth, CV_16UC1); warpAffine(depth, _faceDepth, faceTransform, _faceDepth.size(), INTER_NEAREST); - + } else { _faceDepth = depth; } _smoothedFaceDepth.create(encodedHeight, encodedWidth, CV_16UC1); - + // smooth the depth over time const ushort ELEVEN_BIT_MAXIMUM = 2047; const float DEPTH_SMOOTHING = 0.25f; @@ -578,7 +580,7 @@ void FrameGrabber::grabFrame() { const ushort MINIMUM_DEPTH_OFFSET = 64; const float FIXED_MID_DEPTH = 640.0f; float midFaceDepth = (_videoSendMode == FACE_VIDEO) ? (minimumDepth + MINIMUM_DEPTH_OFFSET) : FIXED_MID_DEPTH; - + // smooth the mid face depth over time const float MID_FACE_DEPTH_SMOOTHING = 0.5f; _smoothedMidFaceDepth = (_smoothedMidFaceDepth == UNINITIALIZED_FACE_DEPTH) ? midFaceDepth : @@ -588,35 +590,35 @@ void FrameGrabber::grabFrame() { depthOffset = EIGHT_BIT_MIDPOINT - _smoothedMidFaceDepth; depth.convertTo(_grayDepthFrame, CV_8UC1, 1.0, depthOffset); } - + QByteArray payload; if (_videoSendMode != NO_VIDEO) { if (_colorCodec.name == 0) { // initialize encoder context(s) vpx_codec_enc_cfg_t codecConfig; vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &codecConfig, 0); - codecConfig.rc_target_bitrate = encodedWidth * encodedHeight * + codecConfig.rc_target_bitrate = ENCODED_FACE_WIDTH * ENCODED_FACE_HEIGHT * colorBitrateMultiplier * codecConfig.rc_target_bitrate / codecConfig.g_w / codecConfig.g_h; codecConfig.g_w = encodedWidth; codecConfig.g_h = encodedHeight; vpx_codec_enc_init(&_colorCodec, vpx_codec_vp8_cx(), &codecConfig, 0); - + if (!depth.empty()) { codecConfig.rc_target_bitrate *= depthBitrateMultiplier; vpx_codec_enc_init(&_depthCodec, vpx_codec_vp8_cx(), &codecConfig, 0); } } - + Mat transform; if (_videoSendMode == FACE_VIDEO) { // resize/rotate face into encoding rectangle _faceColor.create(encodedHeight, encodedWidth, CV_8UC3); warpAffine(color, _faceColor, faceTransform, _faceColor.size()); - + } else { _faceColor = color; } - + // convert from RGB to YV12: see http://www.fourcc.org/yuv.php and // http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor const int ENCODED_BITS_PER_Y = 8; @@ -651,7 +653,7 @@ void FrameGrabber::grabFrame() { uchar* tr = _faceColor.ptr(i, j + 1); uchar* bl = _faceColor.ptr(i + 1, j); uchar* br = _faceColor.ptr(i + 1, j + 1); - + ydest[0] = (tl[redIndex] * Y_RED_WEIGHT + tl[1] * Y_GREEN_WEIGHT + tl[blueIndex] * Y_BLUE_WEIGHT) >> 8; ydest[1] = (tr[redIndex] * Y_RED_WEIGHT + tr[1] * Y_GREEN_WEIGHT + tr[blueIndex] * Y_BLUE_WEIGHT) >> 8; ydest[vpxImage.stride[0]] = (bl[redIndex] * Y_RED_WEIGHT + bl[greenIndex] * @@ -659,12 +661,12 @@ void FrameGrabber::grabFrame() { ydest[vpxImage.stride[0] + 1] = (br[redIndex] * Y_RED_WEIGHT + br[greenIndex] * Y_GREEN_WEIGHT + br[blueIndex] * Y_BLUE_WEIGHT) >> 8; ydest += 2; - + int totalRed = tl[redIndex] + tr[redIndex] + bl[redIndex] + br[redIndex]; int totalGreen = tl[greenIndex] + tr[greenIndex] + bl[greenIndex] + br[greenIndex]; int totalBlue = tl[blueIndex] + tr[blueIndex] + bl[blueIndex] + br[blueIndex]; int totalY = (totalRed * Y_RED_WEIGHT + totalGreen * Y_GREEN_WEIGHT + totalBlue * Y_BLUE_WEIGHT) >> 8; - + *vdest++ = (((totalRed - totalY) * V_RED_WEIGHT) >> 10) + 128; *udest++ = (((totalBlue - totalY) * U_BLUE_WEIGHT) >> 10) + 128; } @@ -672,7 +674,7 @@ void FrameGrabber::grabFrame() { vline += vpxImage.stride[1]; uline += vpxImage.stride[2]; } - + // encode the frame vpx_codec_encode(&_colorCodec, &vpxImage, ++_frameCount, 1, 0, VPX_DL_REALTIME); @@ -689,7 +691,7 @@ void FrameGrabber::grabFrame() { payload.append((const char*)packet->data.frame.buf, packet->data.frame.sz); } } - + if (!depth.empty()) { // convert with mask uchar* yline = vpxImage.planes[0]; @@ -705,9 +707,9 @@ void FrameGrabber::grabFrame() { ushort tr = *_smoothedFaceDepth.ptr(i, j + 1); ushort bl = *_smoothedFaceDepth.ptr(i + 1, j); ushort br = *_smoothedFaceDepth.ptr(i + 1, j + 1); - + uchar mask = EIGHT_BIT_MAXIMUM; - + ydest[0] = (tl == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) : saturate_cast(tl + depthOffset); ydest[1] = (tr == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) : @@ -717,7 +719,7 @@ void FrameGrabber::grabFrame() { ydest[vpxImage.stride[0] + 1] = (br == ELEVEN_BIT_MINIMUM) ? (mask = EIGHT_BIT_MIDPOINT) : saturate_cast(br + depthOffset); ydest += 2; - + *vdest++ = mask; *udest++ = EIGHT_BIT_MIDPOINT; } @@ -725,7 +727,7 @@ void FrameGrabber::grabFrame() { vline += vpxImage.stride[1]; uline += vpxImage.stride[2]; } - + // encode the frame vpx_codec_encode(&_depthCodec, &vpxImage, _frameCount, 1, 0, VPX_DL_REALTIME); @@ -739,10 +741,10 @@ void FrameGrabber::grabFrame() { } } } - + QMetaObject::invokeMethod(Application::getInstance(), "sendAvatarFaceVideoMessage", Q_ARG(int, _frameCount), Q_ARG(QByteArray, payload)); - + QMetaObject::invokeMethod(Application::getInstance()->getWebcam(), "setFrame", Q_ARG(cv::Mat, color), Q_ARG(int, format), Q_ARG(cv::Mat, _grayDepthFrame), Q_ARG(float, _smoothedMidFaceDepth), Q_ARG(float, aspectRatio), Q_ARG(cv::RotatedRect, _smoothedFaceRect), Q_ARG(bool, !payload.isEmpty()), @@ -768,19 +770,19 @@ bool FrameGrabber::init() { _depthGenerator.GetMetaData(_depthMetaData); _imageGenerator.SetPixelFormat(XN_PIXEL_FORMAT_RGB24); _imageGenerator.GetMetaData(_imageMetaData); - + XnCallbackHandle userCallbacks, calibrationStartCallback, calibrationCompleteCallback; _userGenerator.RegisterUserCallbacks(newUser, lostUser, 0, userCallbacks); _userGenerator.GetSkeletonCap().RegisterToCalibrationStart(calibrationStarted, 0, calibrationStartCallback); _userGenerator.GetSkeletonCap().RegisterToCalibrationComplete(calibrationCompleted, 0, calibrationCompleteCallback); - + _userGenerator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_UPPER); - + // make the depth viewpoint match that of the video image if (_depthGenerator.IsCapabilitySupported(XN_CAPABILITY_ALTERNATIVE_VIEW_POINT)) { _depthGenerator.GetAlternativeViewPointCap().SetViewPoint(_imageGenerator); } - + _xnContext.StartGeneratingAll(); return true; } @@ -795,7 +797,7 @@ bool FrameGrabber::init() { const int IDEAL_FRAME_HEIGHT = 240; cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH, IDEAL_FRAME_WIDTH); cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT, IDEAL_FRAME_HEIGHT); - + #ifdef __APPLE__ configureCamera(0x5ac, 0x8510, false, 0.975, 0.5, 1.0, 0.5, true, 0.5); #else diff --git a/interface/src/Webcam.h b/interface/src/Webcam.h index 35c85cc63a..aee87e1bc7 100644 --- a/interface/src/Webcam.h +++ b/interface/src/Webcam.h @@ -38,9 +38,9 @@ typedef QVector JointVector; class Webcam : public QObject { Q_OBJECT - + public: - + Webcam(); ~Webcam(); @@ -49,34 +49,34 @@ public: bool isActive() const { return _active; } bool isSending() const { return _sending; } - + GLuint getColorTextureID() const { return _colorTextureID; } GLuint getDepthTextureID() const { return _depthTextureID; } const cv::Size2f& getTextureSize() const { return _textureSize; } - + float getAspectRatio() const { return _aspectRatio; } - + const cv::RotatedRect& getFaceRect() const { return _faceRect; } - + const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; } const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; } const JointVector& getEstimatedJoints() const { return _estimatedJoints; } void reset(); - void renderPreview(int screenWidth, int screenHeight); + void renderPreview(int screenWidth, int screenHeight); public slots: - + void setEnabled(bool enabled); void setFrame(const cv::Mat& color, int format, const cv::Mat& depth, float midFaceDepth, float aspectRatio, const cv::RotatedRect& faceRect, bool sending, const JointVector& joints); void setSkeletonTrackingOn(bool toggle) { _skeletonTrackingOn = toggle; }; private: - + QThread _grabberThread; FrameGrabber* _grabber; - + bool _enabled; bool _active; bool _sending; @@ -88,12 +88,12 @@ private: cv::RotatedRect _initialFaceRect; float _initialFaceDepth; JointVector _joints; - + uint64_t _startTimestamp; int _frameCount; - + uint64_t _lastFrameTimestamp; - + glm::vec3 _estimatedPosition; glm::vec3 _estimatedRotation; JointVector _estimatedJoints; @@ -103,27 +103,27 @@ private: class FrameGrabber : public QObject { Q_OBJECT - + public: - + FrameGrabber(); virtual ~FrameGrabber(); public slots: - + void cycleVideoSendMode(); void reset(); void shutdown(); void grabFrame(); - + private: - + enum VideoSendMode { NO_VIDEO, FACE_VIDEO, FULL_FRAME_VIDEO, VIDEO_SEND_MODE_COUNT }; - + bool init(); void updateHSVFrame(const cv::Mat& frame, int format); void destroyCodecs(); - + bool _initialized; VideoSendMode _videoSendMode; CvCapture* _capture; @@ -135,7 +135,7 @@ private: cv::Rect _searchWindow; cv::Mat _grayDepthFrame; float _smoothedMidFaceDepth; - + vpx_codec_ctx_t _colorCodec; vpx_codec_ctx_t _depthCodec; int _frameCount; @@ -144,7 +144,7 @@ private: cv::Mat _smoothedFaceDepth; QByteArray _encodedFace; cv::RotatedRect _smoothedFaceRect; - + #ifdef HAVE_OPENNI xn::Context _xnContext; xn::DepthGenerator _depthGenerator; @@ -158,10 +158,10 @@ private: class Joint { public: - + Joint(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& projected); Joint(); - + bool isValid; glm::vec3 position; glm::quat rotation; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b4fef89d94..346d5ff7d5 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -101,8 +101,8 @@ Avatar::Avatar(Node* owningNode) : _lastCollisionPosition(0, 0, 0), _speedBrakes(false), _isThrustOn(false), - _voxels(this), - _leadingAvatar(NULL) + _leadingAvatar(NULL), + _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData _headData = &_head; @@ -369,11 +369,24 @@ glm::vec3 Avatar::getUprightHeadPosition() const { } glm::vec3 Avatar::getUprightEyeLevelPosition() const { - const float EYE_UP_OFFSET = 0.36f; + const float EYE_UP_OFFSET = 0.36f; glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; return _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET + glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); } +glm::vec3 Avatar::getEyePosition() { + const float EYE_UP_OFFSET = 0.36f; + const float EYE_FRONT_OFFSET = 0.8f; + + glm::quat orientation = getWorldAlignedOrientation(); + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; + + float scale = _scale * BODY_BALL_RADIUS_HEAD_BASE; + + return getHead().getPosition() + up * scale * EYE_UP_OFFSET + front * scale * EYE_FRONT_OFFSET; +} + void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { // // Gather thrust information from keyboard and sensors to apply to avatar motion diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 80d5b463bf..e9df1c125d 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -171,6 +171,7 @@ public: glm::vec3 getUprightHeadPosition() const; glm::vec3 getUprightEyeLevelPosition() const; + glm::vec3 getEyePosition(); AvatarVoxelSystem* getVoxels() { return &_voxels; } diff --git a/interface/src/avatar/AvatarVoxelSystem.h b/interface/src/avatar/AvatarVoxelSystem.h index 51144e3954..3a7cb224a6 100644 --- a/interface/src/avatar/AvatarVoxelSystem.h +++ b/interface/src/avatar/AvatarVoxelSystem.h @@ -21,7 +21,7 @@ class QNetworkReply; class Avatar; -class AvatarVoxelSystem : public QObject, public VoxelSystem { +class AvatarVoxelSystem : public VoxelSystem { Q_OBJECT public: diff --git a/interface/src/avatar/Face.cpp b/interface/src/avatar/Face.cpp index 0541b3c21c..ffc88d4b5b 100644 --- a/interface/src/avatar/Face.cpp +++ b/interface/src/avatar/Face.cpp @@ -163,21 +163,21 @@ int Face::processVideoMessage(unsigned char* packetData, size_t dataBytes) { int ybr = ysrc[image->w + 1]; ysrc += 2; - tl[0] = ytl + redOffset; - tl[1] = ytl - greenOffset; - tl[2] = ytl + blueOffset; + tl[0] = saturate_cast(ytl + redOffset); + tl[1] = saturate_cast(ytl - greenOffset); + tl[2] = saturate_cast(ytl + blueOffset); - tr[0] = ytr + redOffset; - tr[1] = ytr - greenOffset; - tr[2] = ytr + blueOffset; + tr[0] = saturate_cast(ytr + redOffset); + tr[1] = saturate_cast(ytr - greenOffset); + tr[2] = saturate_cast(ytr + blueOffset); - bl[0] = ybl + redOffset; - bl[1] = ybl - greenOffset; - bl[2] = ybl + blueOffset; + bl[0] = saturate_cast(ybl + redOffset); + bl[1] = saturate_cast(ybl - greenOffset); + bl[2] = saturate_cast(ybl + blueOffset); - br[0] = ybr + redOffset; - br[1] = ybr - greenOffset; - br[2] = ybr + blueOffset; + br[0] = saturate_cast(ybr + redOffset); + br[1] = saturate_cast(ybr - greenOffset); + br[2] = saturate_cast(ybr + blueOffset); } yline += image->stride[0] * 2; vline += image->stride[1]; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b09cd1f701..b88802b7f1 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -59,7 +59,7 @@ Head::Head(Avatar* owningAvatar) : _rotation(0.0f, 0.0f, 0.0f), _leftEyePosition(0.0f, 0.0f, 0.0f), _rightEyePosition(0.0f, 0.0f, 0.0f), - _eyeLevelPosition(0.0f, 0.0f, 0.0f), + _eyePosition(0.0f, 0.0f, 0.0f), _leftEyeBrowPosition(0.0f, 0.0f, 0.0f), _rightEyeBrowPosition(0.0f, 0.0f, 0.0f), _leftEarPosition(0.0f, 0.0f, 0.0f), @@ -280,7 +280,7 @@ void Head::calculateGeometry() { + up * scale * EYE_UP_OFFSET + front * scale * EYE_FRONT_OFFSET; - _eyeLevelPosition = _rightEyePosition - right * scale * EYE_RIGHT_OFFSET; + _eyePosition = _rightEyePosition - right * scale * EYE_RIGHT_OFFSET; //calculate the eyebrow positions _leftEyeBrowPosition = _leftEyePosition; diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 259786fb6a..1256b05bb7 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -62,7 +62,7 @@ public: float getScale() const { return _scale; } glm::vec3 getPosition() const { return _position; } - const glm::vec3& getEyeLevelPosition() const { return _eyeLevelPosition; } + const glm::vec3& getEyePosition() const { return _eyePosition; } glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } @@ -96,7 +96,7 @@ private: glm::vec3 _rotation; glm::vec3 _leftEyePosition; glm::vec3 _rightEyePosition; - glm::vec3 _eyeLevelPosition; + glm::vec3 _eyePosition; glm::vec3 _leftEyeBrowPosition; glm::vec3 _rightEyeBrowPosition; glm::vec3 _leftEarPosition; diff --git a/interface/src/world.h b/interface/src/world.h index 9a1b506ae2..f53db4ff49 100644 --- a/interface/src/world.h +++ b/interface/src/world.h @@ -12,7 +12,6 @@ #define __interface__world__ -const float WORLD_SIZE = 10.0; #define PIf 3.14159265f const float GRAVITY_EARTH = 9.80665f; diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 65cbade423..79de62e747 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -61,6 +61,8 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) { Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); if (audioMixer) { _destinationSocket = *audioMixer->getActiveSocket(); + } else { + pthread_exit(0); } } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index a2ba56b8ef..b9a6d8a0ba 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -6,12 +6,12 @@ // Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // -#include #include +#include +#include -#include #include -#include +#include #include "AudioInjector.h" @@ -21,7 +21,8 @@ AudioInjector::AudioInjector(const char* filename) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false) + _isInjectingAudio(false), + _lastFrameIntensity(0.0f) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -51,7 +52,8 @@ AudioInjector::AudioInjector(int maxNumSamples) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false) + _isInjectingAudio(false), + _lastFrameIntensity(0.0f) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -114,6 +116,18 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); + // calculate the intensity for this frame + float lastRMS = 0; + + for (int j = 0; j < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; j++) { + lastRMS += _audioSampleArray[i + j] * _audioSampleArray[i + j]; + } + + lastRMS /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + lastRMS = sqrtf(lastRMS); + + _lastFrameIntensity = lastRMS / std::numeric_limits::max(); + int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * INJECT_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); @@ -131,8 +145,8 @@ void AudioInjector::addSample(const int16_t sample) { } } -void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { - if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + (_numTotalSamples / sizeof(int16_t))) { +void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { + if (_audioSampleArray + _indexOfNextSlot + numSamples <= _audioSampleArray + _numTotalSamples) { // only copy the audio from the sample buffer if there's space memcpy(_audioSampleArray + _indexOfNextSlot, sampleBuffer, numSamples * sizeof(int16_t)); _indexOfNextSlot += numSamples; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 875bc815ce..b102d58e19 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -9,8 +9,7 @@ #ifndef __hifi__AudioInjector__ #define __hifi__AudioInjector__ -#include -#include +#include #include #include @@ -36,6 +35,8 @@ public: unsigned char getVolume() const { return _volume; } void setVolume(unsigned char volume) { _volume = volume; } + float getLastFrameIntensity() const { return _lastFrameIntensity; } + const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3& position) { _position = position; } @@ -57,6 +58,7 @@ private: unsigned char _volume; int _indexOfNextSlot; bool _isInjectingAudio; + float _lastFrameIntensity; }; #endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/avatars/src/Agent.cpp b/libraries/avatars/src/Agent.cpp new file mode 100644 index 0000000000..f027bc1f55 --- /dev/null +++ b/libraries/avatars/src/Agent.cpp @@ -0,0 +1,88 @@ +// +// Agent.cpp +// hifi +// +// Created by Stephen Birarda on 7/1/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#import +#import + +#include + +#include "AvatarData.h" + +#include "Agent.h" + +Agent::Agent() : + _shouldStop(false) +{ + +} + +void Agent::run(QUrl scriptURL) { + NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT); + NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AVATAR_MIXER, 1); + + QNetworkAccessManager* manager = new QNetworkAccessManager(); + + qDebug() << "Attemping download of " << scriptURL; + + QNetworkReply* reply = manager->get(QNetworkRequest(scriptURL)); + + QEventLoop loop; + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + QString scriptString = QString(reply->readAll()); + + QScriptEngine engine; + + AvatarData *testAvatarData = new AvatarData; + + QScriptValue avatarDataValue = engine.newQObject(testAvatarData); + engine.globalObject().setProperty("AvatarData", avatarDataValue); + + QScriptValue agentValue = engine.newQObject(this); + engine.globalObject().setProperty("Agent", agentValue); + + qDebug() << "Downloaded script:" << scriptString; + + qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString(); + + timeval thisSend; + timeval lastDomainServerCheckIn = {}; + int numMicrosecondsSleep = 0; + + const float DATA_SEND_INTERVAL_USECS = (1 / 60) * 1000 * 1000; + + sockaddr_in senderAddress; + unsigned char receivedData[MAX_PACKET_SIZE]; + ssize_t receivedBytes; + + while (!_shouldStop) { + // update the thisSend timeval to the current time + gettimeofday(&thisSend, NULL); + + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + NodeList::getInstance()->sendDomainServerCheckIn(); + } + + emit preSendCallback(); + + testAvatarData->sendData(); + + if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) { + NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); + } + + // sleep for the correct amount of time to have data send be consistently timed + if ((numMicrosecondsSleep = DATA_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { + usleep(numMicrosecondsSleep); + } + } + +} \ No newline at end of file diff --git a/libraries/avatars/src/Agent.h b/libraries/avatars/src/Agent.h new file mode 100644 index 0000000000..e083abb541 --- /dev/null +++ b/libraries/avatars/src/Agent.h @@ -0,0 +1,32 @@ +// +// Agent.h +// hifi +// +// Created by Stephen Birarda on 7/1/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__Agent__ +#define __hifi__Agent__ + +#include +#include + +#include "SharedUtil.h" + +#include +#include + +class Agent : public QObject { + Q_OBJECT +public: + Agent(); + + bool volatile _shouldStop; + + void run(QUrl scriptUrl); +signals: + void preSendCallback(); +}; + +#endif /* defined(__hifi__Operative__) */ diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9c254453e1..75d88525bf 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -10,8 +10,9 @@ #include #include -#include +#include #include +#include #include "AvatarData.h" #include @@ -50,6 +51,22 @@ AvatarData::~AvatarData() { delete _handData; } +void AvatarData::sendData() { + + // called from Agent visual loop to send data + if (Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER)) { + unsigned char packet[MAX_PACKET_SIZE]; + + unsigned char* endOfPacket = packet; + endOfPacket += populateTypeAndVersion(endOfPacket, PACKET_TYPE_HEAD_DATA); + endOfPacket += packNodeId(endOfPacket, NodeList::getInstance()->getOwnerID()); + + int numPacketBytes = (endOfPacket - packet) + getBroadcastData(endOfPacket); + + NodeList::getInstance()->getNodeSocket()->send(avatarMixer->getActiveSocket(), packet, numPacketBytes); + } +} + int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { unsigned char* bufferStart = destinationBuffer; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 209d822426..2399d1062c 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include "HeadData.h" #include "HandData.h" @@ -39,6 +41,7 @@ enum KeyState class JointData; class AvatarData : public NodeData { + Q_OBJECT public: AvatarData(Node* owningNode = NULL); ~AvatarData(); @@ -53,7 +56,6 @@ public: // Body Rotation float getBodyYaw() const { return _bodyYaw; } - void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; } float getBodyPitch() const { return _bodyPitch; } void setBodyPitch(float bodyPitch) { _bodyPitch = bodyPitch; } float getBodyRoll() const {return _bodyRoll; } @@ -103,6 +105,11 @@ public: void setHeadData(HeadData* headData) { _headData = headData; } void setHandData(HandData* handData) { _handData = handData; } +public slots: + void setPosition(float x, float y, float z) { _position = glm::vec3(x, y, z); } + void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; } + void sendData(); + protected: glm::vec3 _position; glm::vec3 _handPosition; diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 1a7a99f2db..c32a04a0c4 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -13,7 +13,7 @@ #include #include -#include +#include class AvatarData; class FingerData; diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index cf1c603b7d..218adb4d5f 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -26,3 +26,6 @@ if (UNIX AND NOT APPLE) target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) endif (UNIX AND NOT APPLE) +# include GLM +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index d7cf429558..7aebb0c022 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -21,7 +21,7 @@ #include "SharedUtil.h" #include "UDPSocket.h" -#include +#include int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) { memcpy(nodeId, packedData, sizeof(uint16_t)); @@ -75,6 +75,7 @@ const char* NODE_TYPE_NAME_AUDIO_MIXER = "Audio Mixer"; const char* NODE_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer"; const char* NODE_TYPE_NAME_AUDIO_INJECTOR = "Audio Injector"; const char* NODE_TYPE_NAME_ANIMATION_SERVER = "Animation Server"; +const char* NODE_TYPE_NAME_UNASSIGNED = "Unassigned"; const char* NODE_TYPE_NAME_UNKNOWN = "Unknown"; const char* Node::getTypeName() const { diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index 46bf90ed43..df20664bda 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -18,7 +18,7 @@ #include #endif -#include +#include #include "NodeData.h" #include "SimpleMovingAverage.h" diff --git a/libraries/shared/src/NodeData.h b/libraries/shared/src/NodeData.h index c11b41ced9..8d3ddf51e0 100644 --- a/libraries/shared/src/NodeData.h +++ b/libraries/shared/src/NodeData.h @@ -9,9 +9,12 @@ #ifndef hifi_NodeData_h #define hifi_NodeData_h +#include + class Node; -class NodeData { +class NodeData : public QObject { + Q_OBJECT public: NodeData(Node* owningNode); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 3051f5ce68..2dfd537d93 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include "NodeList.h" #include "NodeTypes.h" @@ -366,6 +366,15 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte return readNodes; } +void NodeList::sendAssignmentRequest() { + const char ASSIGNMENT_SERVER_HOSTNAME[] = "assignment.highfidelity.io"; + + static sockaddr_in assignmentServerSocket = socketForHostname(ASSIGNMENT_SERVER_HOSTNAME); + assignmentServerSocket.sin_port = htons(ASSIGNMENT_SERVER_PORT); + + _nodeSocket.send((sockaddr*) &assignmentServerSocket, &PACKET_TYPE_REQUEST_ASSIGNMENT, 1); +} + Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) { NodeList::iterator node = end(); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 4c4795bdb0..260fddf96f 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -14,9 +14,10 @@ #include #include -#include +#include #include "Node.h" +#include "NodeTypes.h" #include "UDPSocket.h" #ifdef _WIN32 @@ -54,14 +55,16 @@ public: NodeListIterator begin() const; NodeListIterator end() const; + + NODE_TYPE getOwnerType() const { return _ownerType; } + void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; } + const char* getDomainHostname() const { return _domainHostname; }; void setDomainHostname(const char* domainHostname); void setDomainIP(const char* domainIP); void setDomainIPToLocalhost(); - - char getOwnerType() const { return _ownerType; } - + uint16_t getLastNodeID() const { return _lastNodeID; } void increaseNodeID() { ++_lastNodeID; } @@ -80,9 +83,12 @@ public: void clear(); void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); + void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); + void sendAssignmentRequest(); + Node* nodeWithAddress(sockaddr *senderAddress); Node* nodeWithID(uint16_t nodeID); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 8acc9a922f..0a198f9832 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include "SharedUtil.h" #include "OctalCode.h" diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 2e7b95c7f7..6d61056f85 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include "PacketHeaders.h" diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 2fbdc4d791..2b021db82c 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -34,6 +34,8 @@ const PACKET_TYPE PACKET_TYPE_TRANSMITTER_DATA_V2 = 'T'; const PACKET_TYPE PACKET_TYPE_ENVIRONMENT_DATA = 'e'; const PACKET_TYPE PACKET_TYPE_DOMAIN_LIST_REQUEST = 'L'; const PACKET_TYPE PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY = 'C'; +const PACKET_TYPE PACKET_TYPE_REQUEST_ASSIGNMENT = 'r'; +const PACKET_TYPE PACKET_TYPE_SEND_ASSIGNMENT = 's'; const PACKET_TYPE PACKET_TYPE_VOXEL_STATS = '#'; typedef char PACKET_VERSION; @@ -52,4 +54,6 @@ const int MAX_PACKET_HEADER_BYTES = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) #define ADD_SCENE_COMMAND "add scene" #define TEST_COMMAND "a message" +const int ASSIGNMENT_SERVER_PORT = 7007; + #endif diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index dde460dbb0..5199c09937 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include "PerfStat.h" diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index b6674fdb32..93ea8a70ed 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -20,7 +20,7 @@ #include #endif -#include +#include #include "OctalCode.h" #include "PacketHeaders.h" diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index d840a83ed9..49e8ae6f02 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -13,7 +13,7 @@ #include #include -#include +#include #ifdef _WIN32 #include "Systime.h" diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 0cd8efb723..c156ddd1be 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -20,7 +20,7 @@ #include #endif -#include +#include #include "UDPSocket.h" @@ -118,6 +118,17 @@ unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { } } +sockaddr_in socketForHostname(const char* hostname) { + struct hostent* pHostInfo; + sockaddr_in newSocket; + + if ((pHostInfo = gethostbyname(hostname))) { + memcpy(&newSocket.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); + } + + return newSocket; +} + UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking(true) { init(); // create the socket diff --git a/libraries/shared/src/UDPSocket.h b/libraries/shared/src/UDPSocket.h index 8539ff93c2..58bee3d2de 100644 --- a/libraries/shared/src/UDPSocket.h +++ b/libraries/shared/src/UDPSocket.h @@ -42,5 +42,6 @@ int packSocket(unsigned char* packStore, sockaddr* socketToPack); int unpackSocket(unsigned char* packedData, sockaddr* unpackDestSocket); int getLocalAddress(); unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket); +sockaddr_in socketForHostname(const char* hostname); #endif /* defined(__interface__UDPSocket__) */ diff --git a/libraries/voxels/src/JurisdictionMap.cpp b/libraries/voxels/src/JurisdictionMap.cpp index b67963d8d6..f67bbbabf7 100644 --- a/libraries/voxels/src/JurisdictionMap.cpp +++ b/libraries/voxels/src/JurisdictionMap.cpp @@ -44,12 +44,28 @@ JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(NULL) { readFromFile(filename); } - JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes) : _rootOctalCode(NULL) { init(rootOctalCode, endNodes); } +JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { + _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); + + QString endNodesHexStrings(endNodesHexCodes); + QString delimiterPattern(","); + QStringList endNodeList = endNodesHexStrings.split(delimiterPattern); + + for (int i = 0; i < endNodeList.size(); i++) { + QString endNodeHexString = endNodeList.at(i); + + unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString); + //printOctalCode(endNodeOctcode); + _endNodes.push_back(endNodeOctcode); + } +} + + void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector& endNodes) { clear(); // clean up our own memory _rootOctalCode = rootOctalCode; diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h index a52765549f..6c7cc4f0ca 100644 --- a/libraries/voxels/src/JurisdictionMap.h +++ b/libraries/voxels/src/JurisdictionMap.h @@ -23,6 +23,7 @@ public: JurisdictionMap(); JurisdictionMap(const char* filename); JurisdictionMap(unsigned char* rootOctalCode, const std::vector& endNodes); + JurisdictionMap(const char* rootHextString, const char* endNodesHextString); ~JurisdictionMap(); Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const; diff --git a/voxel-server/src/README b/voxel-server/src/README index 81824d96a9..76ed051679 100644 --- a/voxel-server/src/README +++ b/voxel-server/src/README @@ -15,6 +15,12 @@ OPTIONS --local This will run the voxel server in "local domain mode" and will look for a domain-server running on the same IP address as the voxel server + + --jurisdictionRoot [hex string of root octcode] + Tells the server to honor jurisdiction from the specified root node and below + + --jurisdictionEndNodes [(<,octcode>...)] + Tells the server to honor jurisdiction from the root down to the octcodes included in the comma separated list --jurisdictionFile [filename] Tells the server to load it's jurisdiction from the specified file. When a voxel server is running with a limited diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 329e8d803c..5d7489135a 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -456,11 +456,22 @@ int main(int argc, const char * argv[]) { printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); jurisdiction = new JurisdictionMap(jurisdictionFile); printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); + } else { + const char* JURISDICTION_ROOT = "--jurisdictionRoot"; + const char* jurisdictionRoot = getCmdOption(argc, argv, JURISDICTION_ROOT); + if (jurisdictionRoot) { + printf("jurisdictionRoot=%s\n", jurisdictionRoot); + } - // test writing the file... - printf("about to writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); - jurisdiction->writeToFile(jurisdictionFile); - printf("after writeToFile().... jurisdictionFile=%s\n", jurisdictionFile); + const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; + const char* jurisdictionEndNodes = getCmdOption(argc, argv, JURISDICTION_ENDNODES); + if (jurisdictionEndNodes) { + printf("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); + } + + if (jurisdictionRoot || jurisdictionEndNodes) { + jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); + } } NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, listenPort); From e2ba8e22d50bd6a56f03dc30d8ab993c25bff9ad Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 5 Aug 2013 11:35:02 -0700 Subject: [PATCH 3/4] added BendyLine --- interface/src/BendyLine.cpp | 119 ++++++++++++++++++++++++++++++++++++ interface/src/BendyLine.h | 52 ++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 interface/src/BendyLine.cpp create mode 100644 interface/src/BendyLine.h diff --git a/interface/src/BendyLine.cpp b/interface/src/BendyLine.cpp new file mode 100644 index 0000000000..ef5bd5f18d --- /dev/null +++ b/interface/src/BendyLine.cpp @@ -0,0 +1,119 @@ +// +// BendyLine.cpp +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include "BendyLine.h" +#include "Util.h" +#include "world.h" + +const float DEFAULT_BENDY_LINE_SPRING_FORCE = 10.0f; +const float DEFAULT_BENDY_LINE_TORQUE_FORCE = 0.1f; +const float DEFAULT_BENDY_LINE_DRAG = 10.0f; +const float DEFAULT_BENDY_LINE_LENGTH = 0.09f; +const float DEFAULT_BENDY_LINE_THICKNESS = 0.03f; + +BendyLine::BendyLine(){ + + _springForce = DEFAULT_BENDY_LINE_SPRING_FORCE; + _torqueForce = DEFAULT_BENDY_LINE_TORQUE_FORCE; + _drag = DEFAULT_BENDY_LINE_DRAG; + _length = DEFAULT_BENDY_LINE_LENGTH; + _thickness = DEFAULT_BENDY_LINE_THICKNESS; + + _gravityForce = glm::vec3(0.0f, 0.0f, 0.0f); + _basePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _baseDirection = glm::vec3(0.0f, 0.0f, 0.0f); + _midPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _endPosition = glm::vec3(0.0f, 0.0f, 0.0f); + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); +} + +void BendyLine::reset() { + + _midPosition = _basePosition + _baseDirection * _length * ONE_HALF; + _endPosition = _midPosition + _baseDirection * _length * ONE_HALF; + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); +} + +void BendyLine::update(float deltaTime) { + + glm::vec3 midAxis = _midPosition - _basePosition; + glm::vec3 endAxis = _endPosition - _midPosition; + + float midLength = glm::length(midAxis); + float endLength = glm::length(endAxis); + + glm::vec3 midDirection; + glm::vec3 endDirection; + + if (midLength > 0.0f) { + midDirection = midAxis / midLength; + } else { + midDirection = _baseDirection; + } + + if (endLength > 0.0f) { + endDirection = endAxis / endLength; + } else { + endDirection = _baseDirection; + } + + // add spring force + float midForce = midLength - _length * ONE_HALF; + float endForce = endLength - _length * ONE_HALF; + _midVelocity -= midDirection * midForce * _springForce * deltaTime; + _endVelocity -= endDirection * endForce * _springForce * deltaTime; + + // add gravity force + _midVelocity += _gravityForce; + _endVelocity += _gravityForce; + + // add torque force + _midVelocity += _baseDirection * _torqueForce * deltaTime; + _endVelocity += midDirection * _torqueForce * deltaTime; + + // add drag force + float momentum = 1.0f - (_drag * deltaTime); + if (momentum < 0.0f) { + _midVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + _endVelocity = glm::vec3(0.0f, 0.0f, 0.0f); + } else { + _midVelocity *= momentum; + _endVelocity *= momentum; + } + + // update position by velocity + _midPosition += _midVelocity; + _endPosition += _endVelocity; + + // clamp lengths + glm::vec3 newMidVector = _midPosition - _basePosition; + glm::vec3 newEndVector = _endPosition - _midPosition; + + float newMidLength = glm::length(newMidVector); + float newEndLength = glm::length(newEndVector); + + glm::vec3 newMidDirection; + glm::vec3 newEndDirection; + + if (newMidLength > 0.0f) { + newMidDirection = newMidVector/newMidLength; + } else { + newMidDirection = _baseDirection; + } + + if (newEndLength > 0.0f) { + newEndDirection = newEndVector/newEndLength; + } else { + newEndDirection = _baseDirection; + } + + _endPosition = _midPosition + newEndDirection * _length * ONE_HALF; + _midPosition = _basePosition + newMidDirection * _length * ONE_HALF; +} + + diff --git a/interface/src/BendyLine.h b/interface/src/BendyLine.h new file mode 100644 index 0000000000..47a86595ff --- /dev/null +++ b/interface/src/BendyLine.h @@ -0,0 +1,52 @@ +// +// BendyLine.h +// interface +// +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef hifi_bendyLine_h +#define hifi_bendyLine_h + +#include +#include +#include + +class BendyLine { +public: + BendyLine(); + + void update(float deltaTime); + void reset(); + + void setLength (float length ) { _length = length; } + void setThickness (float thickness ) { _thickness = thickness; } + void setSpringForce (float springForce ) { _springForce = springForce; } + void setTorqueForce (float torqueForce ) { _torqueForce = torqueForce; } + void setDrag (float drag ) { _drag = drag; } + void setBasePosition (glm::vec3 basePosition ) { _basePosition = basePosition; } + void setBaseDirection(glm::vec3 baseDirection) { _baseDirection = baseDirection;} + void setGravityForce (glm::vec3 gravityForce ) { _gravityForce = gravityForce; } + + glm::vec3 getBasePosition() { return _basePosition; } + glm::vec3 getMidPosition () { return _midPosition; } + glm::vec3 getEndPosition () { return _endPosition; } + float getThickness () { return _thickness; } + +private: + + float _springForce; + float _torqueForce; + float _drag; + float _length; + float _thickness; + glm::vec3 _gravityForce; + glm::vec3 _basePosition; + glm::vec3 _baseDirection; + glm::vec3 _midPosition; + glm::vec3 _endPosition; + glm::vec3 _midVelocity; + glm::vec3 _endVelocity; +}; + +#endif From 405cb516f6de21217266064380d1b5a6cacd039a Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 5 Aug 2013 12:05:15 -0700 Subject: [PATCH 4/4] removed 3 magic numbers in particle system --- interface/src/ParticleSystem.cpp | 6 +++--- interface/src/ParticleSystem.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index c3e24a3d9f..5aed606191 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -344,9 +344,9 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_RAINBOW_CYCLE) { float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude * ONE_HALF; - redModulation = sinf(radian * 0.5f) * amp; - greenModulation = sinf(radian * 0.7f) * amp; - bueModulation = sinf(radian * 1.0f) * amp; + redModulation = sinf(radian * RAINBOW_CYCLE_RED_RATE ) * amp; + greenModulation = sinf(radian * RAINBOW_CYCLE_GREEN_RATE) * amp; + bueModulation = sinf(radian * RAINBOW_CYCLE_BLUE_RATE ) * amp; } _particle[p].color.r += redModulation; diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 840c1e63cc..60bd0f91d4 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -15,6 +15,10 @@ const int NULL_PARTICLE = -1; const int MAX_EMITTERS = 100; const int MAX_PARTICLES = 5000; +const float RAINBOW_CYCLE_RED_RATE = 0.5f; +const float RAINBOW_CYCLE_GREEN_RATE = 0.7f; +const float RAINBOW_CYCLE_BLUE_RATE = 1.0f; + enum ParticleRenderStyle { PARTICLE_RENDER_STYLE_SPHERE = 0,