diff --git a/examples/audioReflectorTools.js b/examples/audioReflectorTools.js index 76869de578..f299407e54 100644 --- a/examples/audioReflectorTools.js +++ b/examples/audioReflectorTools.js @@ -7,6 +7,8 @@ // // Tools for manipulating the attributes of the AudioReflector behavior // +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // diff --git a/examples/clap.js b/examples/clap.js index a0efcfab7b..9da36ba094 100644 --- a/examples/clap.js +++ b/examples/clap.js @@ -50,7 +50,7 @@ function maybePlaySound(deltaTime) { const CLAP_DISTANCE = 0.2; if (!clapping[palm] && (distanceBetween < CLAP_DISTANCE) && (speed > CLAP_SPEED)) { - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); options.position = palm1Position; options.volume = speed / 2.0; if (options.volume > 1.0) options.volume = 1.0; diff --git a/examples/drumStick.js b/examples/drumStick.js index e9ac54f814..188661b000 100644 --- a/examples/drumStick.js +++ b/examples/drumStick.js @@ -61,7 +61,7 @@ function checkSticks(deltaTime) { // Waiting for change in velocity direction or slowing to trigger drum sound if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) { state[palm] = 0; - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); options.position = Controller.getSpatialControlPosition(palm * 2 + 1); if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; } options.volume = strokeSpeed[palm]; diff --git a/examples/playSound.js b/examples/playSound.js index fb589bc9e3..317581ba36 100644 --- a/examples/playSound.js +++ b/examples/playSound.js @@ -9,12 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // First, load the clap sound from a URL -var clap = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw"); +var clap = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw"); function maybePlaySound(deltaTime) { if (Math.random() < 0.01) { // Set the location and other info for the sound to play - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); var palmPosition = Controller.getSpatialControlPosition(0); options.position = palmPosition; options.volume = 0.5; diff --git a/examples/spaceInvadersExample.js b/examples/spaceInvadersExample.js index 5b25fa1236..5d62102d71 100644 --- a/examples/spaceInvadersExample.js +++ b/examples/spaceInvadersExample.js @@ -217,7 +217,7 @@ function update(deltaTime) { if (invaderStepOfCycle % stepsPerSound == 0) { // play the move sound - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -329,7 +329,7 @@ function fireMissile() { lifetime: 5 }); - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -379,7 +379,7 @@ function deleteIfInvader(possibleInvaderParticle) { Particles.deleteParticle(myMissile); // play the hit sound - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); if (soundInMyHead) { options.position = { x: MyAvatar.position.x + 0.0, y: MyAvatar.position.y + 0.1, @@ -417,4 +417,3 @@ initializeInvaders(); // shut down the game after 1 minute var gameTimer = Script.setTimeout(endGame, itemLifetimes * 1000); - diff --git a/examples/testingVoxelViewerRestart.js b/examples/testingVoxelViewerRestart.js index 4fbdee1223..c4ab67e8ba 100644 --- a/examples/testingVoxelViewerRestart.js +++ b/examples/testingVoxelViewerRestart.js @@ -5,7 +5,8 @@ // Created by Brad Hefta-Gaub on 2/26/14 // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // -// This is an example script +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // var count = 0; diff --git a/examples/toyball.js b/examples/toyball.js index de68e97357..d312c1bc94 100644 --- a/examples/toyball.js +++ b/examples/toyball.js @@ -111,7 +111,7 @@ function checkControllerSide(whichSide) { velocity : { x: 0, y: 0, z: 0}, inHand: true }; Particles.editParticle(closestParticle, properties); - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); options.position = ballPosition; options.volume = 1.0; Audio.playSound(catchSound, options); @@ -152,7 +152,7 @@ function checkControllerSide(whichSide) { } // Play a new ball sound - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); options.position = ballPosition; options.volume = 1.0; Audio.playSound(catchSound, options); @@ -201,7 +201,7 @@ function checkControllerSide(whichSide) { rightHandParticle = false; } - var options = new AudioInjectionOptions();
 + var options = new AudioInjectionOptions(); options.position = ballPosition; options.volume = 1.0; Audio.playSound(throwSound, options); diff --git a/examples/voxelDrumming.js b/examples/voxelDrumming.js index 7f3495dea7..1b320ed755 100644 --- a/examples/voxelDrumming.js +++ b/examples/voxelDrumming.js @@ -64,7 +64,7 @@ collisionBubble[1] = Overlays.addOverlay("sphere", visible: false }); -var audioOptions = new AudioInjectionOptions();
 +var audioOptions = new AudioInjectionOptions(); audioOptions.position = { x: MyAvatar.position.x, y: MyAvatar.position.y + 1, z: MyAvatar.position.z }; audioOptions.volume = 1; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f461b7e44c..3ae4720351 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2651,6 +2651,8 @@ void Application::displayOverlay() { audioMeterY, Menu::getInstance()->isOptionChecked(MenuOption::Mirror)); + _audio.renderScope(_glWidget->width(), _glWidget->height()); + glBegin(GL_QUADS); if (isClipping) { glColor3f(1, 0, 0); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 698a8db725..eb4a751356 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -92,7 +92,14 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _processSpatialAudio(false), _spatialAudioStart(0), _spatialAudioFinish(0), - _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true) // random access mode + _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true), // random access mode + _scopeEnabled(false), + _scopeEnabledPause(false), + _scopeInputOffset(0), + _scopeOutputOffset(0), + _scopeInput(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0), + _scopeOutputLeft(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0), + _scopeOutputRight(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0) { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); @@ -575,6 +582,14 @@ void Audio::handleAudioInput() { processProceduralAudio(monoAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); } + if (_scopeEnabled && !_scopeEnabledPause) { + unsigned int numMonoAudioChannels = 1; + unsigned int monoAudioChannel = 0; + addBufferToScope(_scopeInput, _scopeInputOffset, monoAudioSamples, monoAudioChannel, numMonoAudioChannels); + _scopeInputOffset += NETWORK_SAMPLES_PER_FRAME; + _scopeInputOffset %= SAMPLES_PER_SCOPE_WIDTH; + } + NodeList* nodeList = NodeList::getInstance(); SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer); @@ -813,6 +828,30 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { if (_outputDevice) { _outputDevice->write(outputBuffer); } + + if (_scopeEnabled && !_scopeEnabledPause) { + unsigned int numAudioChannels = _desiredOutputFormat.channelCount(); + int16_t* samples = ringBufferSamples; + for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) { + + unsigned int audioChannel = 0; + addBufferToScope( + _scopeOutputLeft, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + audioChannel = 1; + addBufferToScope( + _scopeOutputRight, + _scopeOutputOffset, + samples, audioChannel, numAudioChannels); + + _scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME; + _scopeOutputOffset %= SAMPLES_PER_SCOPE_WIDTH; + samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels; + } + } + delete[] ringBufferSamples; } } @@ -1019,6 +1058,140 @@ void Audio::renderToolBox(int x, int y, bool boxed) { glDisable(GL_TEXTURE_2D); } +void Audio::toggleScopePause() { + _scopeEnabledPause = !_scopeEnabledPause; +} + +void Audio::toggleScope() { + _scopeEnabled = !_scopeEnabled; + if (_scopeEnabled) { + static const int width = SAMPLES_PER_SCOPE_WIDTH; + _scopeInputOffset = 0; + _scopeOutputOffset = 0; + memset(_scopeInput.data(), 0, width * sizeof(int16_t)); + memset(_scopeOutputLeft.data(), 0, width * sizeof(int16_t)); + memset(_scopeOutputRight.data(), 0, width * sizeof(int16_t)); + } +} + +void Audio::addBufferToScope( + QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels) { + + // Constant multiplier to map sample value to vertical size of scope + float multiplier = (float)MULTIPLIER_SCOPE_HEIGHT / logf(2.0f); + + // Temporary variable receives sample value + float sample; + + // Temporary variable receives mapping of sample value + int16_t value; + + // Short int pointer to mapped samples in byte array + int16_t* destination = (int16_t*) byteArray.data(); + + for (int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) { + + sample = (float)source[i * sourceNumberOfChannels + sourceChannel]; + + if (sample > 0) { + value = (int16_t)(multiplier * logf(sample)); + } else if (sample < 0) { + value = (int16_t)(-multiplier * logf(-sample)); + } else { + value = 0; + } + + destination[i + frameOffset] = value; + } +} + +void Audio::renderScope(int width, int height) { + + if (!_scopeEnabled) + return; + + static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f }; + static const float gridColor[4] = { 0.3f, 0.3f, 0.3f, 0.6f }; + static const float inputColor[4] = { 0.3f, .7f, 0.3f, 0.6f }; + static const float outputLeftColor[4] = { 0.7f, .3f, 0.3f, 0.6f }; + static const float outputRightColor[4] = { 0.3f, .3f, 0.7f, 0.6f }; + static const int gridRows = 2; + static const int gridCols = 5; + + int x = (width - SAMPLES_PER_SCOPE_WIDTH) / 2; + int y = (height - SAMPLES_PER_SCOPE_HEIGHT) / 2; + int w = SAMPLES_PER_SCOPE_WIDTH; + int h = SAMPLES_PER_SCOPE_HEIGHT; + + renderBackground(backgroundColor, x, y, w, h); + renderGrid(gridColor, x, y, w, h, gridRows, gridCols); + renderLineStrip(inputColor, x, y, w, _scopeInputOffset, _scopeInput); + renderLineStrip(outputLeftColor, x, y, w, _scopeOutputOffset, _scopeOutputLeft); + renderLineStrip(outputRightColor, x, y, w, _scopeOutputOffset, _scopeOutputRight); +} + +void Audio::renderBackground(const float* color, int x, int y, int width, int height) { + + glColor4fv(color); + glBegin(GL_QUADS); + + glVertex2i(x, y); + glVertex2i(x + width, y); + glVertex2i(x + width, y + height); + glVertex2i(x , y + height); + + glEnd(); + glColor4f(1, 1, 1, 1); +} + +void Audio::renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols) { + + glColor4fv(color); + glBegin(GL_LINES); + + int dx = width / cols; + int dy = height / rows; + int tx = x; + int ty = y; + + // Draw horizontal grid lines + for (int i = rows + 1; --i >= 0; ) { + glVertex2i(x, ty); + glVertex2i(x + width, ty); + ty += dy; + } + // Draw vertical grid lines + for (int i = cols + 1; --i >= 0; ) { + glVertex2i(tx, y); + glVertex2i(tx, y + height); + tx += dx; + } + glEnd(); + glColor4f(1, 1, 1, 1); +} + +void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray& byteArray) { + + glColor4fv(color); + glBegin(GL_LINE_STRIP); + + int16_t sample; + int16_t* samples = ((int16_t*) byteArray.data()) + offset; + y += SAMPLES_PER_SCOPE_HEIGHT / 2; + for (int i = n - offset; --i >= 0; ) { + sample = *samples++; + glVertex2i(x++, y - sample); + } + samples = (int16_t*) byteArray.data(); + for (int i = offset; --i >= 0; ) { + sample = *samples++; + glVertex2i(x++, y - sample); + } + glEnd(); + glColor4f(1, 1, 1, 1); +} + + bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) { bool supportedFormat = false; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 96def43dd2..ebd7f8612a 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,7 @@ public: bool mousePressEvent(int x, int y); void renderToolBox(int x, int y, bool boxed); + void renderScope(int width, int height); int getNetworkSampleRate() { return SAMPLE_RATE; } int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; } @@ -83,6 +85,8 @@ public slots: void toggleMute(); void toggleAudioNoiseReduction(); void toggleToneInjection(); + void toggleScope(); + void toggleScopePause(); void toggleAudioSpatialProcessing(); virtual void handleAudioByteArray(const QByteArray& audioByteArray); @@ -196,6 +200,29 @@ private: int calculateNumberOfFrameSamples(int numBytes); float calculateDeviceToNetworkInputRatio(int numBytes); + // Audio scope methods for data acquisition + void addBufferToScope( + QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels); + + // Audio scope methods for rendering + void renderBackground(const float* color, int x, int y, int width, int height); + 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 scope data + static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + static const unsigned int FRAMES_PER_SCOPE = 5; + static const unsigned int SAMPLES_PER_SCOPE_WIDTH = FRAMES_PER_SCOPE * NETWORK_SAMPLES_PER_FRAME; + static const unsigned int MULTIPLIER_SCOPE_HEIGHT = 20; + static const unsigned int SAMPLES_PER_SCOPE_HEIGHT = 2 * 15 * MULTIPLIER_SCOPE_HEIGHT; + bool _scopeEnabled; + bool _scopeEnabledPause; + int _scopeInputOffset; + int _scopeOutputOffset; + QByteArray _scopeInput; + QByteArray _scopeOutputLeft; + QByteArray _scopeOutputRight; + }; diff --git a/interface/src/AudioReflector.h b/interface/src/AudioReflector.h index 582345e064..1bfb52ea09 100644 --- a/interface/src/AudioReflector.h +++ b/interface/src/AudioReflector.h @@ -5,6 +5,9 @@ // Created by Brad Hefta-Gaub on 4/2/2014 // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// #ifndef interface_AudioReflector_h #define interface_AudioReflector_h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b5b0f65d82..84b17fddca 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -260,6 +260,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::AudioScope, 0, false, + appInstance->getAudio(), + SLOT(toggleScope())); QMenu* developerMenu = addMenu("Developer"); @@ -386,6 +389,11 @@ Menu::Menu() : false, appInstance->getAudio(), SLOT(toggleToneInjection())); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScopePause, + Qt::CTRL | Qt::Key_P, + false, + appInstance->getAudio(), + SLOT(toggleScopePause())); QMenu* spatialAudioMenu = audioDebugMenu->addMenu("Spatial Audio"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index a55570afaf..a1e6cded2a 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -259,8 +259,9 @@ namespace MenuOption { const QString AmbientOcclusion = "Ambient Occlusion"; const QString Atmosphere = "Atmosphere"; const QString AudioNoiseReduction = "Audio Noise Reduction"; + const QString AudioScope = "Audio Scope"; + const QString AudioScopePause = "Pause Audio Scope"; const QString AudioToneInjection = "Inject Test Tone"; - const QString AudioSpatialProcessing = "Audio Spatial Processing"; const QString AudioSpatialProcessingHeadOriented = "Head Oriented"; const QString AudioSpatialProcessingIncludeOriginal = "Includes Network Original"; diff --git a/interface/src/voxels/PrimitiveRenderer.h b/interface/src/voxels/PrimitiveRenderer.h index 8626e2e2a4..06dac119b0 100644 --- a/interface/src/voxels/PrimitiveRenderer.h +++ b/interface/src/voxels/PrimitiveRenderer.h @@ -106,7 +106,7 @@ private: /// Copy constructor prohibited. /// Primitive( - const Primitive& prim + const Primitive& copy ); // SPI methods are defined here @@ -153,14 +153,14 @@ public: /// Configuration dependency injection constructor. /// Cube( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faces + float x, ///< Cube location on X-axis + float y, ///< Cube location on Y-axis + float z, ///< Cube location on Z-axis + float s, ///< Cube size + unsigned char r, ///< Cube red color component + unsigned char g, ///< Cube green color component + unsigned char b, ///< Cube blue color component + unsigned char faces ///< Bitmask of faces of cube excluded from construction ); ~Cube(); @@ -172,36 +172,48 @@ private: const Cube& cube ); + /// Cube initialization + /// void init( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions + float x, ///< Cube location on X-axis + float y, ///< Cube location on Y-axis + float z, ///< Cube location on Z-axis + float s, ///< Cube size + unsigned char r, ///< Cube red color component + unsigned char g, ///< Cube green color component + unsigned char b, ///< Cube blue color component + unsigned char faceExclusions ///< Bitmask of faces of cube excluded from construction ); + /// Cube termination + /// void terminate(); + /// Initialize cube's vertex list + /// void initializeVertices( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions + float x, ///< Cube location on X-axis + float y, ///< Cube location on Y-axis + float z, ///< Cube location on Z-axis + float s, ///< Cube size + unsigned char r, ///< Cube red color component + unsigned char g, ///< Cube green color component + unsigned char b, ///< Cube blue color component + unsigned char faceExclusions ///< Bitmask of faces of cube excluded from construction ); + /// Terminate cube's vertex list + /// void terminateVertices(); + /// Initialize cube's triangle list + /// void initializeTris( unsigned char faceExclusions ); + /// Terminate cube's triangle list + /// void terminateTris(); // SPI virtual override methods go here @@ -219,11 +231,11 @@ private: unsigned long _cpuMemoryUsage; ///< Memory allocation of object - static const int _sNumFacesPerCube = 6; - static const int _sNumVerticesPerCube = 24; - static unsigned char _sFaceIndexToHalfSpaceMask[6]; - static float _sVertexIndexToConstructionVector[24][3]; - static float _sVertexIndexToNormalVector[6][3]; + static const int _sNumFacesPerCube = 6; ///< Number of faces per cube + static const int _sNumVerticesPerCube = 24; ///< Number of vertices per cube + static unsigned char _sFaceIndexToHalfSpaceMask[6]; ///< index to bitmask map + static float _sVertexIndexToConstructionVector[24][3]; ///< Vertex index to construction vector map + static float _sVertexIndexToNormalVector[6][3]; ///< Vertex index to normal vector map }; @@ -242,13 +254,13 @@ public: /// Add primitive to renderer database. /// int add( - Primitive* primitive ///< Pointer to primitive + Primitive* primitive ///< Primitive instance to be added ); /// Remove primitive from renderer database. /// void remove( - int id ///< Primitive id + int id ///< Primitive id to be removed ); /// Clear all primitives from renderer database @@ -278,7 +290,7 @@ private: /// Copy constructor prohibited. /// Renderer( - const Renderer& primitive + const Renderer& copy ); // SPI methods are defined here @@ -286,10 +298,10 @@ private: /// Add primitive to renderer database. /// Service implementer to provide private override for this method /// in derived class - /// @return primitive id + /// @return Primitive id /// virtual int vAdd( - Primitive* primitive ///< Pointer to primitive + Primitive* primitive ///< Primitive instance to be added ) = 0; /// Remove primitive from renderer database. @@ -297,7 +309,7 @@ private: /// in derived class /// virtual void vRemove( - int id ///< Primitive id + int id ///< Primitive id ) = 0; /// Clear all primitives from renderer database @@ -332,7 +344,7 @@ public: /// Configuration dependency injection constructor. /// PrimitiveRenderer( - int maxCount + int maxCount ///< Max count ); ~PrimitiveRenderer(); @@ -365,39 +377,39 @@ private: /// Construct the elements of the faces of the primitive. /// void constructElements( - Primitive* primitive + Primitive* primitive ///< Primitive instance ); /// Deconstruct the elements of the faces of the primitive. /// void deconstructElements( - Primitive* primitive + Primitive* primitive ///< Primitive instance ); /// Deconstruct the triangle element from the GL buffer. /// void deconstructTriElement( - int idx + int idx ///< Triangle element index ); /// Deconstruct the vertex element from the GL buffer. /// void deconstructVertexElement( - int idx + int idx ///< Vertex element index ); /// Transfer the vertex element to the GL buffer. /// void transferVertexElement( - int idx, - VertexElement *vertex + int idx, ///< Vertex element index + VertexElement *vertex ///< Vertex element instance ); /// Transfer the triangle element to the GL buffer. /// void transferTriElement( - int idx, - int tri[3] + int idx, ///< Triangle element index + int tri[3] ///< Triangle element data ); /// Get available primitive index. @@ -424,13 +436,13 @@ private: /// Add primitive to renderer database. /// int vAdd( - Primitive* primitive + Primitive* primitive ///< Primitive instance to be added ); /// Remove primitive from renderer database. /// void vRemove( - int id + int id ///< Primitive id to be removed ); /// Clear all primitives from renderer database @@ -451,7 +463,7 @@ private: private: - int _maxCount; + int _maxCount; ///< Maximum count of tris // GL related parameters @@ -479,8 +491,8 @@ private: // Statistics parameters, not necessary for proper operation - unsigned long _gpuMemoryUsage; - unsigned long _cpuMemoryUsage; + unsigned long _gpuMemoryUsage; ///< GPU memory used by this instance + unsigned long _cpuMemoryUsage; ///< CPU memory used by this instance static const int _sIndicesPerTri = 3; diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 8d59f33674..9a54a08619 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -938,6 +938,8 @@ void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, } void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { + static unsigned int lockForReadAttempt = 0; + static unsigned int lockForWriteAttempt = 0; PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "copyWrittenDataToReadArrays()"); @@ -946,7 +948,9 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { // time around, the only side effect is the VBOs won't be updated this frame const int WAIT_FOR_LOCK_IN_MS = 5; if (_readArraysLock.tryLockForWrite(WAIT_FOR_LOCK_IN_MS)) { + lockForWriteAttempt = 0; if (_writeArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { + lockForReadAttempt = 0; if (_voxelsDirty && _voxelsUpdated) { if (fullVBOs) { copyWrittenDataToReadArraysFullVBOs(); @@ -956,11 +960,19 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { } _writeArraysLock.unlock(); } else { - qDebug() << "couldn't get _writeArraysLock.LockForRead()..."; + lockForReadAttempt++; + // only report error of first failure + if (lockForReadAttempt == 1) { + qDebug() << "couldn't get _writeArraysLock.LockForRead()..."; + } } _readArraysLock.unlock(); } else { - qDebug() << "couldn't get _readArraysLock.LockForWrite()..."; + lockForWriteAttempt++; + // only report error of first failure + if (lockForWriteAttempt == 1) { + qDebug() << "couldn't get _readArraysLock.LockForWrite()..."; + } } } @@ -1683,11 +1695,12 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, //qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s); - // TODO: All of the exterior faces of this voxel element are - // occluders, which means that this element is completely - // occupied. Hence, the subtree from this node could be - // pruned and replaced by a leaf voxel, if the visible - // properties of the children are the same + // All of the exterior faces of this voxel element are + // occluders, which means that this element is completely + // occupied. Hence, the subtree from this node could be + // pruned and replaced by a leaf voxel, if the visible + // properties of the children are the same + } else if (exteriorOcclusions != OctreeElement::HalfSpace::None) { //const glm::vec3& v = voxel->getCorner(); //float s = voxel->getScale();