Merge branch 'master' of https://github.com/highfidelity/hifi into tuneAvatarInfo

This commit is contained in:
ZappoMan 2017-01-11 10:22:14 -08:00
commit 5b76eaaf52
18 changed files with 107 additions and 41 deletions

View file

@ -193,8 +193,9 @@ static QTimer pingTimer;
static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
// For processing on QThreadPool, target 2 less than the ideal number of threads, leaving // For processing on QThreadPool, we target a number of threads after reserving some
// 2 logical cores available for time sensitive tasks. // based on how many are being consumed by the application and the display plugin. However,
// we will never drop below the 'min' value
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2; static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SNAPSHOT_EXTENSION = ".jpg";
@ -3313,15 +3314,15 @@ void Application::idle(float nsecsElapsed) {
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop); connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
} }
PROFILE_COUNTER(app, "fps", { { "fps", _frameCounter.rate() } }); auto displayPlugin = getActiveDisplayPlugin();
PROFILE_COUNTER(app, "downloads", { if (displayPlugin) {
{ "current", ResourceCache::getLoadingRequests().length() }, PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate());
{ "pending", ResourceCache::getPendingRequestCount() } }
}); PROFILE_COUNTER_IF_CHANGED(app, "fps", float, _frameCounter.rate());
PROFILE_COUNTER(app, "processing", { PROFILE_COUNTER_IF_CHANGED(app, "currentDownloads", int, ResourceCache::getLoadingRequests().length());
{ "current", DependencyManager::get<StatTracker>()->getStat("Processing") }, PROFILE_COUNTER_IF_CHANGED(app, "pendingDownloads", int, ResourceCache::getPendingRequestCount());
{ "pending", DependencyManager::get<StatTracker>()->getStat("PendingProcessing") } PROFILE_COUNTER_IF_CHANGED(app, "currentProcessing", int, DependencyManager::get<StatTracker>()->getStat("Processing").toInt());
}); PROFILE_COUNTER_IF_CHANGED(app, "pendingProcessing", int, DependencyManager::get<StatTracker>()->getStat("PendingProcessing").toInt());
PROFILE_RANGE(app, __FUNCTION__); PROFILE_RANGE(app, __FUNCTION__);

View file

@ -18,6 +18,8 @@
#include "Application.h" #include "Application.h"
Q_LOGGING_CATEGORY(trace_test, "trace.test")
TestScriptingInterface* TestScriptingInterface::getInstance() { TestScriptingInterface* TestScriptingInterface::getInstance() {
static TestScriptingInterface sharedInstance; static TestScriptingInterface sharedInstance;
return &sharedInstance; return &sharedInstance;
@ -125,3 +127,10 @@ bool TestScriptingInterface::waitForCondition(qint64 maxWaitMs, std::function<bo
return condition(); return condition();
} }
void TestScriptingInterface::startTraceEvent(QString name) {
tracing::traceEvent(trace_test(), name, tracing::DurationBegin, "");
}
void TestScriptingInterface::endTraceEvent(QString name) {
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
}

View file

@ -65,6 +65,11 @@ public slots:
*/ */
bool stopTracing(QString filename); bool stopTracing(QString filename);
void startTraceEvent(QString name);
void endTraceEvent(QString name);
private: private:
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition); bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
}; };

View file

@ -902,7 +902,7 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh
void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xffff00ff, 0); PROFILE_RANGE_EX(simulation_animation_detail, __FUNCTION__, 0xffff00ff, 0);
PerformanceTimer perfTimer("updateAnimations"); PerformanceTimer perfTimer("updateAnimations");
setModelOffset(rootTransform); setModelOffset(rootTransform);

View file

