diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 37d4a7993d..ad4787b407 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -237,14 +237,6 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf _clientSamples[delayedChannelIndex + SINGLE_STEREO_OFFSET] += delayBufferSample[1]; } - // The following code is pretty gross and redundant, but AFAIK it's the best way to avoid - // too many conditionals in handling the delay samples at the beginning of _clientSamples. - // Basically we try to take the samples in batches of four, and then handle the remainder - // conditionally to get rid of the rest. - - const int DOUBLE_STEREO_OFFSET = 4; - const int TRIPLE_STEREO_OFFSET = 6; - if (numSamplesDelay > 0) { // if there was a sample delay for this buffer, we need to pull samples prior to the nextOutput // to stick at the beginning diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b42a690d97..a4983e6a95 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -90,12 +90,12 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { switch (packetArrivalInfo._status) { case SequenceNumberStats::Early: { int packetsLost = packetArrivalInfo._seqDiffFromExpected; - avatarRingBuffer->parseData(packet, packetsLost); + avatarRingBuffer->parseDataAndHandleDroppedPackets(packet, packetsLost); break; } case SequenceNumberStats::OnTime: { // ask the AvatarAudioRingBuffer instance to parse the data - avatarRingBuffer->parseData(packet); + avatarRingBuffer->parseDataAndHandleDroppedPackets(packet, 0); break; } default: { @@ -134,12 +134,12 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { switch (packetArrivalInfo._status) { case SequenceNumberStats::Early: { int packetsLost = packetArrivalInfo._seqDiffFromExpected; - matchingInjectedRingBuffer->parseData(packet, packetsLost); + matchingInjectedRingBuffer->parseDataAndHandleDroppedPackets(packet, packetsLost); break; } case SequenceNumberStats::OnTime: { // ask the AvatarAudioRingBuffer instance to parse the data - matchingInjectedRingBuffer->parseData(packet); + matchingInjectedRingBuffer->parseDataAndHandleDroppedPackets(packet, 0); break; } default: { diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index f6edde7ac4..382e8de68b 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -18,7 +18,7 @@ AvatarAudioRingBuffer::AvatarAudioRingBuffer(bool isStereo, bool dynamicJitterBu } -int AvatarAudioRingBuffer::parseData(const QByteArray& packet, int packetsSkipped) { +int AvatarAudioRingBuffer::parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) { frameReceivedUpdateTimingStats(); _shouldLoopbackForNode = (packetTypeForPacket(packet) == PacketTypeMicrophoneAudioWithEcho); diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index df9dc3787a..96233220cd 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -20,7 +20,7 @@ class AvatarAudioRingBuffer : public PositionalAudioRingBuffer { public: AvatarAudioRingBuffer(bool isStereo = false, bool dynamicJitterBuffer = false); - int parseData(const QByteArray& packet, int packetsSkipped = 0); + int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped); private: // disallow copying of AvatarAudioRingBuffer objects AvatarAudioRingBuffer(const AvatarAudioRingBuffer&); diff --git a/examples/editModels.js b/examples/editModels.js index 458ddf7b4a..ea88c87bea 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1168,7 +1168,6 @@ function handeMenuEvent(menuItem){ angles.z = array[7].value; selectedModelProperties.modelRotation = Quat.fromVec3Degrees(angles); selectedModelProperties.radius = array[8].value / 2; - print(selectedModelProperties.radius); Models.editModel(selectedModelID, selectedModelProperties); } diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 8d2a516f55..306156cc18 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -51,7 +51,6 @@ var lastVoxelScale = 0; var dragStart = { x: 0, y: 0 }; var wheelPixelsMoved = 0; - var mouseX = 0; var mouseY = 0; @@ -168,7 +167,16 @@ var voxelPreview = Overlays.addOverlay("cube", { lineWidth: 4 }); -var linePreviewTop = Overlays.addOverlay("line3d", { +var linePreviewTop = []; +var linePreviewBottom = []; +var linePreviewLeft = []; +var linePreviewRight = []; + +// Currend cursor index +var currentCursor = 0; + +function addLineOverlay() { + return Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z: 0}, end: { x: 0, y: 0, z: 0}, color: { red: 255, green: 255, blue: 255}, @@ -176,34 +184,24 @@ var linePreviewTop = Overlays.addOverlay("line3d", { visible: false, lineWidth: previewLineWidth }); +} + +//Cursor line previews for up to three cursors +linePreviewTop[0] = addLineOverlay(); +linePreviewTop[1] = addLineOverlay(); +linePreviewTop[2] = addLineOverlay(); -var linePreviewBottom = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0}, - end: { x: 0, y: 0, z: 0}, - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false, - lineWidth: previewLineWidth - }); - -var linePreviewLeft = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0}, - end: { x: 0, y: 0, z: 0}, - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false, - lineWidth: previewLineWidth - }); - -var linePreviewRight = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z: 0}, - end: { x: 0, y: 0, z: 0}, - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false, - lineWidth: previewLineWidth - }); - +linePreviewBottom[0] = addLineOverlay(); +linePreviewBottom[1] = addLineOverlay(); +linePreviewBottom[2] = addLineOverlay(); + +linePreviewLeft[0] = addLineOverlay(); +linePreviewLeft[1] = addLineOverlay(); +linePreviewLeft[2] = addLineOverlay(); + +linePreviewRight[0] = addLineOverlay(); +linePreviewRight[1] = addLineOverlay(); +linePreviewRight[2] = addLineOverlay(); // these will be used below var scaleSelectorWidth = 144; @@ -809,21 +807,21 @@ function showPreviewLines() { var pasteVoxel = getNewPasteVoxel(pickRay); // X axis - Overlays.editOverlay(linePreviewBottom, { + Overlays.editOverlay(linePreviewBottom[currentCursor], { position: pasteVoxel.origin, end: {x: pasteVoxel.origin.x + pasteVoxel.voxelSize, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z }, visible: true }); // Y axis - Overlays.editOverlay(linePreviewRight, { + Overlays.editOverlay(linePreviewRight[currentCursor], { position: pasteVoxel.origin, end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y + pasteVoxel.voxelSize, z: pasteVoxel.origin.z }, visible: true }); // Z axis - Overlays.editOverlay(linePreviewTop, { + Overlays.editOverlay(linePreviewTop[currentCursor], { position: pasteVoxel.origin, end: {x: pasteVoxel.origin.x, y: pasteVoxel.origin.y, z: pasteVoxel.origin.z - pasteVoxel.voxelSize }, visible: true @@ -837,10 +835,10 @@ function showPreviewLines() { if (intersection.intersects) { resultVoxel = calculateVoxelFromIntersection(intersection,""); Overlays.editOverlay(voxelPreview, { visible: false }); - Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true }); - Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true }); - Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true }); - Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true }); + Overlays.editOverlay(linePreviewTop[currentCursor], { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true }); + Overlays.editOverlay(linePreviewBottom[currentCursor], { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true }); + Overlays.editOverlay(linePreviewLeft[currentCursor], { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true }); + Overlays.editOverlay(linePreviewRight[currentCursor], { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true }); colors[0] = {red: intersection.voxel.red, green: intersection.voxel.green , blue: intersection.voxel.blue }; if (copyScale) { @@ -849,10 +847,10 @@ function showPreviewLines() { moveTools(); } else { Overlays.editOverlay(voxelPreview, { visible: false }); - Overlays.editOverlay(linePreviewTop, { visible: false }); - Overlays.editOverlay(linePreviewBottom, { visible: false }); - Overlays.editOverlay(linePreviewLeft, { visible: false }); - Overlays.editOverlay(linePreviewRight, { visible: false }); + Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false }); } } @@ -862,20 +860,20 @@ function showPreviewGuides() { showPreviewVoxel(); // make sure alternative is hidden - Overlays.editOverlay(linePreviewTop, { visible: false }); - Overlays.editOverlay(linePreviewBottom, { visible: false }); - Overlays.editOverlay(linePreviewLeft, { visible: false }); - Overlays.editOverlay(linePreviewRight, { visible: false }); + Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false }); } else { showPreviewLines(); } } else { // make sure all previews are off Overlays.editOverlay(voxelPreview, { visible: false }); - Overlays.editOverlay(linePreviewTop, { visible: false }); - Overlays.editOverlay(linePreviewBottom, { visible: false }); - Overlays.editOverlay(linePreviewLeft, { visible: false }); - Overlays.editOverlay(linePreviewRight, { visible: false }); + Overlays.editOverlay(linePreviewTop[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewBottom[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewLeft[currentCursor], { visible: false }); + Overlays.editOverlay(linePreviewRight[currentCursor], { visible: false }); } } @@ -968,6 +966,14 @@ function mousePressEvent(event) { return; } + if (event.deviceID == 1500) { // Left Hydra Controller + currentCursor = 0; + } else if (event.deviceID == 1501) { // Right Hydra Controller + currentCursor = 1; + } else { + currentCursor = 2; + } + var clickedOnSomething = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); @@ -1220,6 +1226,7 @@ function menuItemEvent(menuItem) { } function mouseMoveEvent(event) { + if (!editToolsOn) { return; } @@ -1227,6 +1234,14 @@ function mouseMoveEvent(event) { return; } + if (event.deviceID == 1500) { // Left Hydra Controller + currentCursor = 0; + } else if (event.deviceID == 1501) { // Right Hydra Controller + currentCursor = 1; + } else { + currentCursor = 2; + } + // Move Import Preview if (isImporting) { var pickRay = Camera.computePickRay(event.x, event.y); @@ -1475,10 +1490,12 @@ Controller.captureKeyEvents({ text: "-" }); function scriptEnding() { Overlays.deleteOverlay(voxelPreview); - Overlays.deleteOverlay(linePreviewTop); - Overlays.deleteOverlay(linePreviewBottom); - Overlays.deleteOverlay(linePreviewLeft); - Overlays.deleteOverlay(linePreviewRight); + for (var i = 0; i < linePreviewTop.length; i++) { + Overlays.deleteOverlay(linePreviewTop[i]); + Overlays.deleteOverlay(linePreviewBottom[i]); + Overlays.deleteOverlay(linePreviewLeft[i]); + Overlays.deleteOverlay(linePreviewRight[i]); + } for (s = 0; s < numColors; s++) { Overlays.deleteOverlay(swatches[s]); } diff --git a/examples/laserPointer.js b/examples/laserPointer.js new file mode 100644 index 0000000000..bedafe6a18 --- /dev/null +++ b/examples/laserPointer.js @@ -0,0 +1,23 @@ +// +// laserPointer.js +// examples +// +// Created by Clément Brisset on 7/18/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var LEFT = 0; +var RIGHT = 1; +var LEFT_HAND_FLAG = 1; +var RIGHT_HAND_FLAG = 2; + +function update() { + var state = ((Controller.getTriggerValue(LEFT) > 0.9) ? LEFT_HAND_FLAG : 0) + + ((Controller.getTriggerValue(RIGHT) > 0.9) ? RIGHT_HAND_FLAG : 0); + MyAvatar.setHandState(state); +} + +Script.update.connect(update); \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6aa6fcd19e..89642f8d18 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -592,7 +592,7 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay - _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); + _myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition()); _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { @@ -611,10 +611,10 @@ void Application::paintGL() { if (OculusManager::isConnected()) { _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); + _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); } else { _myCamera.setTightness(0.0f); - glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); + glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition(); float headHeight = eyePosition.y - _myAvatar->getPosition().y; _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); @@ -1911,17 +1911,9 @@ void Application::updateMyAvatarLookAtPosition() { } } else { // I am not looking at anyone else, so just look forward - lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() + + lookAtSpot = _myAvatar->getHead()->getEyePosition() + (_myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.f, 0.f, -TREE_SCALE)); } - // TODO: Add saccade to mouse pointer when stable, IF not looking at someone (since we know we are looking at it) - /* - const float FIXED_MIN_EYE_DISTANCE = 0.3f; - float minEyeDistance = FIXED_MIN_EYE_DISTANCE + (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON ? 0.0f : - glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition())); - lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance); - */ - } // // Deflect the eyes a bit to match the detected Gaze from 3D camera if active @@ -1931,7 +1923,7 @@ void Application::updateMyAvatarLookAtPosition() { float eyeYaw = tracker->getEstimatedEyeYaw(); const float GAZE_DEFLECTION_REDUCTION_DURING_EYE_CONTACT = 0.1f; // deflect using Faceshift gaze data - glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition(); + glm::vec3 origin = _myAvatar->getHead()->getEyePosition(); float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f; float deflection = Menu::getInstance()->getFaceshiftEyeDeflection(); if (isLookingAtSomeone) { @@ -2935,7 +2927,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { _mirrorCamera.setTargetPosition(glm::vec3()); } else { - _mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); + _mirrorCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); } } _mirrorCamera.setAspectRatio((float)region.width() / region.height()); @@ -2964,7 +2956,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { _myAvatar->getSkeletonModel().getNeckPosition(neckPosition); // get the eye position relative to the body - glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); + glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition(); float eyeHeight = eyePosition.y - _myAvatar->getPosition().y; // set the translation of the face relative to the neck position @@ -3355,7 +3347,7 @@ void Application::nodeKilled(SharedNodePointer node) { _modelEditSender.nodeKilled(node); if (node->getType() == NodeType::AudioMixer) { - QMetaObject::invokeMethod(&_audio, "resetIncomingMixedAudioSequenceNumberStats"); + QMetaObject::invokeMethod(&_audio, "audioMixerKilled"); } if (node->getType() == NodeType::VoxelServer) { @@ -3641,7 +3633,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript scriptEngine->getModelsScriptingInterface()->setModelTree(_models.getTree()); // model has some custom types - Model::registerMetaTypes(scriptEngine->getEngine()); + Model::registerMetaTypes(scriptEngine); // hook our avatar object into this script engine scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 24dcdcf6df..5054537287 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -43,6 +43,7 @@ #include "Audio.h" #include "Menu.h" #include "Util.h" +#include "AudioRingBuffer.h" static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; @@ -125,14 +126,16 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _scopeInput(0), _scopeOutputLeft(0), _scopeOutputRight(0), + _statsEnabled(false), _starveCount(0), _consecutiveNotMixedCount(0), _outgoingAvatarAudioSequenceNumber(0), _incomingMixedAudioSequenceNumberStats(INCOMING_SEQ_STATS_HISTORY_LENGTH), _interframeTimeGapStats(TIME_GAPS_STATS_INTERVAL_SAMPLES, TIME_GAP_STATS_WINDOW_INTERVALS), - _inputRingBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), + _audioInputMsecsReadStats(MSECS_PER_SECOND / (float)AUDIO_CALLBACK_MSECS * CALLBACK_ACCELERATOR_RATIO, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), + _inputRingBufferMsecsAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), _outputRingBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS), - _audioOutputBufferFramesAvailableStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS) + _audioOutputMsecsUnplayedStats(1, FRAMES_AVAILABLE_STATS_WINDOW_SECONDS) { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); @@ -148,15 +151,34 @@ void Audio::init(QGLWidget *parent) { void Audio::reset() { _ringBuffer.reset(); - + + // we don't want to reset seq numbers when space-bar reset occurs. + //_outgoingAvatarAudioSequenceNumber = 0; + + resetStats(); +} + +void Audio::resetStats() { _starveCount = 0; _consecutiveNotMixedCount = 0; _audioMixerAvatarStreamAudioStats = AudioStreamStats(); _audioMixerInjectedStreamAudioStatsMap.clear(); - //_outgoingAvatarAudioSequenceNumber = 0; _incomingMixedAudioSequenceNumberStats.reset(); + + _interframeTimeGapStats.reset(); + + _audioInputMsecsReadStats.reset(); + _inputRingBufferMsecsAvailableStats.reset(); + + _outputRingBufferFramesAvailableStats.reset(); + _audioOutputMsecsUnplayedStats.reset(); +} + +void Audio::audioMixerKilled() { + _outgoingAvatarAudioSequenceNumber = 0; + resetStats(); } QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) { @@ -499,8 +521,11 @@ void Audio::handleAudioInput() { } _inputRingBuffer.writeData(inputByteArray.data(), inputByteArray.size()); + + float audioInputMsecsRead = inputByteArray.size() / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC)); + _audioInputMsecsReadStats.update(audioInputMsecsRead); - while (_inputRingBuffer.samplesAvailable() > inputSamplesRequired) { + while (_inputRingBuffer.samplesAvailable() >= inputSamplesRequired) { int16_t* inputAudioSamples = new int16_t[inputSamplesRequired]; _inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired); @@ -811,11 +836,12 @@ AudioStreamStats Audio::getDownstreamAudioStreamStats() const { void Audio::sendDownstreamAudioStatsPacket() { - _inputRingBufferFramesAvailableStats.update(getInputRingBufferFramesAvailable()); + // since this function is called every second, we'll sample some of our stats here + + _inputRingBufferMsecsAvailableStats.update(getInputRingBufferMsecsAvailable()); - // since this function is called every second, we'll sample the number of audio frames available here. _outputRingBufferFramesAvailableStats.update(_ringBuffer.framesAvailable()); - _audioOutputBufferFramesAvailableStats.update(getOutputRingBufferFramesAvailable()); + _audioOutputMsecsUnplayedStats.update(getAudioOutputMsecsUnplayed()); // push the current seq number stats into history, which moves the history window forward 1s // (since that's how often pushStatsToHistory() is called) @@ -1286,6 +1312,10 @@ void Audio::toggleScopePause() { _scopeEnabledPause = !_scopeEnabledPause; } +void Audio::toggleStats() { + _statsEnabled = !_statsEnabled; +} + void Audio::selectAudioScopeFiveFrames() { if (Menu::getInstance()->isOptionChecked(MenuOption::AudioScopeFiveFrames)) { reallocateScope(5); @@ -1365,6 +1395,174 @@ void Audio::addBufferToScope( } } +void Audio::renderStats(const float* color, int width, int height) { + if (!_statsEnabled) { + return; + } + + const int LINES_WHEN_CENTERED = 30; + const int CENTERED_BACKGROUND_HEIGHT = STATS_HEIGHT_PER_LINE * LINES_WHEN_CENTERED; + + int lines = _audioMixerInjectedStreamAudioStatsMap.size() * 7 + 23; + int statsHeight = STATS_HEIGHT_PER_LINE * lines; + + + static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f }; + + int x = std::max((width - (int)STATS_WIDTH) / 2, 0); + int y = std::max((height - CENTERED_BACKGROUND_HEIGHT) / 2, 0); + int w = STATS_WIDTH; + int h = statsHeight; + renderBackground(backgroundColor, x, y, w, h); + + + int horizontalOffset = x + 5; + int verticalOffset = y; + + float scale = 0.10f; + float rotation = 0.0f; + int font = 2; + + + char latencyStatString[512]; + + const float BUFFER_SEND_INTERVAL_MSECS = BUFFER_SEND_INTERVAL_USECS / (float)USECS_PER_MSEC; + + float audioInputBufferLatency = 0.0f, inputRingBufferLatency = 0.0f, networkRoundtripLatency = 0.0f, mixerRingBufferLatency = 0.0f, outputRingBufferLatency = 0.0f, audioOutputBufferLatency = 0.0f; + + SharedNodePointer audioMixerNodePointer = NodeList::getInstance()->soloNodeOfType(NodeType::AudioMixer); + if (!audioMixerNodePointer.isNull()) { + audioInputBufferLatency = _audioInputMsecsReadStats.getWindowAverage(); + inputRingBufferLatency = getInputRingBufferAverageMsecsAvailable(); + networkRoundtripLatency = audioMixerNodePointer->getPingMs(); + mixerRingBufferLatency = _audioMixerAvatarStreamAudioStats._ringBufferFramesAvailableAverage * BUFFER_SEND_INTERVAL_MSECS; + outputRingBufferLatency = _outputRingBufferFramesAvailableStats.getWindowAverage() * BUFFER_SEND_INTERVAL_MSECS; + audioOutputBufferLatency = _audioOutputMsecsUnplayedStats.getWindowAverage(); + } + float totalLatency = audioInputBufferLatency + inputRingBufferLatency + networkRoundtripLatency + mixerRingBufferLatency + outputRingBufferLatency + audioOutputBufferLatency; + + sprintf(latencyStatString, " Audio input buffer: %7.2fms - avg msecs of samples read to the input ring buffer in last 10s", audioInputBufferLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " Input ring buffer: %7.2fms - avg msecs of samples in input ring buffer in last 10s", inputRingBufferLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " Network to mixer: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " AudioMixer ring buffer: %7.2fms - avg msecs of samples in audio mixer's ring buffer in last 10s", mixerRingBufferLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " Network to client: %7.2fms - half of last ping value calculated by the node list", networkRoundtripLatency / 2.0f); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " Output ring buffer: %7.2fms - avg msecs of samples in output ring buffer in last 10s", outputRingBufferLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " Audio output buffer: %7.2fms - avg msecs of samples in audio output buffer in last 10s", audioOutputBufferLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + sprintf(latencyStatString, " TOTAL: %7.2fms\n", totalLatency); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, latencyStatString, color); + + + verticalOffset += STATS_HEIGHT_PER_LINE; // blank line + + + char downstreamLabelString[] = "Downstream mixed audio stats:"; + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); + + renderAudioStreamStats(getDownstreamAudioStreamStats(), horizontalOffset, verticalOffset, scale, rotation, font, color, true); + + + verticalOffset += STATS_HEIGHT_PER_LINE; // blank line + + char upstreamMicLabelString[] = "Upstream mic audio stats:"; + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamMicLabelString, color); + + renderAudioStreamStats(_audioMixerAvatarStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color); + + + foreach(const AudioStreamStats& injectedStreamAudioStats, _audioMixerInjectedStreamAudioStatsMap) { + + verticalOffset += STATS_HEIGHT_PER_LINE; // blank line + + char upstreamInjectedLabelString[512]; + sprintf(upstreamInjectedLabelString, "Upstream injected audio stats: stream ID: %s", + injectedStreamAudioStats._streamIdentifier.toString().toLatin1().data()); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamInjectedLabelString, color); + + renderAudioStreamStats(injectedStreamAudioStats, horizontalOffset, verticalOffset, scale, rotation, font, color); + } +} + +void Audio::renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset, + float scale, float rotation, int font, const float* color, bool isDownstreamStats) { + + char stringBuffer[512]; + + sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", + streamStats._packetStreamStats.getLostRate() * 100.0f, + streamStats._packetStreamStats._numLost, + streamStats._packetStreamWindowStats.getLostRate() * 100.0f, + streamStats._packetStreamWindowStats._numLost); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + if (isDownstreamStats) { + + const float BUFFER_SEND_INTERVAL_MSECS = BUFFER_SEND_INTERVAL_USECS / (float)USECS_PER_MSEC; + sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u+%d, available: %u+%d", + streamStats._ringBufferDesiredJitterBufferFrames, + streamStats._ringBufferFramesAvailableAverage, + (int)(getAudioOutputAverageMsecsUnplayed() / BUFFER_SEND_INTERVAL_MSECS), + streamStats._ringBufferFramesAvailable, + (int)(getAudioOutputMsecsUnplayed() / BUFFER_SEND_INTERVAL_MSECS)); + } else { + sprintf(stringBuffer, " Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u", + streamStats._ringBufferDesiredJitterBufferFrames, + streamStats._ringBufferFramesAvailableAverage, + streamStats._ringBufferFramesAvailable); + } + + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + sprintf(stringBuffer, " Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u", + streamStats._ringBufferStarveCount, + streamStats._ringBufferConsecutiveNotMixedCount, + streamStats._ringBufferSilentFramesDropped, + streamStats._ringBufferOverflowCount); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + sprintf(stringBuffer, " Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(streamStats._timeGapMin).toLatin1().data(), + formatUsecTime(streamStats._timeGapMax).toLatin1().data(), + formatUsecTime(streamStats._timeGapAverage).toLatin1().data()); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); + + sprintf(stringBuffer, " Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s", + formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(), + formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(), + formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data()); + verticalOffset += STATS_HEIGHT_PER_LINE; + drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); +} + + void Audio::renderScope(int width, int height) { if (!_scopeEnabled) @@ -1622,15 +1820,14 @@ int Audio::calculateNumberOfFrameSamples(int numBytes) const { return frameSamples; } -int Audio::getOutputRingBufferFramesAvailable() const { - float networkOutputToOutputRatio = (_desiredOutputFormat.sampleRate() / (float)_outputFormat.sampleRate()) - * (_desiredOutputFormat.channelCount() / (float)_outputFormat.channelCount()); - - return (_audioOutput->bufferSize() - _audioOutput->bytesFree()) * networkOutputToOutputRatio - / (sizeof(int16_t) * _ringBuffer.getNumFrameSamples()); +float Audio::getAudioOutputMsecsUnplayed() const { + int bytesAudioOutputUnplayed = _audioOutput->bufferSize() - _audioOutput->bytesFree(); + float msecsAudioOutputUnplayed = bytesAudioOutputUnplayed / (float)_outputFormat.bytesForDuration(USECS_PER_MSEC); + return msecsAudioOutputUnplayed; } -int Audio::getInputRingBufferFramesAvailable() const { - float inputToNetworkInputRatio = calculateDeviceToNetworkInputRatio(_numInputCallbackBytes); - return _inputRingBuffer.samplesAvailable() / inputToNetworkInputRatio / _inputRingBuffer.getNumFrameSamples(); +float Audio::getInputRingBufferMsecsAvailable() const { + int bytesInInputRingBuffer = _inputRingBuffer.samplesAvailable() * sizeof(int16_t); + float msecsInInputRingBuffer = bytesInInputRingBuffer / (float)(_inputFormat.bytesForDuration(USECS_PER_MSEC)); + return msecsInInputRingBuffer; } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ed50815d78..67a951b8d9 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -71,6 +71,7 @@ public: void renderToolBox(int x, int y, bool boxed); void renderScope(int width, int height); + void renderStats(const float* color, int width, int height); int getNetworkSampleRate() { return SAMPLE_RATE; } int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; } @@ -78,12 +79,12 @@ public: bool getProcessSpatialAudio() const { return _processSpatialAudio; } const SequenceNumberStats& getIncomingMixedAudioSequenceNumberStats() const { return _incomingMixedAudioSequenceNumberStats; } + + float getInputRingBufferMsecsAvailable() const; + float getInputRingBufferAverageMsecsAvailable() const { return (float)_inputRingBufferMsecsAvailableStats.getWindowAverage(); } - int getInputRingBufferFramesAvailable() const; - int getInputRingBufferAverageFramesAvailable() const { return (int)_inputRingBufferFramesAvailableStats.getWindowAverage(); } - - int getOutputRingBufferFramesAvailable() const; - int getOutputRingBufferAverageFramesAvailable() const { return (int)_audioOutputBufferFramesAvailableStats.getWindowAverage(); } + float getAudioOutputMsecsUnplayed() const; + float getAudioOutputAverageMsecsUnplayed() const { return (float)_audioOutputMsecsUnplayedStats.getWindowAverage(); } public slots: void start(); @@ -93,12 +94,14 @@ public slots: void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples); void handleAudioInput(); void reset(); - void resetIncomingMixedAudioSequenceNumberStats() { _incomingMixedAudioSequenceNumberStats.reset(); } + void resetStats(); + void audioMixerKilled(); void toggleMute(); void toggleAudioNoiseReduction(); void toggleToneInjection(); void toggleScope(); void toggleScopePause(); + void toggleStats(); void toggleAudioSpatialProcessing(); void toggleStereoInput(); void selectAudioScopeFiveFrames(); @@ -245,6 +248,10 @@ private: void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols); void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); + // audio stats methods for rendering + void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset, + float scale, float rotation, int font, const float* color, bool isDownstreamStats = false); + // Audio scope data static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; @@ -261,6 +268,13 @@ private: QByteArray* _scopeInput; QByteArray* _scopeOutputLeft; QByteArray* _scopeOutputRight; +#ifdef _WIN32 + static const unsigned int STATS_WIDTH = 1500; +#else + static const unsigned int STATS_WIDTH = 650; +#endif + static const unsigned int STATS_HEIGHT_PER_LINE = 20; + bool _statsEnabled; int _starveCount; int _consecutiveNotMixedCount; @@ -273,10 +287,11 @@ private: MovingMinMaxAvg _interframeTimeGapStats; - MovingMinMaxAvg _inputRingBufferFramesAvailableStats; + MovingMinMaxAvg _audioInputMsecsReadStats; + MovingMinMaxAvg _inputRingBufferMsecsAvailableStats; MovingMinMaxAvg _outputRingBufferFramesAvailableStats; - MovingMinMaxAvg _audioOutputBufferFramesAvailableStats; + MovingMinMaxAvg _audioOutputMsecsUnplayedStats; }; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 16c3419561..f0fcc20201 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -593,6 +593,12 @@ Menu::Menu() : Qt::CTRL | Qt::SHIFT | Qt::Key_U, false); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioStats, + 0, + false, + appInstance->getAudio(), + SLOT(toggleStats())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, true); addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index e4221b0913..81dd26dc01 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -315,6 +315,7 @@ namespace MenuOption { const QString AudioScopeFrames = "Display Frames"; const QString AudioScopePause = "Pause Audio Scope"; const QString AudioScopeTwentyFrames = "Twenty"; + const QString AudioStats = "Audio Stats"; const QString AudioSpatialProcessingAlternateDistanceAttenuate = "Alternate distance attenuation"; const QString AudioSpatialProcessing = "Audio Spatial Processing"; const QString AudioSpatialProcessingDontDistanceAttenuate = "Don't calculate distance attenuation"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b9b9dc738f..27c4e39062 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -218,6 +218,52 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { + + if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), + _position) < 10.0f) { + // render pointing lasers + glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f); + float laserLength = 50.0f; + if (_handState == HAND_STATE_LEFT_POINTING || + _handState == HAND_STATE_BOTH_POINTING) { + int leftIndex = _skeletonModel.getLeftHandJointIndex(); + glm::vec3 leftPosition; + glm::quat leftRotation; + _skeletonModel.getJointPositionInWorldFrame(leftIndex, leftPosition); + _skeletonModel.getJointRotationInWorldFrame(leftIndex, leftRotation); + glPushMatrix(); { + glTranslatef(leftPosition.x, leftPosition.y, leftPosition.z); + float angle = glm::degrees(glm::angle(leftRotation)); + glm::vec3 axis = glm::axis(leftRotation); + glRotatef(angle, axis.x, axis.y, axis.z); + glBegin(GL_LINES); + glColor3f(laserColor.x, laserColor.y, laserColor.z); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, laserLength, 0.0f); + glEnd(); + } glPopMatrix(); + } + if (_handState == HAND_STATE_RIGHT_POINTING || + _handState == HAND_STATE_BOTH_POINTING) { + int rightIndex = _skeletonModel.getRightHandJointIndex(); + glm::vec3 rightPosition; + glm::quat rightRotation; + _skeletonModel.getJointPositionInWorldFrame(rightIndex, rightPosition); + _skeletonModel.getJointRotationInWorldFrame(rightIndex, rightRotation); + glPushMatrix(); { + glTranslatef(rightPosition.x, rightPosition.y, rightPosition.z); + float angle = glm::degrees(glm::angle(rightRotation)); + glm::vec3 axis = glm::axis(rightRotation); + glRotatef(angle, axis.x, axis.y, axis.z); + glBegin(GL_LINES); + glColor3f(laserColor.x, laserColor.y, laserColor.z); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(0.0f, laserLength, 0.0f); + glEnd(); + } glPopMatrix(); + } + } + // simple frustum check float boundingRadius = getBillboardSize(); ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ? diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 08e1cf83df..5ef1fbafea 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -125,7 +125,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) { glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); -} +} void Hand::renderHandTargets(bool isMine) { glPushMatrix(); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index ee242d179a..d3d1e74fc8 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -159,6 +159,10 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } _eyePosition = calculateAverageEyePosition(); + + float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f); + _filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition; + } void Head::relaxLean(float deltaTime) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 36df51fa6f..6d1e82b97f 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -88,8 +88,7 @@ public: const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() const { return _averageLoudness; } - glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } - + glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; } /// \return the point about which scaling occurs. glm::vec3 getScalePivot() const; @@ -110,6 +109,8 @@ public: void addLeanDeltas(float sideways, float forward); private: + glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } + // disallow copies of the Head, copy of owning Avatar is disallowed too Head(const Head&); Head& operator= (const Head&); @@ -120,6 +121,8 @@ private: glm::vec3 _leftEyePosition; glm::vec3 _rightEyePosition; glm::vec3 _eyePosition; + glm::vec3 _filteredEyePosition; // velocity filtered world space eye position + float _scale; float _lastLoudness; float _audioAttack; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 556f9dfc68..6bebc37f1d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -137,9 +137,6 @@ void MyAvatar::simulate(float deltaTime) { } _skeletonModel.setShowTrueJointTransforms(! Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)); - // no extra movement of the hand here any more ... - _handState = HAND_STATE_NULL; - { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); @@ -908,7 +905,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const { const Head* head = getHead(); return (renderMode != NORMAL_RENDER_MODE) || - (glm::length(cameraPosition - head->calculateAverageEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); + (glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale); } float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8f99308530..581044c522 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -21,9 +21,9 @@ enum AvatarHandState { HAND_STATE_NULL = 0, - HAND_STATE_OPEN, - HAND_STATE_GRASPING, - HAND_STATE_POINTING, + HAND_STATE_LEFT_POINTING, + HAND_STATE_RIGHT_POINTING, + HAND_STATE_BOTH_POINTING, NUM_HAND_STATES }; diff --git a/interface/src/models/ModelTreeRenderer.h b/interface/src/models/ModelTreeRenderer.h index b6df71565d..d69b85efe9 100644 --- a/interface/src/models/ModelTreeRenderer.h +++ b/interface/src/models/ModelTreeRenderer.h @@ -27,6 +27,7 @@ // Generic client side Octree renderer class. class ModelTreeRenderer : public OctreeRenderer, public ModelItemFBXService { + Q_OBJECT public: ModelTreeRenderer(); virtual ~ModelTreeRenderer(); @@ -56,7 +57,7 @@ public: protected: void clearModelsCache(); - Model* getModel(const ModelItem& modelItem); + Q_INVOKABLE Model* getModel(const ModelItem& modelItem); QMap _knownModelsItemModels; QMap _unknownModelsItemModels; }; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 3badde4042..c49873b5f5 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -178,7 +178,7 @@ void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direc float dist = sqrt(x * x + y * y); float z = -sqrt(1.0f - dist * dist); - glm::vec3 relativePosition = myAvatar->getHead()->calculateAverageEyePosition() + + glm::vec3 relativePosition = myAvatar->getHead()->getEyePosition() + glm::normalize(myAvatar->getOrientation() * glm::vec3(x, y, z)); //Rotate the UI pick ray by the avatar orientation @@ -274,7 +274,7 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { MyAvatar* myAvatar = application->getAvatar(); glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm); - glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition(); + glm::vec3 eyePos = myAvatar->getHead()->getEyePosition(); glm::quat orientation = glm::inverse(myAvatar->getOrientation()); glm::vec3 dir = orientation * glm::normalize(application->getCamera()->getPosition() - tip); //direction of ray goes towards camera glm::vec3 tipPos = orientation * (tip - eyePos); @@ -331,7 +331,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, glm::quat orientation = myAvatar->getOrientation(); - glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->calculateAverageEyePosition()); + glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition()); glm::vec3 relativeDirection = orientation * direction; float t; @@ -375,7 +375,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) { glPushMatrix(); const glm::quat& orientation = myAvatar->getOrientation(); - const glm::vec3& position = myAvatar->getHead()->calculateAverageEyePosition(); + const glm::vec3& position = myAvatar->getHead()->getEyePosition(); glm::mat4 rotation = glm::toMat4(orientation); @@ -1022,6 +1022,8 @@ void ApplicationOverlay::renderAudioMeter() { audio->renderScope(glWidget->width(), glWidget->height()); + audio->renderStats(WHITE_TEXT, glWidget->width(), glWidget->height()); + glBegin(GL_QUADS); if (isClipping) { glColor3f(1, 0, 0); @@ -1210,7 +1212,7 @@ void ApplicationOverlay::renderTexturedHemisphere() { Application* application = Application::getInstance(); MyAvatar* myAvatar = application->getAvatar(); const glm::quat& orientation = myAvatar->getOrientation(); - const glm::vec3& position = myAvatar->getHead()->calculateAverageEyePosition(); + const glm::vec3& position = myAvatar->getHead()->getEyePosition(); glm::mat4 rotation = glm::toMat4(orientation); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index f82bc7ba17..77598e0c5e 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -278,9 +278,8 @@ void Stats::display( Audio* audio = Application::getInstance()->getAudio(); - const QHash& audioMixerInjectedStreamAudioStatsMap = audio->getAudioMixerInjectedStreamAudioStatsMap(); - lines = _expanded ? 13 + (audioMixerInjectedStreamAudioStatsMap.size() + 2) * 3 : 3; + lines = _expanded ? 4 : 3; drawBackground(backgroundColor, horizontalOffset, 0, _pingStatsWidth, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; @@ -313,128 +312,6 @@ void Stats::display( verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, voxelMaxPing, color); - - char inputAudioLabelString[] = "Input: avail_avg_10s/avail"; - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, inputAudioLabelString, color); - - char inputAudioStatsString[512]; - sprintf(inputAudioStatsString, " %d/%d", audio->getInputRingBufferAverageFramesAvailable(), - audio->getInputRingBufferFramesAvailable()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, inputAudioStatsString, color); - - char audioMixerStatsLabelString[] = "AudioMixer stats:"; - char streamStatsFormatLabelString[] = "lost%/lost_30s%"; - char streamStatsFormatLabelString2[] = "desired/avail_avg_10s/avail"; - char streamStatsFormatLabelString3[] = "gaps: min/max/avg, starv/ovfl"; - char streamStatsFormatLabelString4[] = "gaps_30s: (same), notmix/sdrop"; - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, audioMixerStatsLabelString, color); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString, color); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString2, color); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString3, color); - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, streamStatsFormatLabelString4, color); - - char downstreamLabelString[] = " Downstream:"; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamLabelString, color); - - char downstreamAudioStatsString[512]; - - AudioStreamStats downstreamAudioStreamStats = audio->getDownstreamAudioStreamStats(); - - sprintf(downstreamAudioStatsString, " mix: %.2f%%/%.2f%%, %u/%u+%d/%u+%d", downstreamAudioStreamStats._packetStreamStats.getLostRate()*100.0f, - downstreamAudioStreamStats._packetStreamWindowStats.getLostRate() * 100.0f, - downstreamAudioStreamStats._ringBufferDesiredJitterBufferFrames, downstreamAudioStreamStats._ringBufferFramesAvailableAverage, - audio->getOutputRingBufferAverageFramesAvailable(), - downstreamAudioStreamStats._ringBufferFramesAvailable, audio->getOutputRingBufferFramesAvailable()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color); - - sprintf(downstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(downstreamAudioStreamStats._timeGapMin).toLatin1().data(), - formatUsecTime(downstreamAudioStreamStats._timeGapMax).toLatin1().data(), - formatUsecTime(downstreamAudioStreamStats._timeGapAverage).toLatin1().data(), - downstreamAudioStreamStats._ringBufferStarveCount, downstreamAudioStreamStats._ringBufferOverflowCount); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color); - - sprintf(downstreamAudioStatsString, " %s/%s/%s, %u/?", formatUsecTime(downstreamAudioStreamStats._timeGapWindowMin).toLatin1().data(), - formatUsecTime(downstreamAudioStreamStats._timeGapWindowMax).toLatin1().data(), - formatUsecTime(downstreamAudioStreamStats._timeGapWindowAverage).toLatin1().data(), - downstreamAudioStreamStats._ringBufferConsecutiveNotMixedCount); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, downstreamAudioStatsString, color); - - - char upstreamLabelString[] = " Upstream:"; - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamLabelString, color); - - char upstreamAudioStatsString[512]; - - const AudioStreamStats& audioMixerAvatarAudioStreamStats = audio->getAudioMixerAvatarStreamAudioStats(); - - sprintf(upstreamAudioStatsString, " mic: %.2f%%/%.2f%%, %u/%u/%u", audioMixerAvatarAudioStreamStats._packetStreamStats.getLostRate()*100.0f, - audioMixerAvatarAudioStreamStats._packetStreamWindowStats.getLostRate() * 100.0f, - audioMixerAvatarAudioStreamStats._ringBufferDesiredJitterBufferFrames, audioMixerAvatarAudioStreamStats._ringBufferFramesAvailableAverage, - audioMixerAvatarAudioStreamStats._ringBufferFramesAvailable); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - - sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapMin).toLatin1().data(), - formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapMax).toLatin1().data(), - formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapAverage).toLatin1().data(), - audioMixerAvatarAudioStreamStats._ringBufferStarveCount, audioMixerAvatarAudioStreamStats._ringBufferOverflowCount); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - - sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowMin).toLatin1().data(), - formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowMax).toLatin1().data(), - formatUsecTime(audioMixerAvatarAudioStreamStats._timeGapWindowAverage).toLatin1().data(), - audioMixerAvatarAudioStreamStats._ringBufferConsecutiveNotMixedCount, audioMixerAvatarAudioStreamStats._ringBufferSilentFramesDropped); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - - foreach(const AudioStreamStats& injectedStreamAudioStats, audioMixerInjectedStreamAudioStatsMap) { - - sprintf(upstreamAudioStatsString, " inj: %.2f%%/%.2f%%, %u/%u/%u", injectedStreamAudioStats._packetStreamStats.getLostRate()*100.0f, - injectedStreamAudioStats._packetStreamWindowStats.getLostRate() * 100.0f, - injectedStreamAudioStats._ringBufferDesiredJitterBufferFrames, injectedStreamAudioStats._ringBufferFramesAvailableAverage, - injectedStreamAudioStats._ringBufferFramesAvailable); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - - sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(injectedStreamAudioStats._timeGapMin).toLatin1().data(), - formatUsecTime(injectedStreamAudioStats._timeGapMax).toLatin1().data(), - formatUsecTime(injectedStreamAudioStats._timeGapAverage).toLatin1().data(), - injectedStreamAudioStats._ringBufferStarveCount, injectedStreamAudioStats._ringBufferOverflowCount); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - - sprintf(upstreamAudioStatsString, " %s/%s/%s, %u/%u", formatUsecTime(injectedStreamAudioStats._timeGapWindowMin).toLatin1().data(), - formatUsecTime(injectedStreamAudioStats._timeGapWindowMax).toLatin1().data(), - formatUsecTime(injectedStreamAudioStats._timeGapWindowAverage).toLatin1().data(), - injectedStreamAudioStats._ringBufferConsecutiveNotMixedCount, injectedStreamAudioStats._ringBufferSilentFramesDropped); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, upstreamAudioStatsString, color); - } } verticalOffset = 0; diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index da2d8336de..4723bca906 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -30,7 +30,7 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer(const QUuid& streamIdentifier, const uchar MAX_INJECTOR_VOLUME = 255; -int InjectedAudioRingBuffer::parseData(const QByteArray& packet, int packetsSkipped) { +int InjectedAudioRingBuffer::parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) { frameReceivedUpdateTimingStats(); // setup a data stream to read from this packet diff --git a/libraries/audio/src/InjectedAudioRingBuffer.h b/libraries/audio/src/InjectedAudioRingBuffer.h index f226d99b12..4a1f8b5292 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.h +++ b/libraries/audio/src/InjectedAudioRingBuffer.h @@ -20,7 +20,7 @@ class InjectedAudioRingBuffer : public PositionalAudioRingBuffer { public: InjectedAudioRingBuffer(const QUuid& streamIdentifier = QUuid(), bool dynamicJitterBuffer = false); - int parseData(const QByteArray& packet, int packetsSkipped = 0); + int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped); const QUuid& getStreamIdentifier() const { return _streamIdentifier; } float getRadius() const { return _radius; } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index f0d6aff80b..0b14a12858 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -45,7 +45,7 @@ public: PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false, bool dynamicJitterBuffers = false); - virtual int parseData(const QByteArray& packet, int packetsSkipped = 0) = 0; + virtual int parseDataAndHandleDroppedPackets(const QByteArray& packet, int packetsSkipped) = 0; int parsePositionalData(const QByteArray& positionalByteArray); int parseListenModeData(const QByteArray& listenModeByteArray); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 768633c366..008aecc817 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -185,8 +185,8 @@ public: void setClampedTargetScale(float targetScale); // Hand State - void setHandState(char s) { _handState = s; } - char getHandState() const { return _handState; } + Q_INVOKABLE void setHandState(char s) { _handState = s; } + Q_INVOKABLE char getHandState() const { return _handState; } const QVector& getJointData() const { return _jointData; } void setJointData(const QVector& jointData) { _jointData = jointData; } diff --git a/libraries/models/src/ModelsScriptingInterface.cpp b/libraries/models/src/ModelsScriptingInterface.cpp index 634039f949..d2c3ed1ba7 100644 --- a/libraries/models/src/ModelsScriptingInterface.cpp +++ b/libraries/models/src/ModelsScriptingInterface.cpp @@ -70,7 +70,7 @@ ModelItemProperties ModelsScriptingInterface::getModelProperties(ModelItemID mod if (_modelTree) { _modelTree->lockForRead(); ModelItem* model = const_cast(_modelTree->findModelByID(identity.id, true)); - if (model) { + if (model && _modelTree->getGeometryForModel(*model)) { model->setSittingPoints(_modelTree->getGeometryForModel(*model)->sittingPoints); results.copyFromModelItem(*model); } else { diff --git a/libraries/script-engine/src/ArrayBufferClass.cpp b/libraries/script-engine/src/ArrayBufferClass.cpp index ab33b5ffe7..b84188f707 100644 --- a/libraries/script-engine/src/ArrayBufferClass.cpp +++ b/libraries/script-engine/src/ArrayBufferClass.cpp @@ -23,8 +23,8 @@ static const QString CLASS_NAME = "ArrayBuffer"; Q_DECLARE_METATYPE(QByteArray*) ArrayBufferClass::ArrayBufferClass(ScriptEngine* scriptEngine) : -QObject(scriptEngine->getEngine()), -QScriptClass(scriptEngine->getEngine()), +QObject(scriptEngine), +QScriptClass(scriptEngine), _scriptEngine(scriptEngine) { qScriptRegisterMetaType(engine(), toScriptValue, fromScriptValue); QScriptValue global = engine()->globalObject(); diff --git a/libraries/script-engine/src/ArrayBufferViewClass.cpp b/libraries/script-engine/src/ArrayBufferViewClass.cpp index aad2e6add7..cf776ed834 100644 --- a/libraries/script-engine/src/ArrayBufferViewClass.cpp +++ b/libraries/script-engine/src/ArrayBufferViewClass.cpp @@ -14,8 +14,8 @@ Q_DECLARE_METATYPE(QByteArray*) ArrayBufferViewClass::ArrayBufferViewClass(ScriptEngine* scriptEngine) : -QObject(scriptEngine->getEngine()), -QScriptClass(scriptEngine->getEngine()), +QObject(scriptEngine), +QScriptClass(scriptEngine), _scriptEngine(scriptEngine) { // Save string handles for quick lookup _bufferName = engine()->toStringHandle(BUFFER_PROPERTY_NAME.toLatin1()); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index fab21ea928..df66fa44d5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -87,7 +87,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _isFinished(false), _isRunning(false), _isInitialized(false), - _engine(), _isAvatar(false), _avatarIdentityTimer(NULL), _avatarBillboardTimer(NULL), @@ -113,7 +112,6 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, _isFinished(false), _isRunning(false), _isInitialized(false), - _engine(), _isAvatar(false), _avatarIdentityTimer(NULL), _avatarBillboardTimer(NULL), @@ -194,7 +192,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa _avatarData = avatarData; // remove the old Avatar property, if it exists - _engine.globalObject().setProperty(objectName, QScriptValue()); + globalObject().setProperty(objectName, QScriptValue()); // give the script engine the new Avatar script property registerGlobalObject(objectName, _avatarData); @@ -202,7 +200,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa void ScriptEngine::setAvatarHashMap(AvatarHashMap* avatarHashMap, const QString& objectName) { // remove the old Avatar property, if it exists - _engine.globalObject().setProperty(objectName, QScriptValue()); + globalObject().setProperty(objectName, QScriptValue()); // give the script engine the new avatar hash map registerGlobalObject(objectName, avatarHashMap); @@ -231,48 +229,48 @@ void ScriptEngine::init() { _particlesScriptingInterface.init(); // register various meta-types - registerMetaTypes(&_engine); - registerMIDIMetaTypes(&_engine); - registerVoxelMetaTypes(&_engine); - registerEventTypes(&_engine); - registerMenuItemProperties(&_engine); - registerAnimationTypes(&_engine); - registerAvatarTypes(&_engine); - Bitstream::registerTypes(&_engine); + registerMetaTypes(this); + registerMIDIMetaTypes(this); + registerVoxelMetaTypes(this); + registerEventTypes(this); + registerMenuItemProperties(this); + registerAnimationTypes(this); + registerAvatarTypes(this); + Bitstream::registerTypes(this); - qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); - qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); - qScriptRegisterSequenceMetaType >(&_engine); + qScriptRegisterMetaType(this, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); + qScriptRegisterMetaType(this, ParticleIDtoScriptValue, ParticleIDfromScriptValue); + qScriptRegisterSequenceMetaType >(this); - qScriptRegisterMetaType(&_engine, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue); - qScriptRegisterMetaType(&_engine, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue); - qScriptRegisterMetaType(&_engine, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue); - qScriptRegisterSequenceMetaType >(&_engine); + qScriptRegisterMetaType(this, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue); + qScriptRegisterMetaType(this, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue); + qScriptRegisterMetaType(this, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue); + qScriptRegisterSequenceMetaType >(this); - qScriptRegisterSequenceMetaType >(&_engine); - qScriptRegisterSequenceMetaType >(&_engine); - qScriptRegisterSequenceMetaType >(&_engine); + qScriptRegisterSequenceMetaType >(this); + qScriptRegisterSequenceMetaType >(this); + qScriptRegisterSequenceMetaType >(this); - QScriptValue xmlHttpRequestConstructorValue = _engine.newFunction(XMLHttpRequestClass::constructor); - _engine.globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); + QScriptValue xmlHttpRequestConstructorValue = newFunction(XMLHttpRequestClass::constructor); + globalObject().setProperty("XMLHttpRequest", xmlHttpRequestConstructorValue); - QScriptValue printConstructorValue = _engine.newFunction(debugPrint); - _engine.globalObject().setProperty("print", printConstructorValue); + QScriptValue printConstructorValue = newFunction(debugPrint); + globalObject().setProperty("print", printConstructorValue); - QScriptValue soundConstructorValue = _engine.newFunction(soundConstructor); - QScriptValue soundMetaObject = _engine.newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); - _engine.globalObject().setProperty("Sound", soundMetaObject); + QScriptValue soundConstructorValue = newFunction(soundConstructor); + QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); + globalObject().setProperty("Sound", soundMetaObject); - QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject(); - _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); + QScriptValue injectionOptionValue = scriptValueFromQMetaObject(); + globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject(); - _engine.globalObject().setProperty("LocalVoxels", localVoxelsValue); + QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); + globalObject().setProperty("LocalVoxels", localVoxelsValue); - qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue); - qScriptRegisterMetaType( &_engine, injectorToScriptValueInputController, injectorFromScriptValueInputController); + qScriptRegisterMetaType(this, injectorToScriptValue, injectorFromScriptValue); + qScriptRegisterMetaType( this, injectorToScriptValueInputController, injectorFromScriptValueInputController); - qScriptRegisterMetaType(&_engine, animationDetailsToScriptValue, animationDetailsFromScriptValue); + qScriptRegisterMetaType(this, animationDetailsToScriptValue, animationDetailsFromScriptValue); registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); @@ -287,15 +285,14 @@ void ScriptEngine::init() { registerGlobalObject("Voxels", &_voxelsScriptingInterface); // constants - QScriptValue globalObject = _engine.globalObject(); - globalObject.setProperty("TREE_SCALE", _engine.newVariant(QVariant(TREE_SCALE))); - globalObject.setProperty("COLLISION_GROUP_ENVIRONMENT", _engine.newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); - globalObject.setProperty("COLLISION_GROUP_AVATARS", _engine.newVariant(QVariant(COLLISION_GROUP_AVATARS))); - globalObject.setProperty("COLLISION_GROUP_VOXELS", _engine.newVariant(QVariant(COLLISION_GROUP_VOXELS))); - globalObject.setProperty("COLLISION_GROUP_PARTICLES", _engine.newVariant(QVariant(COLLISION_GROUP_PARTICLES))); + globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); + globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); + globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS))); + globalObject().setProperty("COLLISION_GROUP_VOXELS", newVariant(QVariant(COLLISION_GROUP_VOXELS))); + globalObject().setProperty("COLLISION_GROUP_PARTICLES", newVariant(QVariant(COLLISION_GROUP_PARTICLES))); - globalObject.setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); - globalObject.setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", _engine.newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); + globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); + globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); // let the VoxelPacketSender know how frequently we plan to call it _voxelsScriptingInterface.getVoxelPacketSender()->setProcessCallIntervalHint(SCRIPT_DATA_CALLBACK_USECS); @@ -304,8 +301,8 @@ void ScriptEngine::init() { QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { if (object) { - QScriptValue value = _engine.newQObject(object); - _engine.globalObject().setProperty(name, value); + QScriptValue value = newQObject(object); + globalObject().setProperty(name, value); return value; } return QScriptValue::NullValue; @@ -313,15 +310,15 @@ QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* ob void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, QScriptValue object) { - QScriptValue setterFunction = _engine.newFunction(setter, 1); - QScriptValue getterFunction = _engine.newFunction(getter); + QScriptValue setterFunction = newFunction(setter, 1); + QScriptValue getterFunction = newFunction(getter); if (!object.isNull()) { object.setProperty(name, setterFunction, QScriptValue::PropertySetter); object.setProperty(name, getterFunction, QScriptValue::PropertyGetter); } else { - _engine.globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); - _engine.globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); + globalObject().setProperty(name, setterFunction, QScriptValue::PropertySetter); + globalObject().setProperty(name, getterFunction, QScriptValue::PropertyGetter); } } @@ -330,25 +327,24 @@ void ScriptEngine::evaluate() { init(); } - QScriptValue result = _engine.evaluate(_scriptContents); + QScriptValue result = evaluate(_scriptContents); - if (_engine.hasUncaughtException()) { - int line = _engine.uncaughtExceptionLineNumber(); + if (hasUncaughtException()) { + int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); - _engine.clearExceptions(); + clearExceptions(); } } QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { - QScriptValue result = _engine.evaluate(program, fileName, lineNumber); - bool hasUncaughtException = _engine.hasUncaughtException(); - if (hasUncaughtException) { - int line = _engine.uncaughtExceptionLineNumber(); + QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); + if (hasUncaughtException()) { + int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ": " << result.toString(); } - emit evaluationFinished(result, hasUncaughtException); - _engine.clearExceptions(); + emit evaluationFinished(result, hasUncaughtException()); + clearExceptions(); return result; } @@ -372,12 +368,12 @@ void ScriptEngine::run() { _isFinished = false; emit runningStateChanged(); - QScriptValue result = _engine.evaluate(_scriptContents); - if (_engine.hasUncaughtException()) { - int line = _engine.uncaughtExceptionLineNumber(); + QScriptValue result = evaluate(_scriptContents); + if (hasUncaughtException()) { + int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); - _engine.clearExceptions(); + clearExceptions(); } QElapsedTimer startTime; @@ -532,11 +528,11 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - if (_engine.hasUncaughtException()) { - int line = _engine.uncaughtExceptionLineNumber(); - qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << _engine.uncaughtException().toString(); - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); - _engine.clearExceptions(); + if (hasUncaughtException()) { + int line = uncaughtExceptionLineNumber(); + qDebug() << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); + clearExceptions(); } emit update(deltaTime); @@ -694,12 +690,12 @@ void ScriptEngine::include(const QString& includeFile) { } } - QScriptValue result = _engine.evaluate(includeContents); - if (_engine.hasUncaughtException()) { - int line = _engine.uncaughtExceptionLineNumber(); + QScriptValue result = evaluate(includeContents); + if (hasUncaughtException()) { + int line = uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at (" << includeFile << ") line" << line << ":" << result.toString(); emit errorMessage("Uncaught exception at (" + includeFile + ") line" + QString::number(line) + ":" + result.toString()); - _engine.clearExceptions(); + clearExceptions(); } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 0eda74914f..53c2a72b00 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -38,7 +38,7 @@ const QString NO_SCRIPT(""); const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 1000) + 0.5); -class ScriptEngine : public QObject { +class ScriptEngine : public QScriptEngine { Q_OBJECT public: ScriptEngine(const QUrl& scriptURL, @@ -57,7 +57,6 @@ public: /// Access the ModelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener static ModelsScriptingInterface* getModelsScriptingInterface() { return &_modelsScriptingInterface; } - QScriptEngine* getEngine() { return &_engine; } ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } /// sets the script contents, will return false if failed, will fail if script is already running @@ -121,7 +120,6 @@ protected: bool _isFinished; bool _isRunning; bool _isInitialized; - QScriptEngine _engine; bool _isAvatar; QTimer* _avatarIdentityTimer; QTimer* _avatarBillboardTimer;