diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 133a72859e..d9cf479b17 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include #include @@ -22,9 +20,9 @@ Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), _shouldStop(false) { - } + void Agent::stop() { _shouldStop = true; } @@ -41,10 +39,27 @@ static size_t writeScriptDataToString(void *contents, size_t size, size_t nmemb, return realSize; } +QScriptValue vec3toScriptValue(QScriptEngine *engine, const glm::vec3 &vec3) { + QScriptValue obj = engine->newObject(); + obj.setProperty("x", vec3.x); + obj.setProperty("y", vec3.y); + obj.setProperty("z", vec3.z); + return obj; +} + +void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { + vec3.x = object.property("x").toVariant().toFloat(); + vec3.y = object.property("y").toVariant().toFloat(); + vec3.z = object.property("z").toVariant().toFloat(); +} + void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); - nodeList->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1); + + const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER }; + + nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); nodeList->getNodeSocket()->setBlocking(false); @@ -84,6 +99,9 @@ void Agent::run() { QScriptEngine engine; + // register meta-type for glm::vec3 conversions + qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue); + QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); @@ -93,14 +111,14 @@ void Agent::run() { QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); - - const long long VISUAL_DATA_SEND_INTERVAL_USECS = (1 / 60.0f) * 1000 * 1000; // let the VoxelPacketSender know how frequently we plan to call it - voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_SEND_INTERVAL_USECS); + voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS); - QScriptValue visualSendIntervalValue = engine.newVariant((QVariant(VISUAL_DATA_SEND_INTERVAL_USECS / 1000))); - engine.globalObject().setProperty("VISUAL_DATA_SEND_INTERVAL_MS", visualSendIntervalValue); + // hook in a constructor for audio injectorss + AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); + engine.globalObject().setProperty("AudioInjector", audioInjectorValue); qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); @@ -111,19 +129,20 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; } - timeval thisSend; + timeval startTime; + gettimeofday(&startTime, NULL); + timeval lastDomainServerCheckIn = {}; - int numMicrosecondsSleep = 0; sockaddr_in senderAddress; unsigned char receivedData[MAX_PACKET_SIZE]; ssize_t receivedBytes; - bool hasVoxelServer = false; + int thisFrame = 0; + + bool firstDomainCheckIn = false; while (!_shouldStop) { - // update the thisSend timeval to the current time - gettimeofday(&thisSend, NULL); // if we're not hearing from the domain-server we should stop running if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { @@ -136,38 +155,44 @@ void Agent::run() { NodeList::getInstance()->sendDomainServerCheckIn(); } - if (!hasVoxelServer) { - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getType() == NODE_TYPE_VOXEL_SERVER) { - hasVoxelServer = true; + if (firstDomainCheckIn) { + // find the audio-mixer in the NodeList so we can inject audio at it + Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + + emit willSendAudioDataCallback(); + + if (audioMixer) { + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); } + + scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getPublicSocket()); } - } - - if (hasVoxelServer) { + // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); - if (engine.hasUncaughtException()) { - int line = engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; - } - // release the queue of edit voxel messages. voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); - + // since we're in non-threaded mode, call process so that the packets are sent voxelScripter.getVoxelPacketSender()->process(); + } + if (engine.hasUncaughtException()) { + int line = engine.uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; + } + while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) { + if (!firstDomainCheckIn && receivedData[0] == PACKET_TYPE_DOMAIN) { + firstDomainCheckIn = true; + } + NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); } - - // sleep for the correct amount of time to have data send be consistently timed - if ((numMicrosecondsSleep = VISUAL_DATA_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { - usleep(numMicrosecondsSleep); - } } } else { diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 0490238d3f..ba70fd58ec 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -9,9 +9,13 @@ #ifndef __hifi__Agent__ #define __hifi__Agent__ +#include + +#include #include #include +#include #include class Agent : public Assignment { @@ -23,9 +27,13 @@ public: public slots: void stop(); signals: + void willSendAudioDataCallback(); void willSendVisualDataCallback(); private: + static QScriptValue AudioInjectorConstructor(QScriptContext *context, QScriptEngine *engine); + bool volatile _shouldStop; + std::vector _audioInjectors; }; #endif /* defined(__hifi__Operative__) */ diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 9d50469c6d..03578c4e8a 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -66,12 +66,13 @@ void childClient() { // create a request assignment, accept assignments defined by the overidden type Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType); - // if we're here we have no assignment, so send a request qDebug() << "Waiting for assignment -" << requestAssignment << "\n"; while (true) { if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { gettimeofday(&lastRequest, NULL); + + // if we're here we have no assignment, so send a request nodeList->sendAssignment(requestAssignment); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bdd1f8379f..9afb269f1b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -105,6 +105,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _profile(QString()), _mouseX(0), _mouseY(0), + _lastMouseMove(usecTimestampNow()), + _mouseHidden(false), _touchAvgX(0.0f), _touchAvgY(0.0f), _isTouchPressed(false), @@ -154,6 +156,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : NodeList::getInstance()->addHook(&_voxels); NodeList::getInstance()->addHook(this); NodeList::getInstance()->addDomainListener(this); + NodeList::getInstance()->addDomainListener(&_voxels); // network receive thread and voxel parsing thread are both controlled by the --nonblocking command line @@ -908,6 +911,9 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_8: _swatch.handleEvent(event->key(), Menu::getInstance()->isOptionChecked(MenuOption::VoxelGetColorMode)); break; + case Qt::Key_At: + Menu::getInstance()->goToUser(); + break; default: event->ignore(); break; @@ -978,6 +984,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { } void Application::mouseMoveEvent(QMouseEvent* event) { + _lastMouseMove = usecTimestampNow(); + if (_mouseHidden) { + getGLWidget()->setCursor(Qt::ArrowCursor); + _mouseHidden = false; + } + if (activeWindow() == _window) { _mouseX = event->x(); _mouseY = event->y(); @@ -2119,6 +2131,15 @@ void Application::update(float deltaTime) { _audio.setLastVelocity(_myAvatar.getVelocity()); _audio.eventuallyAnalyzePing(); #endif + + // watch mouse position, if it hasn't moved, hide the cursor + uint64_t now = usecTimestampNow(); + int elapsed = now - _lastMouseMove; + const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second + if (elapsed > HIDE_CURSOR_TIMEOUT) { + getGLWidget()->setCursor(Qt::BlankCursor); + _mouseHidden = true; + } } void Application::updateAvatar(float deltaTime) { @@ -3563,9 +3584,6 @@ void Application::domainChanged(QString domain) { // update the user's last domain in their Profile (which will propagate to data-server) _profile.updateDomain(domain); - // kill the local voxels - _voxels.killLocalVoxels(); - // reset the environment so that we don't erroneously end up with multiple _environment.resetToDefault(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index c030b61a74..cb3a3ca73d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -305,6 +305,8 @@ private: int _mouseY; int _mouseDragStartedX; int _mouseDragStartedY; + uint64_t _lastMouseMove; + bool _mouseHidden; float _touchAvgX; float _touchAvgY; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3dda04d8df..f9479865c6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -101,7 +101,7 @@ Menu::Menu() : SLOT(goToLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToUser, - Qt::CTRL | Qt::SHIFT | Qt::Key_U, + Qt::Key_At, this, SLOT(goToUser())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 688d0d3c34..81d213c026 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -66,6 +66,7 @@ public slots: void saveSettings(QSettings* settings = NULL); void importSettings(); void exportSettings(); + void goToUser(); private slots: void aboutApp(); @@ -73,7 +74,6 @@ private slots: void editPreferences(); void goToDomain(); void goToLocation(); - void goToUser(); void bandwidthDetailsClosed(); void voxelStatsDetailsClosed(); void cycleFrustumRenderMode(); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9ea37be662..574615d113 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -109,8 +109,14 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) } void VoxelSystem::voxelDeleted(VoxelNode* node) { - if (node->isKnownBufferIndex() && (node->getVoxelSystem() == this)) { - forceRemoveNodeFromArrays(node); + if (node->getVoxelSystem() == this) { + if (_voxelsInWriteArrays != 0) { + forceRemoveNodeFromArrays(node); + } else { + if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { + printf("VoxelSystem::voxelDeleted() while _voxelsInWriteArrays==0, is that expected? \n"); + } + } } } @@ -223,10 +229,15 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". void VoxelSystem::clearFreeBufferIndexes() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()"); + _voxelsInWriteArrays = 0; // reset our VBO + _abandonedVBOSlots = 0; + + // clear out freeIndexes pthread_mutex_lock(&_freeIndexLock); _freeIndexes.clear(); - _abandonedVBOSlots = 0; pthread_mutex_unlock(&_freeIndexLock); + + clearAllNodesBufferIndex(); } VoxelSystem::~VoxelSystem() { @@ -438,7 +449,6 @@ void VoxelSystem::initVoxelMemory() { // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead // rendering the voxel faces in 6 passes that use a global call to glNormal3f() - qDebug("Using Global Normals...\n"); setupFaceIndices(_vboIndicesTop, identityIndicesTop); setupFaceIndices(_vboIndicesBottom, identityIndicesBottom); setupFaceIndices(_vboIndicesLeft, identityIndicesLeft); @@ -596,11 +606,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { while (totalLength <= numBytes) { if (0==strcmp(command,(char*)"erase all")) { - qDebug("got Z message == erase all\n"); - pthread_mutex_lock(&_treeLock); - _tree->eraseAllVoxels(); - pthread_mutex_unlock(&_treeLock); - _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? + qDebug("got Z message == erase all - NOT SUPPORTED ON INTERFACE\n"); } if (0==strcmp(command,(char*)"add scene")) { qDebug("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); @@ -652,8 +658,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); _callsToTreesToArrays++; if (_writeRenderFullVBO) { - printf("resetting _freeIndexes and _voxelsInWriteArrays\n"); - _voxelsInWriteArrays = 0; // reset our VBO clearFreeBufferIndexes(); } _voxelsUpdated = newTreeToArrays(_tree->rootNode); @@ -972,10 +976,10 @@ int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool force updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); return 1; // updated! } else { - // If we shouldn't render, but we did have a known index, then we will need to release our index - if (reuseIndex && node->isKnownBufferIndex()) { - forceRemoveNodeFromArrays(node); - return 1; // updated! + // If we shouldn't render, and we're in reuseIndex mode, then free our index, this only operates + // on nodes with known index values, so it's safe to call for any node. + if (reuseIndex) { + return forceRemoveNodeFromArrays(node); } } } @@ -1284,8 +1288,11 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { + pthread_mutex_lock(&_treeLock); _tree->eraseAllVoxels(); - _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this?? + pthread_mutex_unlock(&_treeLock); + clearFreeBufferIndexes(); + _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); } @@ -1298,8 +1305,12 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extra void VoxelSystem::clearAllNodesBufferIndex() { _nodeCount = 0; + pthread_mutex_lock(&_treeLock); _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); - qDebug("clearing buffer index of %d nodes\n", _nodeCount); + pthread_mutex_unlock(&_treeLock); + if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { + qDebug("clearing buffer index of %d nodes\n", _nodeCount); + } } bool VoxelSystem::forceRedrawEntireTreeOperation(VoxelNode* node, void* extraData) { @@ -1700,8 +1711,7 @@ bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) { if (node->isKnownBufferIndex()) { args->nodesRemoved++; VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; - thisVoxelSystem->forceRemoveNodeFromArrays(node); - thisVoxelSystem->_voxelsUpdated++; + thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node); thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); } @@ -1714,10 +1724,10 @@ bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) { args->nodesInside++; if (node->getShouldRender() && !node->isKnownBufferIndex()) { - node->setDirtyBit(); // will this make it draw? + node->setDirtyBit(); // will this make it draw! } - return true; + return true; // keep recursing! } @@ -1841,7 +1851,7 @@ void VoxelSystem::falseColorizeRandomEveryOther() { class collectStatsForTreesAndVBOsArgs { public: - collectStatsForTreesAndVBOsArgs() : + collectStatsForTreesAndVBOsArgs(int maxVoxels) : totalNodes(0), dirtyNodes(0), shouldRenderNodes(0), @@ -1852,8 +1862,13 @@ public: duplicateVBOIndex(0), leafNodes(0) { - memset(hasIndexFound, false, DEFAULT_MAX_VOXELS_PER_SYSTEM * sizeof(bool)); + hasIndexFound = new bool[maxVoxels]; + memset(hasIndexFound, false, maxVoxels * sizeof(bool)); }; + + ~collectStatsForTreesAndVBOsArgs() { + delete[] hasIndexFound; + } unsigned long totalNodes; unsigned long dirtyNodes; @@ -1867,7 +1882,7 @@ public: unsigned long expectedMax; - bool hasIndexFound[DEFAULT_MAX_VOXELS_PER_SYSTEM]; + bool* hasIndexFound; }; bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) { @@ -1934,7 +1949,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { } } - collectStatsForTreesAndVBOsArgs args; + collectStatsForTreesAndVBOsArgs args(_maxVoxels); args.expectedMax = _voxelsInWriteArrays; qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>\n"); @@ -1953,7 +1968,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; glBufferIndex maxInVBO = 0; - for (glBufferIndex i = 0; i < DEFAULT_MAX_VOXELS_PER_SYSTEM; i++) { + for (glBufferIndex i = 0; i < _maxVoxels; i++) { if (args.hasIndexFound[i]) { minInVBO = std::min(minInVBO,i); maxInVBO = std::max(maxInVBO,i); @@ -1972,13 +1987,12 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { pthread_mutex_lock(&_treeLock); - _tree->deleteVoxelAt(x, y, z, s); + pthread_mutex_unlock(&_treeLock); // redraw! setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? - pthread_mutex_unlock(&_treeLock); }; VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { @@ -2313,17 +2327,22 @@ void VoxelSystem::nodeKilled(Node* node) { if (_voxelServerCount > 0) { // Kill any voxels from the local tree that match this nodeID + pthread_mutex_lock(&_treeLock); _tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeID); + pthread_mutex_unlock(&_treeLock); _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); } else { // Last server, take the easy way and kill all the local voxels! - _tree->eraseAllVoxels(); - _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this?? + killLocalVoxels(); } - setupNewVoxelsForDrawing(); } } +void VoxelSystem::domainChanged(QString domain) { + killLocalVoxels(); +} + unsigned long VoxelSystem::getFreeMemoryGPU() { // We can't ask all GPUs how much memory they have in use, but we can ask them about how much is free. diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 5f026e043c..1af6b19ca7 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -37,7 +37,8 @@ struct VoxelShaderVBOData }; -class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public VoxelNodeUpdateHook, public NodeListHook { +class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public VoxelNodeUpdateHook, + public NodeListHook, public DomainChangeListener { Q_OBJECT public: VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM); @@ -112,6 +113,7 @@ public: virtual void voxelUpdated(VoxelNode* node); virtual void nodeAdded(Node* node); virtual void nodeKilled(Node* node); + virtual void domainChanged(QString domain); signals: void importSize(float x, float y, float z); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ee4f0c4811..181c320b69 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -221,12 +221,14 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { // Damp avatar velocity const float LINEAR_DAMPING_STRENGTH = 0.5f; const float SPEED_BRAKE_POWER = _scale * 10.0f; - const float SQUARED_DAMPING_STRENGTH = 0.007f; + const float SQUARED_DAMPING_STRENGTH = 0.007f; + const float SLOW_NEAR_RADIUS = 5.f; float linearDamping = LINEAR_DAMPING_STRENGTH; - const float AVATAR_DAMPING_FACTOR = 120.f; - if (_distanceToNearestAvatar < _scale * PERIPERSONAL_RADIUS) { - linearDamping *= 1.f + AVATAR_DAMPING_FACTOR * (PERIPERSONAL_RADIUS - _distanceToNearestAvatar); + const float NEAR_AVATAR_DAMPING_FACTOR = 50.f; + if (_distanceToNearestAvatar < _scale * SLOW_NEAR_RADIUS) { + linearDamping *= 1.f + NEAR_AVATAR_DAMPING_FACTOR * + ((SLOW_NEAR_RADIUS - _distanceToNearestAvatar) / SLOW_NEAR_RADIUS); } if (_speedBrakes) { applyDamping(deltaTime, _velocity, linearDamping * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index b9a6d8a0ba..acdee03e8f 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -21,8 +21,7 @@ AudioInjector::AudioInjector(const char* filename) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false), - _lastFrameIntensity(0.0f) + _isInjectingAudio(false) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -52,8 +51,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _radius(0.0f), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), - _isInjectingAudio(false), - _lastFrameIntensity(0.0f) + _isInjectingAudio(false) { loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES); @@ -103,6 +101,11 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination int nextFrame = 0; for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { + int usecToSleep = usecTimestamp(&startTime) + (nextFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES_PER_CHANNEL; if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { @@ -115,23 +118,6 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); 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); - } } _isInjectingAudio = false; @@ -152,3 +138,15 @@ void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { _indexOfNextSlot += numSamples; } } + +int16_t& AudioInjector::sampleAt(const int index) { + assert(index >= 0 && index < _numTotalSamples); + + return _audioSampleArray[index]; +} + +void AudioInjector::insertSample(const int index, int sample) { + assert (index >= 0 && index < _numTotalSamples); + + _audioSampleArray[index] = (int16_t) sample; +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index b102d58e19..626cdc3149 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -12,6 +12,9 @@ #include #include +#include + +#include #include #include "AudioRingBuffer.h" @@ -22,7 +25,11 @@ const int MAX_INJECTOR_VOLUME = 0xFF; const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000); -class AudioInjector { +class AudioInjector : public QObject { + Q_OBJECT + + Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(uchar volume READ getVolume WRITE setVolume); public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); @@ -35,8 +42,6 @@ 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; } @@ -48,6 +53,9 @@ public: void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); +public slots: + int16_t& sampleAt(const int index); + void insertSample(const int index, int sample); private: unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES]; int16_t* _audioSampleArray; @@ -58,7 +66,6 @@ private: unsigned char _volume; int _indexOfNextSlot; bool _isInjectingAudio; - float _lastFrameIntensity; }; #endif /* defined(__hifi__AudioInjector__) */ diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f0085a4138..46aad2d86f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -53,38 +53,6 @@ AvatarData::~AvatarData() { delete _handData; } -void AvatarData::setPositionFromVariantMap(QVariantMap positionMap) { - _position = glm::vec3(positionMap.value("x").toFloat(), - positionMap.value("y").toFloat(), - positionMap.value("z").toFloat()); -} - -QVariantMap AvatarData::getPositionVariantMap() { - QVariantMap positionMap; - - positionMap.insert("x", _position.x); - positionMap.insert("y", _position.y); - positionMap.insert("z", _position.z); - - return positionMap; -} - -void AvatarData::setHandPositionFromVariantMap(QVariantMap handPositionMap) { - _handPosition = glm::vec3(handPositionMap.value("x").toFloat(), - handPositionMap.value("y").toFloat(), - handPositionMap.value("z").toFloat()); -} - -QVariantMap AvatarData::getHandPositionVariantMap() { - QVariantMap positionMap; - - positionMap.insert("x", _handPosition.x); - positionMap.insert("y", _handPosition.y); - positionMap.insert("z", _handPosition.z); - - return positionMap; -} - void AvatarData::sendData() { // called from Agent visual loop to send data diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 57327f3bba..f3ccab1504 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -20,6 +20,8 @@ #include #include +#include + #include #include "HeadData.h" #include "HandData.h" @@ -49,8 +51,8 @@ class JointData; class AvatarData : public NodeData { Q_OBJECT - Q_PROPERTY(QVariantMap position READ getPositionVariantMap WRITE setPositionFromVariantMap) - Q_PROPERTY(QVariantMap handPosition READ getHandPositionVariantMap WRITE setHandPositionFromVariantMap) + Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll) @@ -60,16 +62,11 @@ public: ~AvatarData(); const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3 position) { _position = position; } + + const glm::vec3& getHandPosition() const { return _handPosition; } void setHandPosition(const glm::vec3 handPosition) { _handPosition = handPosition; } - void setPositionFromVariantMap(QVariantMap positionMap); - QVariantMap getPositionVariantMap(); - - void setHandPositionFromVariantMap(QVariantMap handPositionMap); - QVariantMap getHandPositionVariantMap(); - int getBroadcastData(unsigned char* destinationBuffer); int parseData(unsigned char* sourceBuffer, int numBytes); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 11ae372830..12a24c535f 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -437,7 +437,6 @@ void NodeList::sendAssignment(Assignment& assignment) { } Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) { - NodeList::iterator node = end(); if (publicSocket) { @@ -553,7 +552,7 @@ void* removeSilentNodes(void *args) { node->lock(); if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { - + qDebug() << "Killed " << *node << "\n"; nodeList->notifyHooksOfKilledNode(&*node); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h new file mode 100644 index 0000000000..e15e053ebb --- /dev/null +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -0,0 +1,16 @@ +// +// RegisteredMetaTypes.h +// hifi +// +// Created by Stephen Birarda on 10/3/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// Used to register meta-types with Qt so that they can be used as properties for objects exposed to our +// Agent scripting. + +#ifndef hifi_RegisteredMetaTypes_h +#define hifi_RegisteredMetaTypes_h + +Q_DECLARE_METATYPE(glm::vec3) + +#endif