@ -392,8 +392,8 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame
// linear interpolation with gain // linear interpolation with gain
static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) {
__m128 f0 = _mm_set1_ps(HRTF_GAIN * gain * (1.0f - frac)); __m128 f0 = _mm_set1_ps(gain * (1.0f - frac));
__m128 f1 = _mm_set1_ps(HRTF_GAIN * gain * frac); __m128 f1 = _mm_set1_ps(gain * frac);
assert(HRTF_TAPS % 4 == 0); assert(HRTF_TAPS % 4 == 0);
@ -861,6 +861,9 @@ void AudioHRTF::render(int16_t* input, float* output, int index, float azimuth,
ALIGN32 float bqBuffer[4 * HRTF_BLOCK]; // 4-channel (interleaved) ALIGN32 float bqBuffer[4 * HRTF_BLOCK]; // 4-channel (interleaved)
int delay[4]; // 4-channel (interleaved) int delay[4]; // 4-channel (interleaved)
// apply global and local gain adjustment
gain *= _gainAdjust;
// to avoid polluting the cache, old filters are recomputed instead of stored // to avoid polluting the cache, old filters are recomputed instead of stored
setFilters(firCoef, bqCoef, delay, index, _azimuthState, _distanceState, _gainState, L0); setFilters(firCoef, bqCoef, delay, index, _azimuthState, _distanceState, _gainState, L0);

View file

@ -44,6 +44,11 @@ public:
// //
void renderSilent(int16_t* input, float* output, int index, float azimuth, float distance, float gain, int numFrames); void renderSilent(int16_t* input, float* output, int index, float azimuth, float distance, float gain, int numFrames);
//
// HRTF local gain adjustment
//
void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; };
private: private:
AudioHRTF(const AudioHRTF&) = delete; AudioHRTF(const AudioHRTF&) = delete;
AudioHRTF& operator=(const AudioHRTF&) = delete; AudioHRTF& operator=(const AudioHRTF&) = delete;
@ -73,6 +78,9 @@ private:
float _distanceState = 0.0f; float _distanceState = 0.0f;
float _gainState = 0.0f; float _gainState = 0.0f;
// global and local gain adjustment
float _gainAdjust = HRTF_GAIN;
bool _silentState = false; bool _silentState = false;
}; };

View file

@ -561,22 +561,22 @@ void OpenGLDisplayPlugin::compositeLayers() {
updateCompositeFramebuffer(); updateCompositeFramebuffer();
{ {
PROFILE_RANGE_EX(render, "compositeScene", 0xff0077ff, (uint64_t)presentCount()) PROFILE_RANGE_EX(render_detail, "compositeScene", 0xff0077ff, (uint64_t)presentCount())
compositeScene(); compositeScene();
} }
{ {
PROFILE_RANGE_EX(render, "compositeOverlay", 0xff0077ff, (uint64_t)presentCount()) PROFILE_RANGE_EX(render_detail, "compositeOverlay", 0xff0077ff, (uint64_t)presentCount())
compositeOverlay(); compositeOverlay();
} }
auto compositorHelper = DependencyManager::get<CompositorHelper>(); auto compositorHelper = DependencyManager::get<CompositorHelper>();
if (compositorHelper->getReticleVisible()) { if (compositorHelper->getReticleVisible()) {
PROFILE_RANGE_EX(render, "compositePointer", 0xff0077ff, (uint64_t)presentCount()) PROFILE_RANGE_EX(render_detail, "compositePointer", 0xff0077ff, (uint64_t)presentCount())
compositePointer(); compositePointer();
} }
{ {
PROFILE_RANGE_EX(render, "compositeExtra", 0xff0077ff, (uint64_t)presentCount()) PROFILE_RANGE_EX(render_detail, "compositeExtra", 0xff0077ff, (uint64_t)presentCount())
compositeExtra(); compositeExtra();
} }
} }

View file

@ -211,7 +211,7 @@ namespace render {
template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) { template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) {
if (args) { if (args) {
if (payload && payload->entity) { if (payload && payload->entity) {
PROFILE_RANGE(render, "MetaModelRender"); PROFILE_RANGE(render_detail, "MetaModelRender");
payload->entity->render(args); payload->entity->render(args);
} }
} }

View file

@ -200,7 +200,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
_inRenderTransferPass = true; _inRenderTransferPass = true;
{ // Sync all the buffers { // Sync all the buffers
PROFILE_RANGE(render_gpu_gl, "syncGPUBuffer"); PROFILE_RANGE(render_gpu_gl_detail, "syncGPUBuffer");
for (auto& cached : batch._buffers._items) { for (auto& cached : batch._buffers._items) {
if (cached._data) { if (cached._data) {
@ -210,7 +210,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
} }
{ // Sync all the buffers { // Sync all the buffers
PROFILE_RANGE(render_gpu_gl, "syncCPUTransform"); PROFILE_RANGE(render_gpu_gl_detail, "syncCPUTransform");
_transform._cameras.clear(); _transform._cameras.clear();
_transform._cameraOffsets.clear(); _transform._cameraOffsets.clear();
@ -242,7 +242,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) {
} }
{ // Sync the transform buffers { // Sync the transform buffers
PROFILE_RANGE(render_gpu_gl, "syncGPUTransform"); PROFILE_RANGE(render_gpu_gl_detail, "syncGPUTransform");
transferTransformState(batch); transferTransformState(batch);
} }
@ -304,7 +304,7 @@ void GLBackend::render(const Batch& batch) {
} }
{ {
PROFILE_RANGE(render_gpu_gl, "Transfer"); PROFILE_RANGE(render_gpu_gl_detail, "Transfer");
renderPassTransfer(batch); renderPassTransfer(batch);
} }
@ -314,7 +314,7 @@ void GLBackend::render(const Batch& batch) {
} }
#endif #endif
{ {
PROFILE_RANGE(render_gpu_gl, _stereo._enable ? "Render Stereo" : "Render"); PROFILE_RANGE(render_gpu_gl_detail, _stereo._enable ? "Render Stereo" : "Render");
renderPassDraw(batch); renderPassDraw(batch);
} }
#ifdef GPU_STEREO_DRAWCALL_INSTANCED #ifdef GPU_STEREO_DRAWCALL_INSTANCED
@ -387,18 +387,22 @@ void GLBackend::resetStages() {
void GLBackend::do_pushProfileRange(const Batch& batch, size_t paramOffset) { void GLBackend::do_pushProfileRange(const Batch& batch, size_t paramOffset) {
auto name = batch._profileRanges.get(batch._params[paramOffset]._uint); if (trace_render_gpu_gl_detail().isDebugEnabled()) {
profileRanges.push_back(name); auto name = batch._profileRanges.get(batch._params[paramOffset]._uint);
profileRanges.push_back(name);
#if defined(NSIGHT_FOUND) #if defined(NSIGHT_FOUND)
nvtxRangePush(name.c_str()); nvtxRangePush(name.c_str());
#endif #endif
}
} }
void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) { void GLBackend::do_popProfileRange(const Batch& batch, size_t paramOffset) {
profileRanges.pop_back(); if (trace_render_gpu_gl_detail().isDebugEnabled()) {
profileRanges.pop_back();
#if defined(NSIGHT_FOUND) #if defined(NSIGHT_FOUND)
nvtxRangePop(); nvtxRangePop();
#endif #endif
}
} }
// TODO: As long as we have gl calls explicitely issued from interface // TODO: As long as we have gl calls explicitely issued from interface

View file

@ -28,7 +28,7 @@ void GLBackend::do_beginQuery(const Batch& batch, size_t paramOffset) {
auto query = batch._queries.get(batch._params[paramOffset]._uint); auto query = batch._queries.get(batch._params[paramOffset]._uint);
GLQuery* glquery = syncGPUObject(*query); GLQuery* glquery = syncGPUObject(*query);
if (glquery) { if (glquery) {
PROFILE_RANGE_BEGIN(render_gpu_gl, glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00); PROFILE_RANGE_BEGIN(render_gpu_gl_detail, glquery->_profileRangeId, query->getName().c_str(), 0xFFFF7F00);
++_queryStage._rangeQueryDepth; ++_queryStage._rangeQueryDepth;
glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime); glGetInteger64v(GL_TIMESTAMP, (GLint64*)&glquery->_batchElapsedTime);
@ -62,7 +62,7 @@ void GLBackend::do_endQuery(const Batch& batch, size_t paramOffset) {
glGetInteger64v(GL_TIMESTAMP, &now); glGetInteger64v(GL_TIMESTAMP, &now);
glquery->_batchElapsedTime = now - glquery->_batchElapsedTime; glquery->_batchElapsedTime = now - glquery->_batchElapsedTime;
PROFILE_RANGE_END(render_gpu_gl, glquery->_profileRangeId); PROFILE_RANGE_END(render_gpu_gl_detail, glquery->_profileRangeId);
(void)CHECK_GL_ERROR(); (void)CHECK_GL_ERROR();
} }

View file

@ -17,6 +17,7 @@
Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl") Q_LOGGING_CATEGORY(gpugllogging, "hifi.gpu.gl")
Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl") Q_LOGGING_CATEGORY(trace_render_gpu_gl, "trace.render.gpu.gl")
Q_LOGGING_CATEGORY(trace_render_gpu_gl_detail, "trace.render.gpu.gl.detail")
namespace gpu { namespace gl { namespace gpu { namespace gl {

View file

@ -16,6 +16,7 @@
Q_DECLARE_LOGGING_CATEGORY(gpugllogging) Q_DECLARE_LOGGING_CATEGORY(gpugllogging)
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl) Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl)
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl_detail)
namespace gpu { namespace gl { namespace gpu { namespace gl {

View file

@ -81,6 +81,7 @@ FramePointer Context::endFrame() {
} }
void Context::executeBatch(Batch& batch) const { void Context::executeBatch(Batch& batch) const {
PROFILE_RANGE(render_gpu, __FUNCTION__);
batch.flush(); batch.flush();
_backend->render(batch); _backend->render(batch);
} }
@ -94,6 +95,8 @@ void Context::consumeFrameUpdates(const FramePointer& frame) const {
} }
void Context::executeFrame(const FramePointer& frame) const { void Context::executeFrame(const FramePointer& frame) const {
PROFILE_RANGE(render_gpu, __FUNCTION__);
// Grab the stats at the around the frame and delta to have a consistent sampling // Grab the stats at the around the frame and delta to have a consistent sampling
ContextStats beginStats; ContextStats beginStats;
getStats(beginStats); getStats(beginStats);

View file

@ -283,7 +283,7 @@ void Model::reset() {
} }
bool Model::updateGeometry() { bool Model::updateGeometry() {
PROFILE_RANGE(render, __FUNCTION__); PROFILE_RANGE(render_detail, __FUNCTION__);
PerformanceTimer perfTimer("Model::updateGeometry"); PerformanceTimer perfTimer("Model::updateGeometry");
bool needFullUpdate = false; bool needFullUpdate = false;
@ -1114,7 +1114,7 @@ void Model::snapToRegistrationPoint() {
} }
void Model::simulate(float deltaTime, bool fullUpdate) { void Model::simulate(float deltaTime, bool fullUpdate) {
PROFILE_RANGE(simulation, __FUNCTION__); PROFILE_RANGE(simulation_detail, __FUNCTION__);
PerformanceTimer perfTimer("Model::simulate"); PerformanceTimer perfTimer("Model::simulate");
fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit)
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint); || (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);

View file

@ -9,16 +9,21 @@
#include "Profile.h" #include "Profile.h"
Q_LOGGING_CATEGORY(trace_app, "trace.app") Q_LOGGING_CATEGORY(trace_app, "trace.app")
Q_LOGGING_CATEGORY(trace_app_detail, "trace.app.detail")
Q_LOGGING_CATEGORY(trace_network, "trace.network") Q_LOGGING_CATEGORY(trace_network, "trace.network")
Q_LOGGING_CATEGORY(trace_parse, "trace.parse") Q_LOGGING_CATEGORY(trace_parse, "trace.parse")
Q_LOGGING_CATEGORY(trace_render, "trace.render") Q_LOGGING_CATEGORY(trace_render, "trace.render")
Q_LOGGING_CATEGORY(trace_render_detail, "trace.render.detail")
Q_LOGGING_CATEGORY(trace_render_gpu, "trace.render.gpu") Q_LOGGING_CATEGORY(trace_render_gpu, "trace.render.gpu")
Q_LOGGING_CATEGORY(trace_resource, "trace.resource") Q_LOGGING_CATEGORY(trace_resource, "trace.resource")
Q_LOGGING_CATEGORY(trace_resource_network, "trace.resource.network") Q_LOGGING_CATEGORY(trace_resource_network, "trace.resource.network")
Q_LOGGING_CATEGORY(trace_resource_parse, "trace.resource.parse") Q_LOGGING_CATEGORY(trace_resource_parse, "trace.resource.parse")
Q_LOGGING_CATEGORY(trace_simulation, "trace.simulation") Q_LOGGING_CATEGORY(trace_simulation, "trace.simulation")
Q_LOGGING_CATEGORY(trace_simulation_detail, "trace.simulation.detail")
Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation") Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation")
Q_LOGGING_CATEGORY(trace_simulation_animation_detail, "trace.simulation.animation.detail")
Q_LOGGING_CATEGORY(trace_simulation_physics, "trace.simulation.physics") Q_LOGGING_CATEGORY(trace_simulation_physics, "trace.simulation.physics")
Q_LOGGING_CATEGORY(trace_simulation_physics_detail, "trace.simulation.physics.detail")
#if defined(NSIGHT_FOUND) #if defined(NSIGHT_FOUND)
#include "nvToolsExt.h" #include "nvToolsExt.h"

View file

@ -13,16 +13,22 @@
#include "Trace.h" #include "Trace.h"
#include "SharedUtil.h" #include "SharedUtil.h"
// When profiling something that may happen many times per frame, use a xxx_detail category so that they may easily be filtered out of trace results
Q_DECLARE_LOGGING_CATEGORY(trace_app) Q_DECLARE_LOGGING_CATEGORY(trace_app)
Q_DECLARE_LOGGING_CATEGORY(trace_app_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_network) Q_DECLARE_LOGGING_CATEGORY(trace_network)
Q_DECLARE_LOGGING_CATEGORY(trace_render) Q_DECLARE_LOGGING_CATEGORY(trace_render)
Q_DECLARE_LOGGING_CATEGORY(trace_render_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu) Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu)
Q_DECLARE_LOGGING_CATEGORY(trace_resource) Q_DECLARE_LOGGING_CATEGORY(trace_resource)
Q_DECLARE_LOGGING_CATEGORY(trace_resource_parse) Q_DECLARE_LOGGING_CATEGORY(trace_resource_parse)
Q_DECLARE_LOGGING_CATEGORY(trace_resource_network) Q_DECLARE_LOGGING_CATEGORY(trace_resource_network)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation) Q_DECLARE_LOGGING_CATEGORY(trace_simulation)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation_detail)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics)
Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics_detail)
class Duration { class Duration {
public: public:
@ -69,6 +75,7 @@ inline void counter(const QLoggingCategory& category, const QString& name, const
#define PROFILE_RANGE_END(category, rangeId) Duration::endRange(trace_##category(), rangeId) #define PROFILE_RANGE_END(category, rangeId) Duration::endRange(trace_##category(), rangeId)
#define PROFILE_ASYNC_BEGIN(category, name, id, ...) asyncBegin(trace_##category(), name, id, ##__VA_ARGS__); #define PROFILE_ASYNC_BEGIN(category, name, id, ...) asyncBegin(trace_##category(), name, id, ##__VA_ARGS__);
#define PROFILE_ASYNC_END(category, name, id, ...) asyncEnd(trace_##category(), name, id, ##__VA_ARGS__); #define PROFILE_ASYNC_END(category, name, id, ...) asyncEnd(trace_##category(), name, id, ##__VA_ARGS__);
#define PROFILE_COUNTER_IF_CHANGED(category, name, type, value) { static type lastValue = 0; type newValue = value; if (newValue != lastValue) { counter(trace_##category(), name, { { name, newValue }}); lastValue = newValue; } }
#define PROFILE_COUNTER(category, name, ...) counter(trace_##category(), name, ##__VA_ARGS__); #define PROFILE_COUNTER(category, name, ...) counter(trace_##category(), name, ##__VA_ARGS__);
#define PROFILE_INSTANT(category, name, ...) instant(trace_##category(), name, ##__VA_ARGS__); #define PROFILE_INSTANT(category, name, ...) instant(trace_##category(), name, ##__VA_ARGS__);

View file

@ -16,6 +16,7 @@
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QtCore/QDateTime>
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
@ -107,6 +108,12 @@ void Tracer::serialize(const QString& originalPath) {
QString path = originalPath; QString path = originalPath;
// Filter for specific tokens potentially present in the path:
auto now = QDateTime::currentDateTime();
path = path.replace("{DATE}", now.date().toString("yyyyMMdd"));
path = path.replace("{TIME}", now.time().toString("HHmm"));
// If the filename is relative, turn it into an absolute path relative to the document directory. // If the filename is relative, turn it into an absolute path relative to the document directory.
QFileInfo originalFileInfo(path); QFileInfo originalFileInfo(path);
if (originalFileInfo.isRelative()) { if (originalFileInfo.isRelative()) {

View file

@ -58,8 +58,13 @@ ExtendedOverlay.prototype.editOverlay = function (properties) { // change displa
Overlays.editOverlay(this.activeOverlay, properties); Overlays.editOverlay(this.activeOverlay, properties);
}; };
function color(selected) { function color(selected, level) {
return selected ? SELECTED_COLOR : UNSELECTED_COLOR; var base = selected ? SELECTED_COLOR : UNSELECTED_COLOR;
function scale(component) {
var delta = 0xFF - component;
return component + (delta * level);
}
return {red: scale(base.red), green: scale(base.green), blue: scale(base.blue)};
} }
function textures(selected) { function textures(selected) {
@ -71,7 +76,7 @@ ExtendedOverlay.prototype.select = function (selected) {
return; return;
} }
this.editOverlay({color: color(selected)}); this.editOverlay({color: color(selected, this.audioLevel)});
if (this.model) { if (this.model) {
this.model.editOverlay({textures: textures(selected)}); this.model.editOverlay({textures: textures(selected)});
} }
@ -204,7 +209,7 @@ function addAvatarNode(id) {
drawInFront: true, drawInFront: true,
solid: true, solid: true,
alpha: 0.8, alpha: 0.8,
color: color(selected), color: color(selected, 0.0),
ignoreRayIntersection: false}, selected, true); ignoreRayIntersection: false}, selected, true);
} }
function populateUserList() { function populateUserList() {
@ -288,6 +293,7 @@ function updateOverlays() {
overlay.ping = pingPong; overlay.ping = pingPong;
overlay.editOverlay({ overlay.editOverlay({
color: color(ExtendedOverlay.isSelected(id), overlay.audioLevel),
position: target, position: target,
dimensions: 0.032 * distance dimensions: 0.032 * distance
}); });
@ -422,7 +428,7 @@ var LOUDNESS_FLOOR = 11.0;
var LOUDNESS_SCALE = 2.8 / 5.0; var LOUDNESS_SCALE = 2.8 / 5.0;
var LOG2 = Math.log(2.0); var LOG2 = Math.log(2.0);
var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too) var AUDIO_LEVEL_UPDATE_INTERVAL_MS = 100; // 10hz for now (change this and change the AVERAGING_RATIO too)
var accumulatedLevels = {}; var myData = {}; // we're not includied in ExtendedOverlay.get.
function getAudioLevel(id) { function getAudioLevel(id) {
// the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged
@ -430,13 +436,18 @@ function getAudioLevel(id) {
// of updating (the latter for efficiency too). // of updating (the latter for efficiency too).
var avatar = AvatarList.getAvatar(id); var avatar = AvatarList.getAvatar(id);
var audioLevel = 0.0; var audioLevel = 0.0;
var data = id ? ExtendedOverlay.get(id) : myData;
if (!data) {
print('no data for', id);
return audioLevel;
}
// we will do exponential moving average by taking some the last loudness and averaging // we will do exponential moving average by taking some the last loudness and averaging
accumulatedLevels[id] = AVERAGING_RATIO * (accumulatedLevels[id] || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness); data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness);
// add 1 to insure we don't go log() and hit -infinity. Math.log is // add 1 to insure we don't go log() and hit -infinity. Math.log is
// natural log, so to get log base 2, just divide by ln(2). // natural log, so to get log base 2, just divide by ln(2).
var logLevel = Math.log(accumulatedLevels[id] + 1) / LOG2; var logLevel = Math.log(data.accumulatedLevel + 1) / LOG2;
if (logLevel <= LOUDNESS_FLOOR) { if (logLevel <= LOUDNESS_FLOOR) {
audioLevel = logLevel / LOUDNESS_FLOOR * LOUDNESS_SCALE; audioLevel = logLevel / LOUDNESS_FLOOR * LOUDNESS_SCALE;
@ -446,6 +457,7 @@ function getAudioLevel(id) {
if (audioLevel > 1.0) { if (audioLevel > 1.0) {
audioLevel = 1; audioLevel = 1;
} }
data.audioLevel = audioLevel;
return audioLevel; return audioLevel;
} }
@ -455,7 +467,7 @@ function getAudioLevel(id) {
Script.setInterval(function () { Script.setInterval(function () {
if (pal.visible) { if (pal.visible) {
var param = {}; var param = {};
AvatarList.getAvatarIdentifiers().sort().forEach(function (id) { AvatarList.getAvatarIdentifiers().forEach(function (id) {
var level = getAudioLevel(id); var level = getAudioLevel(id);
// qml didn't like an object with null/empty string for a key, so... // qml didn't like an object with null/empty string for a key, so...
var userId = id || 0; var userId = id || 0;