diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 9972adfda2..386d6e8a1d 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "AssignmentFactory.h" @@ -38,7 +39,6 @@ int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), - _shutdownEventListener(this), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), _localASPortSharedMem(NULL) { @@ -49,8 +49,12 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : setApplicationName("assignment-client"); QSettings::setDefaultFormat(QSettings::IniFormat); - installNativeEventFilter(&_shutdownEventListener); - connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us +#ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +#else + ShutdownEventListener::getInstance(); +#endif // set the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 566805d67f..053458f136 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -14,7 +14,6 @@ #include -#include "ShutdownEventListener.h" #include "ThreadedAssignment.h" class QSharedMemory; @@ -34,7 +33,6 @@ private slots: private: Assignment _requestAssignment; static SharedAssignmentPointer _currentAssignment; - ShutdownEventListener _shutdownEventListener; QString _assignmentServerHostname; HifiSockAddr _assignmentServerSocket; QSharedMemory* _localASPortSharedMem; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 358b963b4b..45e1f56d53 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -12,6 +12,7 @@ #include #include +#include #include "AssignmentClientMonitor.h" @@ -19,24 +20,19 @@ const char* NUM_FORKS_PARAMETER = "-n"; const QString ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME = "assignment-client-monitor"; -void signalHandler(int param){ - // get the qApp and cast it to an AssignmentClientMonitor - AssignmentClientMonitor* app = qobject_cast(qApp); - - // tell it to stop the child processes and then go down - app->stopChildProcesses(); - app->quit(); -} - AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) : QCoreApplication(argc, argv) -{ - // be a signal handler for SIGTERM so we can stop our children when we get it - signal(SIGTERM, signalHandler); - +{ // start the Logging class with the parent's target name LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME); + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us +#ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +#else + ShutdownEventListener::getInstance(); +#endif + _childArguments = arguments(); // remove the parameter for the number of forks so it isn't passed to the child forked processes @@ -52,6 +48,10 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int num } } +AssignmentClientMonitor::~AssignmentClientMonitor() { + stopChildProcesses(); +} + void AssignmentClientMonitor::stopChildProcesses() { QList >::Iterator it = _childProcesses.begin(); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 9dbfcc495a..9a7bca9cb3 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -24,6 +24,7 @@ class AssignmentClientMonitor : public QCoreApplication { Q_OBJECT public: AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks); + ~AssignmentClientMonitor(); void stopChildProcesses(); private slots: diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 75db0b8022..bf9505671b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "DomainServerNodeData.h" @@ -41,7 +42,6 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; DomainServer::DomainServer(int argc, char* argv[]) : QCoreApplication(argc, argv), - _shutdownEventListener(this), _httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this), _httpsManager(NULL), _allAssignments(), @@ -70,8 +70,12 @@ DomainServer::DomainServer(int argc, char* argv[]) : _settingsManager.setupConfigMap(arguments()); - installNativeEventFilter(&_shutdownEventListener); - connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); + // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us +#ifdef _WIN32 + installNativeEventFilter(&ShutdownEventListener::getInstance()); +#else + ShutdownEventListener::getInstance(); +#endif qRegisterMetaType("DomainServerWebSessionData"); qRegisterMetaTypeStreamOperators("DomainServerWebSessionData"); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 2a92c63923..76ab562f74 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -27,7 +27,6 @@ #include "DomainServerSettingsManager.h" #include "DomainServerWebSessionData.h" -#include "ShutdownEventListener.h" #include "WalletTransaction.h" #include "PendingAssignedNodeData.h" @@ -125,8 +124,6 @@ private: QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); - - ShutdownEventListener _shutdownEventListener; HTTPManager _httpManager; HTTPSManager* _httpsManager; diff --git a/examples/audioReflectorTools.js b/examples/audioReflectorTools.js deleted file mode 100644 index c5a88edd57..0000000000 --- a/examples/audioReflectorTools.js +++ /dev/null @@ -1,844 +0,0 @@ -// -// audioReflectorTools.js -// hifi -// -// Created by Brad Hefta-Gaub on 2/14/14. -// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. -// -// 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 -// - -Script.include("libraries/globals.js"); - -var delayScale = 100.0; -var fanoutScale = 10.0; -var speedScale = 20; -var factorScale = 5.0; -var localFactorScale = 1.0; -var reflectiveScale = 100.0; -var diffusionScale = 100.0; -var absorptionScale = 100.0; -var combFilterScale = 50.0; -var originalScale = 2.0; -var echoesScale = 2.0; - -// these three properties are bound together, if you change one, the others will also change -var reflectiveRatio = AudioReflector.getReflectiveRatio(); -var diffusionRatio = AudioReflector.getDiffusionRatio(); -var absorptionRatio = AudioReflector.getAbsorptionRatio(); - -var reflectiveThumbX; -var diffusionThumbX; -var absorptionThumbX; - -function setReflectiveRatio(reflective) { - var total = diffusionRatio + absorptionRatio + (reflective / reflectiveScale); - diffusionRatio = diffusionRatio / total; - absorptionRatio = absorptionRatio / total; - reflectiveRatio = (reflective / reflectiveScale) / total; - updateRatioValues(); -} - -function setDiffusionRatio(diffusion) { - var total = (diffusion / diffusionScale) + absorptionRatio + reflectiveRatio; - diffusionRatio = (diffusion / diffusionScale) / total; - absorptionRatio = absorptionRatio / total; - reflectiveRatio = reflectiveRatio / total; - updateRatioValues(); -} - -function setAbsorptionRatio(absorption) { - var total = diffusionRatio + (absorption / absorptionScale) + reflectiveRatio; - diffusionRatio = diffusionRatio / total; - absorptionRatio = (absorption / absorptionScale) / total; - reflectiveRatio = reflectiveRatio / total; - updateRatioValues(); -} - -function updateRatioSliders() { - reflectiveThumbX = reflectiveMinThumbX + ((reflectiveMaxThumbX - reflectiveMinThumbX) * reflectiveRatio); - diffusionThumbX = diffusionMinThumbX + ((diffusionMaxThumbX - diffusionMinThumbX) * diffusionRatio); - absorptionThumbX = absorptionMinThumbX + ((absorptionMaxThumbX - absorptionMinThumbX) * absorptionRatio); - - Overlays.editOverlay(reflectiveThumb, { x: reflectiveThumbX } ); - Overlays.editOverlay(diffusionThumb, { x: diffusionThumbX } ); - Overlays.editOverlay(absorptionThumb, { x: absorptionThumbX } ); -} - -function updateRatioValues() { - AudioReflector.setReflectiveRatio(reflectiveRatio); - AudioReflector.setDiffusionRatio(diffusionRatio); - AudioReflector.setAbsorptionRatio(absorptionRatio); -} - -var topY = 250; -var sliderHeight = 35; - -var delayY = topY; -topY += sliderHeight; -var delayLabel = Overlays.addOverlay("text", { - x: 40, - y: delayY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 12, - leftMargin: 5, - text: "Delay:" - }); - -var delaySlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: delayY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var delayMinThumbX = 110; -var delayMaxThumbX = delayMinThumbX + 110; -var delayThumbX = delayMinThumbX + ((delayMaxThumbX - delayMinThumbX) * (AudioReflector.getPreDelay() / delayScale)); -var delayThumb = Overlays.addOverlay("image", { - x: delayThumbX, - y: delayY + 9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 255, green: 0, blue: 0}, - alpha: 1 - }); - -var fanoutY = topY; -topY += sliderHeight; - -var fanoutLabel = Overlays.addOverlay("text", { - x: 40, - y: fanoutY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 12, - leftMargin: 5, - text: "Fanout:" - }); - -var fanoutSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: fanoutY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var fanoutMinThumbX = 110; -var fanoutMaxThumbX = fanoutMinThumbX + 110; -var fanoutThumbX = fanoutMinThumbX + ((fanoutMaxThumbX - fanoutMinThumbX) * (AudioReflector.getDiffusionFanout() / fanoutScale)); -var fanoutThumb = Overlays.addOverlay("image", { - x: fanoutThumbX, - y: fanoutY + 9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 255, green: 255, blue: 0}, - alpha: 1 - }); - - -var speedY = topY; -topY += sliderHeight; - -var speedLabel = Overlays.addOverlay("text", { - x: 40, - y: speedY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Speed\nin ms/m:" - }); - -var speedSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: speedY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var speedMinThumbX = 110; -var speedMaxThumbX = speedMinThumbX + 110; -var speedThumbX = speedMinThumbX + ((speedMaxThumbX - speedMinThumbX) * (AudioReflector.getSoundMsPerMeter() / speedScale)); -var speedThumb = Overlays.addOverlay("image", { - x: speedThumbX, - y: speedY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 0, green: 255, blue: 0}, - alpha: 1 - }); - -var factorY = topY; -topY += sliderHeight; - -var factorLabel = Overlays.addOverlay("text", { - x: 40, - y: factorY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Attenuation\nFactor:" - }); - - -var factorSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: factorY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var factorMinThumbX = 110; -var factorMaxThumbX = factorMinThumbX + 110; -var factorThumbX = factorMinThumbX + ((factorMaxThumbX - factorMinThumbX) * (AudioReflector.getDistanceAttenuationScalingFactor() / factorScale)); -var factorThumb = Overlays.addOverlay("image", { - x: factorThumbX, - y: factorY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 0, green: 0, blue: 255}, - alpha: 1 - }); - -var localFactorY = topY; -topY += sliderHeight; - -var localFactorLabel = Overlays.addOverlay("text", { - x: 40, - y: localFactorY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Local\nFactor:" - }); - - -var localFactorSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: localFactorY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var localFactorMinThumbX = 110; -var localFactorMaxThumbX = localFactorMinThumbX + 110; -var localFactorThumbX = localFactorMinThumbX + ((localFactorMaxThumbX - localFactorMinThumbX) * (AudioReflector.getLocalAudioAttenuationFactor() / localFactorScale)); -var localFactorThumb = Overlays.addOverlay("image", { - x: localFactorThumbX, - y: localFactorY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 0, green: 128, blue: 128}, - alpha: 1 - }); - -var combFilterY = topY; -topY += sliderHeight; - -var combFilterLabel = Overlays.addOverlay("text", { - x: 40, - y: combFilterY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Comb Filter\nWindow:" - }); - - -var combFilterSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: combFilterY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var combFilterMinThumbX = 110; -var combFilterMaxThumbX = combFilterMinThumbX + 110; -var combFilterThumbX = combFilterMinThumbX + ((combFilterMaxThumbX - combFilterMinThumbX) * (AudioReflector.getCombFilterWindow() / combFilterScale)); -var combFilterThumb = Overlays.addOverlay("image", { - x: combFilterThumbX, - y: combFilterY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 128, green: 128, blue: 0}, - alpha: 1 - }); - - -var reflectiveY = topY; -topY += sliderHeight; - -var reflectiveLabel = Overlays.addOverlay("text", { - x: 40, - y: reflectiveY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Reflective\nRatio:" - }); - - -var reflectiveSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: reflectiveY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var reflectiveMinThumbX = 110; -var reflectiveMaxThumbX = reflectiveMinThumbX + 110; -reflectiveThumbX = reflectiveMinThumbX + ((reflectiveMaxThumbX - reflectiveMinThumbX) * AudioReflector.getReflectiveRatio()); -var reflectiveThumb = Overlays.addOverlay("image", { - x: reflectiveThumbX, - y: reflectiveY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - -var diffusionY = topY; -topY += sliderHeight; - -var diffusionLabel = Overlays.addOverlay("text", { - x: 40, - y: diffusionY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Diffusion\nRatio:" - }); - - -var diffusionSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: diffusionY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var diffusionMinThumbX = 110; -var diffusionMaxThumbX = diffusionMinThumbX + 110; -diffusionThumbX = diffusionMinThumbX + ((diffusionMaxThumbX - diffusionMinThumbX) * AudioReflector.getDiffusionRatio()); -var diffusionThumb = Overlays.addOverlay("image", { - x: diffusionThumbX, - y: diffusionY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 0, green: 255, blue: 255}, - alpha: 1 - }); - -var absorptionY = topY; -topY += sliderHeight; - -var absorptionLabel = Overlays.addOverlay("text", { - x: 40, - y: absorptionY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Absorption\nRatio:" - }); - - -var absorptionSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: absorptionY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var absorptionMinThumbX = 110; -var absorptionMaxThumbX = absorptionMinThumbX + 110; -absorptionThumbX = absorptionMinThumbX + ((absorptionMaxThumbX - absorptionMinThumbX) * AudioReflector.getAbsorptionRatio()); -var absorptionThumb = Overlays.addOverlay("image", { - x: absorptionThumbX, - y: absorptionY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 255, green: 0, blue: 255}, - alpha: 1 - }); - -var originalY = topY; -topY += sliderHeight; - -var originalLabel = Overlays.addOverlay("text", { - x: 40, - y: originalY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Original\nMix:" - }); - - -var originalSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: originalY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var originalMinThumbX = 110; -var originalMaxThumbX = originalMinThumbX + 110; -var originalThumbX = originalMinThumbX + ((originalMaxThumbX - originalMinThumbX) * (AudioReflector.getOriginalSourceAttenuation() / originalScale)); -var originalThumb = Overlays.addOverlay("image", { - x: originalThumbX, - y: originalY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 128, green: 128, blue: 0}, - alpha: 1 - }); - -var echoesY = topY; -topY += sliderHeight; - -var echoesLabel = Overlays.addOverlay("text", { - x: 40, - y: echoesY, - width: 60, - height: sliderHeight, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 255, blue: 255}, - topMargin: 6, - leftMargin: 5, - text: "Echoes\nMix:" - }); - - -var echoesSlider = Overlays.addOverlay("image", { - // alternate form of expressing bounds - bounds: { x: 100, y: echoesY, width: 150, height: sliderHeight}, - subImage: { x: 46, y: 0, width: 200, height: 71 }, - imageURL: HIFI_PUBLIC_BUCKET + "images/slider.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); - - -var echoesMinThumbX = 110; -var echoesMaxThumbX = echoesMinThumbX + 110; -var echoesThumbX = echoesMinThumbX + ((echoesMaxThumbX - echoesMinThumbX) * (AudioReflector.getEchoesAttenuation() / echoesScale)); -var echoesThumb = Overlays.addOverlay("image", { - x: echoesThumbX, - y: echoesY+9, - width: 18, - height: 17, - imageURL: HIFI_PUBLIC_BUCKET + "images/thumb.png", - color: { red: 128, green: 128, blue: 0}, - alpha: 1 - }); - - -// When our script shuts down, we should clean up all of our overlays -function scriptEnding() { - Overlays.deleteOverlay(factorLabel); - Overlays.deleteOverlay(factorThumb); - Overlays.deleteOverlay(factorSlider); - - Overlays.deleteOverlay(combFilterLabel); - Overlays.deleteOverlay(combFilterThumb); - Overlays.deleteOverlay(combFilterSlider); - - Overlays.deleteOverlay(localFactorLabel); - Overlays.deleteOverlay(localFactorThumb); - Overlays.deleteOverlay(localFactorSlider); - - Overlays.deleteOverlay(speedLabel); - Overlays.deleteOverlay(speedThumb); - Overlays.deleteOverlay(speedSlider); - - Overlays.deleteOverlay(delayLabel); - Overlays.deleteOverlay(delayThumb); - Overlays.deleteOverlay(delaySlider); - - Overlays.deleteOverlay(fanoutLabel); - Overlays.deleteOverlay(fanoutThumb); - Overlays.deleteOverlay(fanoutSlider); - - Overlays.deleteOverlay(reflectiveLabel); - Overlays.deleteOverlay(reflectiveThumb); - Overlays.deleteOverlay(reflectiveSlider); - - Overlays.deleteOverlay(diffusionLabel); - Overlays.deleteOverlay(diffusionThumb); - Overlays.deleteOverlay(diffusionSlider); - - Overlays.deleteOverlay(absorptionLabel); - Overlays.deleteOverlay(absorptionThumb); - Overlays.deleteOverlay(absorptionSlider); - - Overlays.deleteOverlay(echoesLabel); - Overlays.deleteOverlay(echoesThumb); - Overlays.deleteOverlay(echoesSlider); - - Overlays.deleteOverlay(originalLabel); - Overlays.deleteOverlay(originalThumb); - Overlays.deleteOverlay(originalSlider); - -} -Script.scriptEnding.connect(scriptEnding); - - -var count = 0; - -// Our update() function is called at approximately 60fps, and we will use it to animate our various overlays -function update(deltaTime) { - count++; -} -Script.update.connect(update); - - -// The slider is handled in the mouse event callbacks. -var movingSliderDelay = false; -var movingSliderFanout = false; -var movingSliderSpeed = false; -var movingSliderFactor = false; -var movingSliderCombFilter = false; -var movingSliderLocalFactor = false; -var movingSliderReflective = false; -var movingSliderDiffusion = false; -var movingSliderAbsorption = false; -var movingSliderOriginal = false; -var movingSliderEchoes = false; - -var thumbClickOffsetX = 0; -function mouseMoveEvent(event) { - if (movingSliderDelay) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < delayMinThumbX) { - newThumbX = delayMinThumbX; - } - if (newThumbX > delayMaxThumbX) { - newThumbX = delayMaxThumbX; - } - Overlays.editOverlay(delayThumb, { x: newThumbX } ); - var delay = ((newThumbX - delayMinThumbX) / (delayMaxThumbX - delayMinThumbX)) * delayScale; - AudioReflector.setPreDelay(delay); - } - if (movingSliderFanout) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < fanoutMinThumbX) { - newThumbX = fanoutMinThumbX; - } - if (newThumbX > fanoutMaxThumbX) { - newThumbX = fanoutMaxThumbX; - } - Overlays.editOverlay(fanoutThumb, { x: newThumbX } ); - var fanout = Math.round(((newThumbX - fanoutMinThumbX) / (fanoutMaxThumbX - fanoutMinThumbX)) * fanoutScale); - AudioReflector.setDiffusionFanout(fanout); - } - if (movingSliderSpeed) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < speedMinThumbX) { - newThumbX = speedMminThumbX; - } - if (newThumbX > speedMaxThumbX) { - newThumbX = speedMaxThumbX; - } - Overlays.editOverlay(speedThumb, { x: newThumbX } ); - var speed = ((newThumbX - speedMinThumbX) / (speedMaxThumbX - speedMinThumbX)) * speedScale; - AudioReflector.setSoundMsPerMeter(speed); - } - if (movingSliderFactor) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < factorMinThumbX) { - newThumbX = factorMminThumbX; - } - if (newThumbX > factorMaxThumbX) { - newThumbX = factorMaxThumbX; - } - Overlays.editOverlay(factorThumb, { x: newThumbX } ); - var factor = ((newThumbX - factorMinThumbX) / (factorMaxThumbX - factorMinThumbX)) * factorScale; - AudioReflector.setDistanceAttenuationScalingFactor(factor); - } - if (movingSliderCombFilter) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < combFilterMinThumbX) { - newThumbX = combFilterMminThumbX; - } - if (newThumbX > combFilterMaxThumbX) { - newThumbX = combFilterMaxThumbX; - } - Overlays.editOverlay(combFilterThumb, { x: newThumbX } ); - var combFilter = ((newThumbX - combFilterMinThumbX) / (combFilterMaxThumbX - combFilterMinThumbX)) * combFilterScale; - AudioReflector.setCombFilterWindow(combFilter); - } - if (movingSliderLocalFactor) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < localFactorMinThumbX) { - newThumbX = localFactorMminThumbX; - } - if (newThumbX > localFactorMaxThumbX) { - newThumbX = localFactorMaxThumbX; - } - Overlays.editOverlay(localFactorThumb, { x: newThumbX } ); - var localFactor = ((newThumbX - localFactorMinThumbX) / (localFactorMaxThumbX - localFactorMinThumbX)) * localFactorScale; - AudioReflector.setLocalAudioAttenuationFactor(localFactor); - } - - if (movingSliderAbsorption) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < absorptionMinThumbX) { - newThumbX = absorptionMminThumbX; - } - if (newThumbX > absorptionMaxThumbX) { - newThumbX = absorptionMaxThumbX; - } - Overlays.editOverlay(absorptionThumb, { x: newThumbX } ); - var absorption = ((newThumbX - absorptionMinThumbX) / (absorptionMaxThumbX - absorptionMinThumbX)) * absorptionScale; - setAbsorptionRatio(absorption); - } - - if (movingSliderReflective) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < reflectiveMinThumbX) { - newThumbX = reflectiveMminThumbX; - } - if (newThumbX > reflectiveMaxThumbX) { - newThumbX = reflectiveMaxThumbX; - } - Overlays.editOverlay(reflectiveThumb, { x: newThumbX } ); - var reflective = ((newThumbX - reflectiveMinThumbX) / (reflectiveMaxThumbX - reflectiveMinThumbX)) * reflectiveScale; - setReflectiveRatio(reflective); - } - - if (movingSliderDiffusion) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < diffusionMinThumbX) { - newThumbX = diffusionMminThumbX; - } - if (newThumbX > diffusionMaxThumbX) { - newThumbX = diffusionMaxThumbX; - } - Overlays.editOverlay(diffusionThumb, { x: newThumbX } ); - var diffusion = ((newThumbX - diffusionMinThumbX) / (diffusionMaxThumbX - diffusionMinThumbX)) * diffusionScale; - setDiffusionRatio(diffusion); - } - if (movingSliderEchoes) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < echoesMinThumbX) { - newThumbX = echoesMminThumbX; - } - if (newThumbX > echoesMaxThumbX) { - newThumbX = echoesMaxThumbX; - } - Overlays.editOverlay(echoesThumb, { x: newThumbX } ); - var echoes = ((newThumbX - echoesMinThumbX) / (echoesMaxThumbX - echoesMinThumbX)) * echoesScale; - AudioReflector.setEchoesAttenuation(echoes); - } - if (movingSliderOriginal) { - newThumbX = event.x - thumbClickOffsetX; - if (newThumbX < originalMinThumbX) { - newThumbX = originalMminThumbX; - } - if (newThumbX > originalMaxThumbX) { - newThumbX = originalMaxThumbX; - } - Overlays.editOverlay(originalThumb, { x: newThumbX } ); - var original = ((newThumbX - originalMinThumbX) / (originalMaxThumbX - originalMinThumbX)) * originalScale; - AudioReflector.setOriginalSourceAttenuation(original); - } - -} - -// we also handle click detection in our mousePressEvent() -function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - if (clickedOverlay == delayThumb) { - movingSliderDelay = true; - thumbClickOffsetX = event.x - delayThumbX; - } - if (clickedOverlay == fanoutThumb) { - movingSliderFanout = true; - thumbClickOffsetX = event.x - fanoutThumbX; - } - if (clickedOverlay == speedThumb) { - movingSliderSpeed = true; - thumbClickOffsetX = event.x - speedThumbX; - } - if (clickedOverlay == factorThumb) { - movingSliderFactor = true; - thumbClickOffsetX = event.x - factorThumbX; - } - if (clickedOverlay == localFactorThumb) { - movingSliderLocalFactor = true; - thumbClickOffsetX = event.x - localFactorThumbX; - } - if (clickedOverlay == combFilterThumb) { - movingSliderCombFilter = true; - thumbClickOffsetX = event.x - combFilterThumbX; - } - if (clickedOverlay == diffusionThumb) { - movingSliderDiffusion = true; - thumbClickOffsetX = event.x - diffusionThumbX; - } - if (clickedOverlay == absorptionThumb) { - movingSliderAbsorption = true; - thumbClickOffsetX = event.x - absorptionThumbX; - } - if (clickedOverlay == reflectiveThumb) { - movingSliderReflective = true; - thumbClickOffsetX = event.x - reflectiveThumbX; - } - if (clickedOverlay == originalThumb) { - movingSliderOriginal = true; - thumbClickOffsetX = event.x - originalThumbX; - } - if (clickedOverlay == echoesThumb) { - movingSliderEchoes = true; - thumbClickOffsetX = event.x - echoesThumbX; - } -} - -function mouseReleaseEvent(event) { - if (movingSliderDelay) { - movingSliderDelay = false; - var delay = ((newThumbX - delayMinThumbX) / (delayMaxThumbX - delayMinThumbX)) * delayScale; - AudioReflector.setPreDelay(delay); - delayThumbX = newThumbX; - } - if (movingSliderFanout) { - movingSliderFanout = false; - var fanout = Math.round(((newThumbX - fanoutMinThumbX) / (fanoutMaxThumbX - fanoutMinThumbX)) * fanoutScale); - AudioReflector.setDiffusionFanout(fanout); - fanoutThumbX = newThumbX; - } - if (movingSliderSpeed) { - movingSliderSpeed = false; - var speed = ((newThumbX - speedMinThumbX) / (speedMaxThumbX - speedMinThumbX)) * speedScale; - AudioReflector.setSoundMsPerMeter(speed); - speedThumbX = newThumbX; - } - if (movingSliderFactor) { - movingSliderFactor = false; - var factor = ((newThumbX - factorMinThumbX) / (factorMaxThumbX - factorMinThumbX)) * factorScale; - AudioReflector.setDistanceAttenuationScalingFactor(factor); - factorThumbX = newThumbX; - } - if (movingSliderCombFilter) { - movingSliderCombFilter = false; - var combFilter = ((newThumbX - combFilterMinThumbX) / (combFilterMaxThumbX - combFilterMinThumbX)) * combFilterScale; - AudioReflector.setCombFilterWindow(combFilter); - combFilterThumbX = newThumbX; - } - if (movingSliderLocalFactor) { - movingSliderLocalFactor = false; - var localFactor = ((newThumbX - localFactorMinThumbX) / (localFactorMaxThumbX - localFactorMinThumbX)) * localFactorScale; - AudioReflector.setLocalAudioAttenuationFactor(localFactor); - localFactorThumbX = newThumbX; - } - if (movingSliderReflective) { - movingSliderReflective = false; - var reflective = ((newThumbX - reflectiveMinThumbX) / (reflectiveMaxThumbX - reflectiveMinThumbX)) * reflectiveScale; - setReflectiveRatio(reflective); - reflectiveThumbX = newThumbX; - updateRatioSliders(); - } - if (movingSliderDiffusion) { - movingSliderDiffusion = false; - var diffusion = ((newThumbX - diffusionMinThumbX) / (diffusionMaxThumbX - diffusionMinThumbX)) * diffusionScale; - setDiffusionRatio(diffusion); - diffusionThumbX = newThumbX; - updateRatioSliders(); - } - if (movingSliderAbsorption) { - movingSliderAbsorption = false; - var absorption = ((newThumbX - absorptionMinThumbX) / (absorptionMaxThumbX - absorptionMinThumbX)) * absorptionScale; - setAbsorptionRatio(absorption); - absorptionThumbX = newThumbX; - updateRatioSliders(); - } - if (movingSliderEchoes) { - movingSliderEchoes = false; - var echoes = ((newThumbX - echoesMinThumbX) / (echoesMaxThumbX - echoesMinThumbX)) * echoesScale; - AudioReflector.setEchoesAttenuation(echoes); - echoesThumbX = newThumbX; - } - if (movingSliderOriginal) { - movingSliderOriginal = false; - var original = ((newThumbX - originalMinThumbX) / (originalMaxThumbX - originalMinThumbX)) * originalScale; - AudioReflector.setOriginalSourceAttenuation(original); - originalThumbX = newThumbX; - } -} - -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index dbd8ee18d9..d39fce0186 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -14,3 +14,4 @@ Script.load("selectAudioDevice.js"); Script.load("hydraMove.js"); Script.load("headMove.js"); Script.load("inspect.js"); +Script.load("lobby.js"); diff --git a/examples/editEntities.js b/examples/editEntities.js index 43e304a76d..e9f42bf74c 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -159,8 +159,8 @@ var toolBar = (function () { visible: false }); - menuItemWidth = Math.max(Overlays.textWidth(loadURLMenuItem, "Model URL"), - Overlays.textWidth(loadFileMenuItem, "Model File")) + 20; + menuItemWidth = Math.max(Overlays.textSize(loadURLMenuItem, "Model URL").width, + Overlays.textSize(loadFileMenuItem, "Model File").width) + 20; Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); diff --git a/examples/editModels.js b/examples/editModels.js index c961d55bed..e0ade3b6a3 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1191,8 +1191,8 @@ var toolBar = (function () { visible: false }); - menuItemWidth = Math.max(Overlays.textWidth(loadURLMenuItem, "Model URL"), - Overlays.textWidth(loadFileMenuItem, "Model File")) + 20; + menuItemWidth = Math.max(Overlays.textSize(loadURLMenuItem, "Model URL").width, + Overlays.textSize(loadFileMenuItem, "Model File").width) + 20; Overlays.editOverlay(loadURLMenuItem, { width: menuItemWidth }); Overlays.editOverlay(loadFileMenuItem, { width: menuItemWidth }); diff --git a/examples/lobby.js b/examples/lobby.js index 99fdbe5a67..b03be7c29b 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -47,6 +47,10 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" +var LOBBY_PANEL_WALL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/PanelWallForInterface.fbx"; +var LOBBY_BLANK_PANEL_TEXTURE_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Texture.jpg"; +var LOBBY_SHELL_URL = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/LobbyShellForInterface.fbx"; + var droneSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.stereo.raw") var currentDrone = null; @@ -62,6 +66,21 @@ function textOverlayPosition() { Vec3.multiply(Quat.getUp(Camera.orientation), TEXT_DISTANCE_DOWN)); } +var panelLocationOrder = [ + 7, 8, 9, 10, 11, 12, 13, + 0, 1, 2, 3, 4, 5, 6, + 14, 15, 16, 17, 18, 19, 20 +]; + +// Location index is 0-based +function locationIndexToPanelIndex(locationIndex) { + return panelLocationOrder.indexOf(locationIndex) + 1; +} + +// Panel index is 1-based +function panelIndexToLocationIndex(panelIndex) { + return panelLocationOrder[panelIndex - 1]; +} var MAX_NUM_PANELS = 21; var DRONE_VOLUME = 0.3; @@ -76,14 +95,14 @@ function drawLobby() { var orbPosition = Vec3.sum(Camera.position, Vec3.multiplyQbyV(towardsMe, ORB_SHIFT)); var panelWallProps = { - url: HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Lobby_v8/forStephen1/PanelWall2.fbx", + url: LOBBY_PANEL_WALL_URL, position: Vec3.sum(orbPosition, Vec3.multiplyQbyV(towardsMe, panelsCenterShift)), rotation: towardsMe, dimensions: panelsDimensions }; var orbShellProps = { - url: HIFI_PUBLIC_BUCKET + "models/sets/Lobby/Lobby_v8/forStephen1/LobbyShell1.4_LightTag.fbx", + url: LOBBY_SHELL_URL, position: orbPosition, rotation: towardsMe, dimensions: orbDimensions, @@ -143,7 +162,9 @@ function changeLobbyTextures() { }; for (var j = 0; j < NUM_PANELS; j++) { - textureProp["textures"]["file" + (j + 1)] = "http:" + locations[j].thumbnail_url + var panelIndex = locationIndexToPanelIndex(j); + textureProp["textures"]["file" + panelIndex] = HIFI_PUBLIC_BUCKET + "images/locations/" + + locations[j].id + "/hifi-location-" + locations[j].id + "_640x360.jpg"; }; Overlays.editOverlay(panelWall, textureProp); @@ -193,7 +214,7 @@ function cleanupLobby() { panelTexturesReset["textures"] = {}; for (var j = 0; j < MAX_NUM_PANELS; j++) { - panelTexturesReset["textures"]["file" + (j + 1)] = HIFI_PUBLIC_BUCKET + "models/sets/Lobby/LobbyPrototype/Texture.jpg"; + panelTexturesReset["textures"]["file" + (j + 1)] = LOBBY_BLANK_PANEL_TEXTURE_URL; }; Overlays.editOverlay(panelWall, panelTexturesReset); @@ -228,12 +249,13 @@ function actionStartEvent(event) { var panelStringIndex = panelName.indexOf("Panel"); if (panelStringIndex != -1) { - var panelIndex = parseInt(panelName.slice(5)) - 1; - if (panelIndex < locations.length) { - var actionLocation = locations[panelIndex]; + var panelIndex = parseInt(panelName.slice(5)); + var locationIndex = panelIndexToLocationIndex(panelIndex); + if (locationIndex < locations.length) { + var actionLocation = locations[locationIndex]; print("Jumping to " + actionLocation.name + " at " + actionLocation.path - + " in " + actionLocation.domain.name + " after click on panel " + panelIndex); + + " in " + actionLocation.domain.name + " after click on panel " + panelIndex + " with location index " + locationIndex); Window.location = actionLocation; maybeCleanupLobby(); @@ -277,9 +299,10 @@ function handleLookAt(pickRay) { var panelName = result.extraInfo; var panelStringIndex = panelName.indexOf("Panel"); if (panelStringIndex != -1) { - var panelIndex = parseInt(panelName.slice(5)) - 1; - if (panelIndex < locations.length) { - var actionLocation = locations[panelIndex]; + var panelIndex = parseInt(panelName.slice(5)); + var locationIndex = panelIndexToLocationIndex(panelIndex); + if (locationIndex < locations.length) { + var actionLocation = locations[locationIndex]; if (actionLocation.description == "") { Overlays.editOverlay(descriptionText, { text: actionLocation.name, visible: showText }); @@ -300,7 +323,7 @@ function handleLookAt(pickRay) { } else { currentTestLine = allWords[currentTestWord]; } - var lineLength = Overlays.textWidth(descriptionText, currentTestLine); + var lineLength = Overlays.textSize(descriptionText, currentTestLine).width; if (lineLength < textWidth || wordsOnLine == 0) { wordsFormated++; currentTestWord++; diff --git a/examples/playChess.js b/examples/playChess.js index 57ed24f342..faa32f6cda 100644 --- a/examples/playChess.js +++ b/examples/playChess.js @@ -86,6 +86,7 @@ ChessGame.Board = (function(position, scale) { modelURL: ChessGame.BOARD.modelURL, position: this.position, dimensions: this.dimensions, + rotation: ChessGame.BOARD.rotation, userData: this.buildUserDataString() } this.entity = null; diff --git a/examples/virtualKeyboard.js b/examples/virtualKeyboard.js index c89dc6fb04..ce793c6ea0 100644 --- a/examples/virtualKeyboard.js +++ b/examples/virtualKeyboard.js @@ -80,7 +80,7 @@ function updateTextOverlay() { var textLines = textText.split("\n"); var maxLineWidth = 0; for (textLine in textLines) { - var lineWidth = Overlays.textWidth(text, textLines[textLine]); + var lineWidth = Overlays.textSize(text, textLines[textLine]).width; if (lineWidth > maxLineWidth) { maxLineWidth = lineWidth; } @@ -92,7 +92,7 @@ function updateTextOverlay() { Overlays.editOverlay(text, {text: textText, font: {size: textFontSize}, topMargin: topMargin}); var maxLineWidth = 0; for (textLine in textLines) { - var lineWidth = Overlays.textWidth(text, textLines[textLine]); + var lineWidth = Overlays.textSize(text, textLines[textLine]).width; if (lineWidth > maxLineWidth) { maxLineWidth = lineWidth; } @@ -122,18 +122,18 @@ keyboard.onKeyRelease = function(event) { var textLines = textText.split("\n"); var maxLineWidth = 0; for (textLine in textLines) { - var lineWidth = Overlays.textWidth(textSizeMeasureOverlay, textLines[textLine]); + var lineWidth = Overlays.textSize(textSizeMeasureOverlay, textLines[textLine]).width; if (lineWidth > maxLineWidth) { maxLineWidth = lineWidth; } } var usernameLine = "--" + GlobalServices.myUsername; - var usernameWidth = Overlays.textWidth(textSizeMeasureOverlay, usernameLine); + var usernameWidth = Overlays.textSize(textSizeMeasureOverlay, usernameLine).width; if (maxLineWidth < usernameWidth) { maxLineWidth = usernameWidth; } else { var spaceableWidth = maxLineWidth - usernameWidth; - var spaceWidth = Overlays.textWidth(textSizeMeasureOverlay, " "); + var spaceWidth = Overlays.textSize(textSizeMeasureOverlay, " ").width; var numberOfSpaces = Math.floor(spaceableWidth / spaceWidth); for (var i = 0; i < numberOfSpaces; i++) { usernameLine = " " + usernameLine; diff --git a/interface/resources/shaders/passthrough.vert b/interface/resources/shaders/passthrough.vert deleted file mode 100644 index bb0a18eefa..0000000000 --- a/interface/resources/shaders/passthrough.vert +++ /dev/null @@ -1,21 +0,0 @@ -#version 120 - -// -// passthrough.vert -// vertex shader -// -// Copyright 2013 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 -// - -attribute float voxelSizeIn; -varying float voxelSize; - -void main(void) { - gl_FrontColor = gl_Color; - gl_Position = gl_Vertex; // don't call ftransform(), because we do projection in geometry shader - voxelSize = voxelSizeIn; -} \ No newline at end of file diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert deleted file mode 100644 index 88c56bf0c4..0000000000 --- a/interface/resources/shaders/point_size.vert +++ /dev/null @@ -1,174 +0,0 @@ -#version 120 - -// -// point_size.vert -// vertex shader -// -// Copyright 2013 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 -// - -attribute float voxelSizeIn; -varying float voxelSize; - -uniform float viewportWidth; -uniform float viewportHeight; -uniform vec3 cameraPosition; - -// Bit codes for faces -const int NONE = 0; -const int RIGHT = 1; -const int LEFT = 2; -const int BOTTOM = 4; -const int BOTTOM_RIGHT = BOTTOM + RIGHT; -const int BOTTOM_LEFT = BOTTOM + LEFT; -const int TOP = 8; -const int TOP_RIGHT = TOP + RIGHT; -const int TOP_LEFT = TOP + LEFT; -const int NEAR = 16; -const int NEAR_RIGHT = NEAR + RIGHT; -const int NEAR_LEFT = NEAR + LEFT; -const int NEAR_BOTTOM = NEAR + BOTTOM; -const int NEAR_BOTTOM_RIGHT = NEAR + BOTTOM + RIGHT; -const int NEAR_BOTTOM_LEFT = NEAR + BOTTOM + LEFT; -const int NEAR_TOP = NEAR + TOP; -const int NEAR_TOP_RIGHT = NEAR + TOP + RIGHT; -const int NEAR_TOP_LEFT = NEAR + TOP + LEFT; -const int FAR = 32; -const int FAR_RIGHT = FAR + RIGHT; -const int FAR_LEFT = FAR + LEFT; -const int FAR_BOTTOM = FAR + BOTTOM; -const int FAR_BOTTOM_RIGHT = FAR + BOTTOM + RIGHT; -const int FAR_BOTTOM_LEFT = FAR + BOTTOM + LEFT; -const int FAR_TOP = FAR + TOP; -const int FAR_TOP_RIGHT = FAR + TOP + RIGHT; -const int FAR_TOP_LEFT = FAR + TOP + LEFT; - -// If we know the position of the camera relative to the voxel, we can a priori know the vertices that make the visible hull -// polygon. This also tells us which two vertices are known to make the longest possible distance between any pair of these -// vertices for the projected polygon. This is a visibleFaces table based on this knowledge. - -void main(void) { - // Note: the gl_Vertex in this case are in "world coordinates" meaning they've already been scaled to TREE_SCALE - // this is also true for voxelSizeIn. - vec4 bottomNearRight = gl_Vertex; - vec4 topFarLeft = (gl_Vertex + vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0)); - - int visibleFaces = NONE; - - // In order to use our visibleFaces "table" (implemented as if statements) below, we need to encode the 6-bit code to - // orient camera relative to the 6 defining faces of the voxel. Based on camera position relative to the bottomNearRight - // corner and the topFarLeft corner, we can calculate which hull and therefore which two vertices are furthest apart - // linearly once projected - if (cameraPosition.x < bottomNearRight.x) { - visibleFaces += RIGHT; - } - if (cameraPosition.x > topFarLeft.x) { - visibleFaces += LEFT; - } - if (cameraPosition.y < bottomNearRight.y) { - visibleFaces += BOTTOM; - } - if (cameraPosition.y > topFarLeft.y) { - visibleFaces += TOP; - } - if (cameraPosition.z < bottomNearRight.z) { - visibleFaces += NEAR; - } - if (cameraPosition.z > topFarLeft.z) { - visibleFaces += FAR; - } - - vec4 cornerAdjustOne; - vec4 cornerAdjustTwo; - - if (visibleFaces == RIGHT) { - cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; - } else if (visibleFaces == LEFT) { - cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; - } else if (visibleFaces == BOTTOM) { - cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; - } else if (visibleFaces == TOP) { - cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; - } else if (visibleFaces == NEAR) { - cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; - } else if (visibleFaces == FAR) { - cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; - } else if (visibleFaces == NEAR_BOTTOM_LEFT || - visibleFaces == FAR_TOP || - visibleFaces == FAR_TOP_RIGHT) { - cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; - } else if (visibleFaces == FAR_TOP_LEFT || - visibleFaces == NEAR_RIGHT || - visibleFaces == NEAR_BOTTOM || - visibleFaces == NEAR_BOTTOM_RIGHT) { - cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; - } else if (visibleFaces == NEAR_TOP_RIGHT || - visibleFaces == FAR_LEFT || - visibleFaces == FAR_BOTTOM_LEFT || - visibleFaces == BOTTOM_RIGHT || - visibleFaces == TOP_LEFT) { - cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; - - // Everything else... - //} else if (visibleFaces == BOTTOM_LEFT || - // visibleFaces == TOP_RIGHT || - // visibleFaces == NEAR_LEFT || - // visibleFaces == FAR_RIGHT || - // visibleFaces == NEAR_TOP || - // visibleFaces == NEAR_TOP_LEFT || - // visibleFaces == FAR_BOTTOM || - // visibleFaces == FAR_BOTTOM_RIGHT) { - } else { - cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; - cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; - } - - // Determine our corners - vec4 cornerOne = gl_Vertex + cornerAdjustOne; - vec4 cornerTwo = gl_Vertex + cornerAdjustTwo; - - // Find their model view projections - vec4 cornerOneMVP = gl_ModelViewProjectionMatrix * cornerOne; - vec4 cornerTwoMVP = gl_ModelViewProjectionMatrix * cornerTwo; - - // Map to x, y screen coordinates - vec2 cornerOneScreen = vec2(cornerOneMVP.x / cornerOneMVP.w, cornerOneMVP.y / cornerOneMVP.w); - if (cornerOneMVP.w < 0) { - cornerOneScreen.x = -cornerOneScreen.x; - cornerOneScreen.y = -cornerOneScreen.y; - } - - vec2 cornerTwoScreen = vec2(cornerTwoMVP.x / cornerTwoMVP.w, cornerTwoMVP.y / cornerTwoMVP.w); - if (cornerTwoMVP.w < 0) { - cornerTwoScreen.x = -cornerTwoScreen.x; - cornerTwoScreen.y = -cornerTwoScreen.y; - } - - // Find the distance between them in pixels - float voxelScreenWidth = abs(cornerOneScreen.x - cornerTwoScreen.x) * viewportWidth / 2.0; - float voxelScreenHeight = abs(cornerOneScreen.y - cornerTwoScreen.y) * viewportHeight / 2.0; - float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); - - // Find the center of the voxel - vec4 centerVertex = gl_Vertex; - float halfSizeIn = voxelSizeIn / 2; - centerVertex += vec4(halfSizeIn, halfSizeIn, halfSizeIn, 0.0); - vec4 center = gl_ModelViewProjectionMatrix * centerVertex; - - // Finally place the point at the center of the voxel, with a size equal to the maximum screen length - gl_Position = center; - gl_PointSize = voxelScreenLength; - gl_FrontColor = gl_Color; -} \ No newline at end of file diff --git a/interface/resources/shaders/voxel.geom b/interface/resources/shaders/voxel.geom deleted file mode 100644 index 4c850ed608..0000000000 --- a/interface/resources/shaders/voxel.geom +++ /dev/null @@ -1,87 +0,0 @@ -#version 120 -#extension GL_ARB_geometry_shader4 : enable - -// -// voxel.geom -// geometry shader -// -// Copyright 2013 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 -// - -// -// VOXEL GEOMETRY SHADER -// -// Input: gl_VerticesIn/gl_PositionIn -// GL_POINTS -// Assumes vertex shader has not transformed coordinates -// Each gl_PositionIn is the corner of voxel -// varying voxelSize - which is the voxel size -// -// Note: In vertex shader doesn't do any transform. Therefore passing the 3D world coordinates xyz to us -// -// Output: GL_TRIANGLE_STRIP -// -// Issues: -// how do we need to handle lighting of these colors?? -// how do we handle normals? -// check for size=0 and don't output the primitive -// - -varying in float voxelSize[1]; - -const int VERTICES_PER_FACE = 4; -const int COORD_PER_VERTEX = 3; -const int COORD_PER_FACE = COORD_PER_VERTEX * VERTICES_PER_FACE; - -void faceOfVoxel(vec4 corner, float scale, float[COORD_PER_FACE] facePoints, vec4 color, vec4 normal) { - for (int v = 0; v < VERTICES_PER_FACE; v++ ) { - vec4 vertex = corner; - for (int c = 0; c < COORD_PER_VERTEX; c++ ) { - int cIndex = c + (v * COORD_PER_VERTEX); - vertex[c] += (facePoints[cIndex] * scale); - } - - gl_FrontColor = color * (gl_LightModel.ambient + gl_LightSource[0].ambient + - gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); - - gl_Position = gl_ModelViewProjectionMatrix * vertex; - EmitVertex(); - } - EndPrimitive(); -} - - -void main() { - //increment variable - int i; - vec4 corner; - float scale; - - float bottomFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1 ); - float topFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1 ); - float rightFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1 ); - float leftFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1 ); - float frontFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 ); - float backFace[COORD_PER_FACE] = float[COORD_PER_FACE]( 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1 ); - - vec4 bottomNormal = vec4(0.0, -1, 0.0, 0.0); - vec4 topNormal = vec4(0.0, 1, 0.0, 0.0); - vec4 rightNormal = vec4( -1, 0.0, 0.0, 0.0); - vec4 leftNormal = vec4( 1, 0.0, 0.0, 0.0); - vec4 frontNormal = vec4(0.0, 0.0, -1, 0.0); - vec4 backNormal = vec4(0.0, 0.0, 1, 0.0); - - for(i = 0; i < gl_VerticesIn; i++) { - corner = gl_PositionIn[i]; - scale = voxelSize[i]; - faceOfVoxel(corner, scale, bottomFace, gl_FrontColorIn[i], bottomNormal); - faceOfVoxel(corner, scale, topFace, gl_FrontColorIn[i], topNormal ); - faceOfVoxel(corner, scale, rightFace, gl_FrontColorIn[i], rightNormal ); - faceOfVoxel(corner, scale, leftFace, gl_FrontColorIn[i], leftNormal ); - faceOfVoxel(corner, scale, frontFace, gl_FrontColorIn[i], frontNormal ); - faceOfVoxel(corner, scale, backFace, gl_FrontColorIn[i], backNormal ); - } -} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d773208ac0..7a0e61240a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -141,6 +142,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _window(new MainWindow(desktop())), _glWidget(new GLCanvas()), + _toolWindow(NULL), _nodeThread(new QThread(this)), _datagramProcessor(), _undoStack(), @@ -415,9 +417,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString(); } - connect(_window, &MainWindow::windowGeometryChanged, - _runningScriptsWidget, &RunningScriptsWidget::setBoundary); - _trayIcon->show(); // set the local loopback interface for local sounds from audio scripts @@ -1917,8 +1916,6 @@ void Application::init() { _deferredLightingEffect.init(); _glowEffect.init(); _ambientOcclusionEffect.init(); - _voxelShader.init(); - _pointShader.init(); // TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager _avatarManager.init(); @@ -1989,8 +1986,6 @@ void Application::init() { // Set up VoxelSystem after loading preferences so we can get the desired max voxel count _voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels()); - _voxels.setUseVoxelShader(false); - _voxels.setVoxelsAsPoints(false); _voxels.setDisableFastVoxelPipeline(false); _voxels.init(); @@ -2034,17 +2029,6 @@ void Application::init() { connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors())); - // set up our audio reflector - _audioReflector.setMyAvatar(getAvatar()); - _audioReflector.setVoxels(_voxels.getTree()); - _audioReflector.setAudio(getAudio()); - _audioReflector.setAvatarManager(&_avatarManager); - - connect(getAudio(), &Audio::processInboundAudio, &_audioReflector, &AudioReflector::processInboundAudio,Qt::DirectConnection); - connect(getAudio(), &Audio::processLocalAudio, &_audioReflector, &AudioReflector::processLocalAudio,Qt::DirectConnection); - connect(getAudio(), &Audio::preProcessOriginalInboundAudio, &_audioReflector, - &AudioReflector::preProcessOriginalInboundAudio,Qt::DirectConnection); - connect(getAudio(), &Audio::muteToggled, AudioDeviceScriptingInterface::getInstance(), &AudioDeviceScriptingInterface::muteToggled, Qt::DirectConnection); @@ -2297,13 +2281,14 @@ void Application::updateCursor(float deltaTime) { PerformanceWarning warn(showWarnings, "Application::updateCursor()"); bool hideMouse = false; - bool underMouse = _glWidget->underMouse(); + bool underMouse = QGuiApplication::topLevelAt(QCursor::pos()) == + Application::getInstance()->getWindow()->windowHandle(); static const int HIDE_CURSOR_TIMEOUT = 3 * USECS_PER_SECOND; // 3 second int elapsed = usecTimestampNow() - _lastMouseMove; - if ((elapsed > HIDE_CURSOR_TIMEOUT && underMouse) || + if ((elapsed > HIDE_CURSOR_TIMEOUT) || (OculusManager::isConnected() && Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode))) { - hideMouse = true; + hideMouse = underMouse; } setCursorVisible(!hideMouse); @@ -2717,6 +2702,29 @@ bool Application::isHMDMode() const { } } +QRect Application::getDesirableApplicationGeometry() { + QRect applicationGeometry = getWindow()->geometry(); + + // If our parent window is on the HMD, then don't use it's geometry, instead use + // the "main screen" geometry. + HMDToolsDialog* hmdTools = Menu::getInstance()->getHMDToolsDialog(); + if (hmdTools && hmdTools->hasHMDScreen()) { + QScreen* hmdScreen = hmdTools->getHMDScreen(); + QWindow* appWindow = getWindow()->windowHandle(); + QScreen* appScreen = appWindow->screen(); + + // if our app's screen is the hmd screen, we don't want to place the + // running scripts widget on it. So we need to pick a better screen. + // we will use the screen for the HMDTools since it's a guarenteed + // better screen. + if (appScreen == hmdScreen) { + QScreen* betterScreen = hmdTools->windowHandle()->screen(); + applicationGeometry = betterScreen->geometry(); + } + } + return applicationGeometry; +} + ///////////////////////////////////////////////////////////////////////////////////// // loadViewFrustum() // @@ -3064,12 +3072,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly, RenderAr glColor3f(1,0,0); _geometryCache.renderSphere(originSphereRadius, 15, 15); - // draw the audio reflector overlay - { - PerformanceTimer perfTimer("audio"); - _audioReflector.render(); - } - // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceTimer perfTimer("voxels"); @@ -3997,7 +3999,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); scriptEngine->registerGlobalObject("SoundCache", &SoundCache::getInstance()); - scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0f0bd91210..f82b14b47e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -42,7 +42,6 @@ #include "MainWindow.h" #include "Audio.h" -#include "AudioReflector.h" #include "Camera.h" #include "DatagramProcessor.h" #include "Environment.h" @@ -65,9 +64,7 @@ #include "renderer/DeferredLightingEffect.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" -#include "renderer/PointShader.h" #include "renderer/TextureCache.h" -#include "renderer/VoxelShader.h" #include "scripting/ControllerScriptingInterface.h" #include "ui/BandwidthDialog.h" #include "ui/BandwidthMeter.h" @@ -193,7 +190,6 @@ public: bool isThrottleRendering() const { return _glWidget->isThrottleRendering(); } MyAvatar* getAvatar() { return _myAvatar; } Audio* getAudio() { return &_audio; } - const AudioReflector* getAudioReflector() const { return &_audioReflector; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } ViewFrustum* getDisplayViewFrustum() { return &_displayViewFrustum; } @@ -297,8 +293,6 @@ public: NodeBounds& getNodeBoundsDisplay() { return _nodeBoundsDisplay; } - VoxelShader& getVoxelShader() { return _voxelShader; } - PointShader& getPointShader() { return _pointShader; } FileLogger* getLogger() { return _logger; } glm::vec2 getViewportDimensions() const { return glm::vec2(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight()); } @@ -327,6 +321,9 @@ public: // rendering of several elements depend on that // TODO: carry that information on the Camera as a setting bool isHMDMode() const; + + QRect getDesirableApplicationGeometry(); + RunningScriptsWidget* getRunningScriptsWidget() { return _runningScriptsWidget; } signals: @@ -588,8 +585,6 @@ private: DeferredLightingEffect _deferredLightingEffect; GlowEffect _glowEffect; AmbientOcclusionEffect _ambientOcclusionEffect; - VoxelShader _voxelShader; - PointShader _pointShader; Audio _audio; @@ -635,7 +630,6 @@ private: Overlays _overlays; ApplicationOverlay _applicationOverlay; - AudioReflector _audioReflector; RunningScriptsWidget* _runningScriptsWidget; QHash _scriptEnginesHash; bool _runningScriptsWidgetWasVisible; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 2214bb54cf..101d16d3ba 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -103,10 +103,6 @@ Audio::Audio(QObject* parent) : _gverb(NULL), _iconColor(1.0f), _iconPulseTimeReference(usecTimestampNow()), - _processSpatialAudio(false), - _spatialAudioStart(0), - _spatialAudioFinish(0), - _spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, true), // random access mode _scopeEnabled(false), _scopeEnabledPause(false), _scopeInputOffset(0), @@ -838,13 +834,6 @@ void Audio::handleAudioInput() { _lastInputLoudness = 0; } - // at this point we have clean monoAudioSamples, which match our target output... - // this is what we should send to our interested listeners - if (_processSpatialAudio && !_muted && !_isStereoInput && _audioOutput) { - QByteArray monoInputData((char*)networkAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); - emit processLocalAudio(_spatialAudioStart, monoInputData, _desiredInputFormat); - } - if (!_isStereoInput && _proceduralAudioOutput) { processProceduralAudio(networkAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); } @@ -984,35 +973,11 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples; - if (_processSpatialAudio) { - unsigned int sampleTime = _spatialAudioStart; - QByteArray buffer = inputBuffer; + // copy the samples we'll resample from the ring buffer - this also + // pushes the read pointer of the ring buffer forwards + //receivedAudioStreamPopOutput.readSamples(receivedSamples, numNetworkOutputSamples); - // Accumulate direct transmission of audio from sender to receiver - bool includeOriginal = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal) - if (includeOriginal) { - emit preProcessOriginalInboundAudio(sampleTime, buffer, _desiredOutputFormat); - addSpatialAudioToBuffer(sampleTime, buffer, numNetworkOutputSamples); - } - - // Send audio off for spatial processing - emit processInboundAudio(sampleTime, buffer, _desiredOutputFormat); - - // copy the samples we'll resample from the spatial audio ring buffer - this also - // pushes the read pointer of the spatial audio ring buffer forwards - _spatialAudioRingBuffer.readSamples(_outputProcessingBuffer, numNetworkOutputSamples); - - // Advance the start point for the next packet of audio to arrive - _spatialAudioStart += numNetworkOutputSamples / _desiredOutputFormat.channelCount(); - - receivedSamples = _outputProcessingBuffer; - } else { - // copy the samples we'll resample from the ring buffer - this also - // pushes the read pointer of the ring buffer forwards - //receivedAudioStreamPopOutput.readSamples(receivedSamples, numNetworkOutputSamples); - - receivedSamples = reinterpret_cast(inputBuffer.data()); - } + receivedSamples = reinterpret_cast(inputBuffer.data()); // copy the packet from the RB to the output linearResampling(receivedSamples, @@ -1123,68 +1088,7 @@ void Audio::sendDownstreamAudioStatsPacket() { nodeList->writeDatagram(packet, dataAt - packet, audioMixer); } -// NOTE: numSamples is the total number of single channel samples, since callers will always call this with stereo -// data we know that we will have 2x samples for each stereo time sample at the format's sample rate -void Audio::addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples) { - // Calculate the number of remaining samples available. The source spatial audio buffer will get - // clipped if there are insufficient samples available in the accumulation buffer. - unsigned int remaining = _spatialAudioRingBuffer.getSampleCapacity() - _spatialAudioRingBuffer.samplesAvailable(); - // Locate where in the accumulation buffer the new samples need to go - if (sampleTime >= _spatialAudioFinish) { - if (_spatialAudioStart == _spatialAudioFinish) { - // Nothing in the spatial audio ring buffer yet, Just do a straight copy, clipping if necessary - unsigned int sampleCount = (remaining < numSamples) ? remaining : numSamples; - if (sampleCount) { - _spatialAudioRingBuffer.writeSamples((int16_t*)spatialAudio.data(), sampleCount); - } - _spatialAudioFinish = _spatialAudioStart + sampleCount / _desiredOutputFormat.channelCount(); - } else { - // Spatial audio ring buffer already has data, but there is no overlap with the new sample. - // Compute the appropriate time delay and pad with silence until the new start time. - unsigned int delay = sampleTime - _spatialAudioFinish; - unsigned int delayCount = delay * _desiredOutputFormat.channelCount(); - unsigned int silentCount = (remaining < delayCount) ? remaining : delayCount; - if (silentCount) { - _spatialAudioRingBuffer.addSilentSamples(silentCount); - } - - // Recalculate the number of remaining samples - remaining -= silentCount; - unsigned int sampleCount = (remaining < numSamples) ? remaining : numSamples; - - // Copy the new spatial audio to the accumulation ring buffer - if (sampleCount) { - _spatialAudioRingBuffer.writeSamples((int16_t*)spatialAudio.data(), sampleCount); - } - _spatialAudioFinish += (sampleCount + silentCount) / _desiredOutputFormat.channelCount(); - } - } else { - // There is overlap between the spatial audio buffer and the new sample, mix the overlap - // Calculate the offset from the buffer's current read position, which should be located at _spatialAudioStart - unsigned int offset = (sampleTime - _spatialAudioStart) * _desiredOutputFormat.channelCount(); - unsigned int mixedSamplesCount = (_spatialAudioFinish - sampleTime) * _desiredOutputFormat.channelCount(); - mixedSamplesCount = (mixedSamplesCount < numSamples) ? mixedSamplesCount : numSamples; - - const int16_t* spatial = reinterpret_cast(spatialAudio.data()); - for (unsigned int i = 0; i < mixedSamplesCount; i++) { - int existingSample = _spatialAudioRingBuffer[i + offset]; - int newSample = spatial[i]; - int sumOfSamples = existingSample + newSample; - _spatialAudioRingBuffer[i + offset] = static_cast(glm::clamp(sumOfSamples, - std::numeric_limits::min(), std::numeric_limits::max())); - } - - // Copy the remaining unoverlapped spatial audio to the spatial audio buffer, if any - unsigned int nonMixedSampleCount = numSamples - mixedSamplesCount; - nonMixedSampleCount = (remaining < nonMixedSampleCount) ? remaining : nonMixedSampleCount; - if (nonMixedSampleCount) { - _spatialAudioRingBuffer.writeSamples((int16_t*)spatialAudio.data() + mixedSamplesCount, nonMixedSampleCount); - // Extend the finish time by the amount of unoverlapped samples - _spatialAudioFinish += nonMixedSampleCount / _desiredOutputFormat.channelCount(); - } - } -} bool Audio::mousePressEvent(int x, int y) { if (_iconBounds.contains(x, y)) { @@ -1264,16 +1168,6 @@ void Audio::selectAudioSourceSine440() { _noiseSourceEnabled = !_toneSourceEnabled; } -void Audio::toggleAudioSpatialProcessing() { - // spatial audio disabled for now - _processSpatialAudio = false; //!_processSpatialAudio; - if (_processSpatialAudio) { - _spatialAudioStart = 0; - _spatialAudioFinish = 0; - _spatialAudioRingBuffer.reset(); - } -} - // Take a pointer to the acquired microphone input samples and add procedural sounds void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) { float sample; @@ -1995,11 +1889,6 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) _timeSinceLastReceived.start(); - // setup spatial audio ringbuffer - int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount(); - _spatialAudioRingBuffer.resizeForFrameSize(numFrameSamples); - _spatialAudioStart = _spatialAudioFinish = 0; - supportedFormat = true; } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 166042878c..47fe00a84c 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -115,8 +115,6 @@ public: int getNetworkSampleRate() { return SAMPLE_RATE; } int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; } - bool getProcessSpatialAudio() const { return _processSpatialAudio; } - float getInputRingBufferMsecsAvailable() const; float getInputRingBufferAverageMsecsAvailable() const { return (float)_inputRingBufferMsecsAvailableStats.getWindowAverage(); } @@ -131,7 +129,6 @@ public slots: void addReceivedAudioToStream(const QByteArray& audioByteArray); void parseAudioStreamStatsPacket(const QByteArray& packet); void parseAudioEnvironmentData(const QByteArray& packet); - void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples); void handleAudioInput(); void reset(); void resetStats(); @@ -145,7 +142,6 @@ public slots: void toggleScopePause(); void toggleStats(); void toggleStatsShowInjectedStreams(); - void toggleAudioSpatialProcessing(); void toggleStereoInput(); void selectAudioScopeFiveFrames(); void selectAudioScopeTwentyFrames(); @@ -254,11 +250,6 @@ private: float _iconColor; qint64 _iconPulseTimeReference; - bool _processSpatialAudio; /// Process received audio by spatial audio hooks - unsigned int _spatialAudioStart; /// Start of spatial audio interval (in sample rate time base) - unsigned int _spatialAudioFinish; /// End of spatial audio interval (in sample rate time base) - AudioRingBuffer _spatialAudioRingBuffer; /// Spatially processed audio - // Process procedural audio by // 1. Echo to the local procedural output device // 2. Mix with the audio input diff --git a/interface/src/AudioReflector.cpp b/interface/src/AudioReflector.cpp deleted file mode 100644 index 8a23ecee79..0000000000 --- a/interface/src/AudioReflector.cpp +++ /dev/null @@ -1,868 +0,0 @@ -// -// AudioReflector.cpp -// interface -// -// Created by Brad Hefta-Gaub on 4/2/2014 -// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. -// - -#include - -#include "AudioReflector.h" -#include "Menu.h" - -const float DEFAULT_PRE_DELAY = 20.0f; // this delay in msecs will always be added to all reflections -const float DEFAULT_MS_DELAY_PER_METER = 3.0f; -const float MINIMUM_ATTENUATION_TO_REFLECT = 1.0f / 256.0f; -const float DEFAULT_DISTANCE_SCALING_FACTOR = 2.0f; -const float MAXIMUM_DELAY_MS = 1000.0 * 20.0f; // stop reflecting after path is this long -const int DEFAULT_DIFFUSION_FANOUT = 5; -const unsigned int ABSOLUTE_MAXIMUM_BOUNCE_COUNT = 10; -const float DEFAULT_LOCAL_ATTENUATION_FACTOR = 0.125; -const float DEFAULT_COMB_FILTER_WINDOW = 0.05f; //ms delay differential to avoid - -const float SLIGHTLY_SHORT = 0.999f; // slightly inside the distance so we're on the inside of the reflection point - -const float DEFAULT_ABSORPTION_RATIO = 0.125; // 12.5% is absorbed -const float DEFAULT_DIFFUSION_RATIO = 0.125; // 12.5% is diffused -const float DEFAULT_ORIGINAL_ATTENUATION = 1.0f; -const float DEFAULT_ECHO_ATTENUATION = 1.0f; - -AudioReflector::AudioReflector(QObject* parent) : - QObject(parent), - _preDelay(DEFAULT_PRE_DELAY), - _soundMsPerMeter(DEFAULT_MS_DELAY_PER_METER), - _distanceAttenuationScalingFactor(DEFAULT_DISTANCE_SCALING_FACTOR), - _localAudioAttenuationFactor(DEFAULT_LOCAL_ATTENUATION_FACTOR), - _combFilterWindow(DEFAULT_COMB_FILTER_WINDOW), - _diffusionFanout(DEFAULT_DIFFUSION_FANOUT), - _absorptionRatio(DEFAULT_ABSORPTION_RATIO), - _diffusionRatio(DEFAULT_DIFFUSION_RATIO), - _originalSourceAttenuation(DEFAULT_ORIGINAL_ATTENUATION), - _allEchoesAttenuation(DEFAULT_ECHO_ATTENUATION), - _withDiffusion(false), - _lastPreDelay(DEFAULT_PRE_DELAY), - _lastSoundMsPerMeter(DEFAULT_MS_DELAY_PER_METER), - _lastDistanceAttenuationScalingFactor(DEFAULT_DISTANCE_SCALING_FACTOR), - _lastLocalAudioAttenuationFactor(DEFAULT_LOCAL_ATTENUATION_FACTOR), - _lastDiffusionFanout(DEFAULT_DIFFUSION_FANOUT), - _lastAbsorptionRatio(DEFAULT_ABSORPTION_RATIO), - _lastDiffusionRatio(DEFAULT_DIFFUSION_RATIO), - _lastDontDistanceAttenuate(false), - _lastAlternateDistanceAttenuate(false) -{ - _reflections = 0; - _diffusionPathCount = 0; - _officialAverageAttenuation = _averageAttenuation = 0.0f; - _officialMaxAttenuation = _maxAttenuation = 0.0f; - _officialMinAttenuation = _minAttenuation = 0.0f; - _officialAverageDelay = _averageDelay = 0; - _officialMaxDelay = _maxDelay = 0; - _officialMinDelay = _minDelay = 0; - _inboundEchoesCount = 0; - _inboundEchoesSuppressedCount = 0; - _localEchoesCount = 0; - _localEchoesSuppressedCount = 0; -} - -bool AudioReflector::haveAttributesChanged() { - - // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingWithDiffusions); - bool withDiffusion = true; - - // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingDontDistanceAttenuate); - bool dontDistanceAttenuate = false; - - //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingAlternateDistanceAttenuate); - bool alternateDistanceAttenuate = false; - - bool attributesChange = (_withDiffusion != withDiffusion - || _lastPreDelay != _preDelay - || _lastSoundMsPerMeter != _soundMsPerMeter - || _lastDistanceAttenuationScalingFactor != _distanceAttenuationScalingFactor - || _lastDiffusionFanout != _diffusionFanout - || _lastAbsorptionRatio != _absorptionRatio - || _lastDiffusionRatio != _diffusionRatio - || _lastDontDistanceAttenuate != dontDistanceAttenuate - || _lastAlternateDistanceAttenuate != alternateDistanceAttenuate); - - if (attributesChange) { - _withDiffusion = withDiffusion; - _lastPreDelay = _preDelay; - _lastSoundMsPerMeter = _soundMsPerMeter; - _lastDistanceAttenuationScalingFactor = _distanceAttenuationScalingFactor; - _lastDiffusionFanout = _diffusionFanout; - _lastAbsorptionRatio = _absorptionRatio; - _lastDiffusionRatio = _diffusionRatio; - _lastDontDistanceAttenuate = dontDistanceAttenuate; - _lastAlternateDistanceAttenuate = alternateDistanceAttenuate; - } - - return attributesChange; -} - -void AudioReflector::render() { - - // if we're not set up yet, or we're not processing spatial audio, then exit early - if (!_myAvatar || !_audio->getProcessSpatialAudio()) { - return; - } - - // use this oportunity to calculate our reflections - calculateAllReflections(); - - // only render if we've been asked to do so - bool renderPaths = false; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingRenderPaths) - if (renderPaths) { - drawRays(); - } -} - -// delay = 1ms per foot -// = 3ms per meter -float AudioReflector::getDelayFromDistance(float distance) { - float delay = (_soundMsPerMeter * distance); - bool includePreDelay = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingPreDelay) - if (includePreDelay) { - delay += _preDelay; - } - return delay; -} - -// attenuation = from the Audio Mixer -float AudioReflector::getDistanceAttenuationCoefficient(float distance) { - - - //!Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingDontDistanceAttenuate); - bool doDistanceAttenuation = true; - - //!Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingAlternateDistanceAttenuate); - bool originalFormula = true; - - float distanceCoefficient = 1.0f; - - if (doDistanceAttenuation) { - - if (originalFormula) { - const float DISTANCE_SCALE = 2.5f; - const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; - const float DISTANCE_LOG_BASE = 2.5f; - const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); - - float distanceSquareToSource = distance * distance; - - // calculate the distance coefficient using the distance to this node - distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, - DISTANCE_SCALE_LOG + - (0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); - distanceCoefficient = std::min(1.0f, distanceCoefficient * getDistanceAttenuationScalingFactor()); - } else { - - // From Fred: If we wanted something that would produce a tail that could go up to 5 seconds in a - // really big room, that would suggest the sound still has to be in the audible after traveling about - // 1500 meters. If it’s a sound of average volume, we probably have about 30 db, or 5 base2 orders - // of magnitude we can drop down before the sound becomes inaudible. (That’s approximate headroom - // based on a few sloppy assumptions.) So we could try a factor like 1 / (2^(D/300)) for starters. - // 1 / (2^(D/300)) - const float DISTANCE_BASE = 2.0f; - const float DISTANCE_DENOMINATOR = 300.0f; - const float DISTANCE_NUMERATOR = 300.0f; - distanceCoefficient = DISTANCE_NUMERATOR / powf(DISTANCE_BASE, (distance / DISTANCE_DENOMINATOR )); - distanceCoefficient = std::min(1.0f, distanceCoefficient * getDistanceAttenuationScalingFactor()); - } - } - - return distanceCoefficient; -} - -glm::vec3 AudioReflector::getFaceNormal(BoxFace face) { - // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSlightlyRandomSurfaces); - bool wantSlightRandomness = true; - glm::vec3 faceNormal; - const float MIN_RANDOM_LENGTH = 0.99f; - const float MAX_RANDOM_LENGTH = 1.0f; - const float NON_RANDOM_LENGTH = 1.0f; - float normalLength = wantSlightRandomness ? randFloatInRange(MIN_RANDOM_LENGTH, MAX_RANDOM_LENGTH) : NON_RANDOM_LENGTH; - float remainder = (1.0f - normalLength)/2.0f; - float remainderSignA = randomSign(); - float remainderSignB = randomSign(); - - if (face == MIN_X_FACE) { - faceNormal = glm::vec3(-normalLength, remainder * remainderSignA, remainder * remainderSignB); - } else if (face == MAX_X_FACE) { - faceNormal = glm::vec3(normalLength, remainder * remainderSignA, remainder * remainderSignB); - } else if (face == MIN_Y_FACE) { - faceNormal = glm::vec3(remainder * remainderSignA, -normalLength, remainder * remainderSignB); - } else if (face == MAX_Y_FACE) { - faceNormal = glm::vec3(remainder * remainderSignA, normalLength, remainder * remainderSignB); - } else if (face == MIN_Z_FACE) { - faceNormal = glm::vec3(remainder * remainderSignA, remainder * remainderSignB, -normalLength); - } else if (face == MAX_Z_FACE) { - faceNormal = glm::vec3(remainder * remainderSignA, remainder * remainderSignB, normalLength); - } - return faceNormal; -} - -// set up our buffers for our attenuated and delayed samples -const int NUMBER_OF_CHANNELS = 2; - -void AudioReflector::injectAudiblePoint(AudioSource source, const AudiblePoint& audiblePoint, - const QByteArray& samples, unsigned int sampleTime, int sampleRate) { - - bool wantEarSeparation = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSeparateEars); - bool wantStereo = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingStereoSource); - glm::vec3 rightEarPosition = wantEarSeparation ? _myAvatar->getHead()->getRightEarPosition() : - _myAvatar->getHead()->getPosition(); - glm::vec3 leftEarPosition = wantEarSeparation ? _myAvatar->getHead()->getLeftEarPosition() : - _myAvatar->getHead()->getPosition(); - - int totalNumberOfSamples = samples.size() / sizeof(int16_t); - int totalNumberOfStereoSamples = samples.size() / (sizeof(int16_t) * NUMBER_OF_CHANNELS); - - const int16_t* originalSamplesData = (const int16_t*)samples.constData(); - QByteArray attenuatedLeftSamples; - QByteArray attenuatedRightSamples; - attenuatedLeftSamples.resize(samples.size()); - attenuatedRightSamples.resize(samples.size()); - - int16_t* attenuatedLeftSamplesData = (int16_t*)attenuatedLeftSamples.data(); - int16_t* attenuatedRightSamplesData = (int16_t*)attenuatedRightSamples.data(); - - // calculate the distance to the ears - float rightEarDistance = glm::distance(audiblePoint.location, rightEarPosition); - float leftEarDistance = glm::distance(audiblePoint.location, leftEarPosition); - - float rightEarDelayMsecs = getDelayFromDistance(rightEarDistance) + audiblePoint.delay; - float leftEarDelayMsecs = getDelayFromDistance(leftEarDistance) + audiblePoint.delay; - float averageEarDelayMsecs = (leftEarDelayMsecs + rightEarDelayMsecs) / 2.0f; - - bool safeToInject = true; // assume the best - - // check to see if this new injection point would be within the comb filter - // suppression window for any of the existing known delays - QMap& knownDelays = (source == INBOUND_AUDIO) ? _inboundAudioDelays : _localAudioDelays; - QMap::const_iterator lowerBound = knownDelays.lowerBound(averageEarDelayMsecs - _combFilterWindow); - if (lowerBound != knownDelays.end()) { - float closestFound = lowerBound.value(); - float deltaToClosest = (averageEarDelayMsecs - closestFound); - if (deltaToClosest > -_combFilterWindow && deltaToClosest < _combFilterWindow) { - safeToInject = false; - } - } - - // keep track of any of our suppressed echoes so we can report them in our statistics - if (!safeToInject) { - QVector& suppressedEchoes = (source == INBOUND_AUDIO) ? _inboundEchoesSuppressed : _localEchoesSuppressed; - suppressedEchoes << averageEarDelayMsecs; - } else { - knownDelays[averageEarDelayMsecs] = averageEarDelayMsecs; - - _totalDelay += rightEarDelayMsecs + leftEarDelayMsecs; - _delayCount += 2; - _maxDelay = std::max(_maxDelay,rightEarDelayMsecs); - _maxDelay = std::max(_maxDelay,leftEarDelayMsecs); - _minDelay = std::min(_minDelay,rightEarDelayMsecs); - _minDelay = std::min(_minDelay,leftEarDelayMsecs); - - int rightEarDelay = rightEarDelayMsecs * sampleRate / MSECS_PER_SECOND; - int leftEarDelay = leftEarDelayMsecs * sampleRate / MSECS_PER_SECOND; - - float rightEarAttenuation = audiblePoint.attenuation * - getDistanceAttenuationCoefficient(rightEarDistance + audiblePoint.distance); - - float leftEarAttenuation = audiblePoint.attenuation * - getDistanceAttenuationCoefficient(leftEarDistance + audiblePoint.distance); - - _totalAttenuation += rightEarAttenuation + leftEarAttenuation; - _attenuationCount += 2; - _maxAttenuation = std::max(_maxAttenuation,rightEarAttenuation); - _maxAttenuation = std::max(_maxAttenuation,leftEarAttenuation); - _minAttenuation = std::min(_minAttenuation,rightEarAttenuation); - _minAttenuation = std::min(_minAttenuation,leftEarAttenuation); - - // run through the samples, and attenuate them - for (int sample = 0; sample < totalNumberOfStereoSamples; sample++) { - int16_t leftSample = originalSamplesData[sample * NUMBER_OF_CHANNELS]; - int16_t rightSample = leftSample; - if (wantStereo) { - rightSample = originalSamplesData[(sample * NUMBER_OF_CHANNELS) + 1]; - } - - attenuatedLeftSamplesData[sample * NUMBER_OF_CHANNELS] = - leftSample * leftEarAttenuation * _allEchoesAttenuation; - attenuatedLeftSamplesData[sample * NUMBER_OF_CHANNELS + 1] = 0; - - attenuatedRightSamplesData[sample * NUMBER_OF_CHANNELS] = 0; - attenuatedRightSamplesData[sample * NUMBER_OF_CHANNELS + 1] = - rightSample * rightEarAttenuation * _allEchoesAttenuation; - } - - // now inject the attenuated array with the appropriate delay - unsigned int sampleTimeLeft = sampleTime + leftEarDelay; - unsigned int sampleTimeRight = sampleTime + rightEarDelay; - - _audio->addSpatialAudioToBuffer(sampleTimeLeft, attenuatedLeftSamples, totalNumberOfSamples); - _audio->addSpatialAudioToBuffer(sampleTimeRight, attenuatedRightSamples, totalNumberOfSamples); - - _injectedEchoes++; - } -} - - -void AudioReflector::preProcessOriginalInboundAudio(unsigned int sampleTime, - QByteArray& samples, const QAudioFormat& format) { - - if (_originalSourceAttenuation != 1.0f) { - int numberOfSamples = (samples.size() / sizeof(int16_t)); - int16_t* sampleData = (int16_t*)samples.data(); - for (int i = 0; i < numberOfSamples; i++) { - sampleData[i] = sampleData[i] * _originalSourceAttenuation; - } - } - -} - -void AudioReflector::processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format) { - bool processLocalAudio = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingProcessLocalAudio) - if (processLocalAudio) { - const int NUM_CHANNELS_INPUT = 1; - const int NUM_CHANNELS_OUTPUT = 2; - const int EXPECTED_SAMPLE_RATE = 24000; - if (format.channelCount() == NUM_CHANNELS_INPUT && format.sampleRate() == EXPECTED_SAMPLE_RATE) { - QAudioFormat outputFormat = format; - outputFormat.setChannelCount(NUM_CHANNELS_OUTPUT); - QByteArray stereoInputData(samples.size() * NUM_CHANNELS_OUTPUT, 0); - int numberOfSamples = (samples.size() / sizeof(int16_t)); - int16_t* monoSamples = (int16_t*)samples.data(); - int16_t* stereoSamples = (int16_t*)stereoInputData.data(); - - for (int i = 0; i < numberOfSamples; i++) { - stereoSamples[i* NUM_CHANNELS_OUTPUT] = monoSamples[i] * _localAudioAttenuationFactor; - stereoSamples[(i * NUM_CHANNELS_OUTPUT) + 1] = monoSamples[i] * _localAudioAttenuationFactor; - } - _localAudioDelays.clear(); - _localEchoesSuppressed.clear(); - echoAudio(LOCAL_AUDIO, sampleTime, stereoInputData, outputFormat); - _localEchoesCount = _localAudioDelays.size(); - _localEchoesSuppressedCount = _localEchoesSuppressed.size(); - } - } -} - -void AudioReflector::processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format) { - _inboundAudioDelays.clear(); - _inboundEchoesSuppressed.clear(); - echoAudio(INBOUND_AUDIO, sampleTime, samples, format); - _inboundEchoesCount = _inboundAudioDelays.size(); - _inboundEchoesSuppressedCount = _inboundEchoesSuppressed.size(); -} - -void AudioReflector::echoAudio(AudioSource source, unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format) { - QMutexLocker locker(&_mutex); - - _maxDelay = 0; - _maxAttenuation = 0.0f; - _minDelay = std::numeric_limits::max(); - _minAttenuation = std::numeric_limits::max(); - _totalDelay = 0.0f; - _delayCount = 0; - _totalAttenuation = 0.0f; - _attenuationCount = 0; - - // depending on if we're processing local or external audio, pick the correct points vector - QVector& audiblePoints = source == INBOUND_AUDIO ? _inboundAudiblePoints : _localAudiblePoints; - - int injectCalls = 0; - _injectedEchoes = 0; - foreach(const AudiblePoint& audiblePoint, audiblePoints) { - injectCalls++; - injectAudiblePoint(source, audiblePoint, samples, sampleTime, format.sampleRate()); - } - - /* - qDebug() << "injectCalls=" << injectCalls; - qDebug() << "_injectedEchoes=" << _injectedEchoes; - */ - - _averageDelay = _delayCount == 0 ? 0 : _totalDelay / _delayCount; - _averageAttenuation = _attenuationCount == 0 ? 0 : _totalAttenuation / _attenuationCount; - - if (_reflections == 0) { - _minDelay = 0.0f; - _minAttenuation = 0.0f; - } - - _officialMaxDelay = _maxDelay; - _officialMinDelay = _minDelay; - _officialMaxAttenuation = _maxAttenuation; - _officialMinAttenuation = _minAttenuation; - _officialAverageDelay = _averageDelay; - _officialAverageAttenuation = _averageAttenuation; - -} - -void AudioReflector::drawVector(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color) { - glDisable(GL_LIGHTING); - glLineWidth(2.0); - - // Draw the vector itself - glBegin(GL_LINES); - glColor3f(color.x,color.y,color.z); - glVertex3f(start.x, start.y, start.z); - glVertex3f(end.x, end.y, end.z); - glEnd(); - - glEnable(GL_LIGHTING); -} - - - -AudioPath::AudioPath(AudioSource source, const glm::vec3& origin, const glm::vec3& direction, - float attenuation, float delay, float distance,bool isDiffusion, int bounceCount) : - - source(source), - isDiffusion(isDiffusion), - startPoint(origin), - startDirection(direction), - startDelay(delay), - startAttenuation(attenuation), - - lastPoint(origin), - lastDirection(direction), - lastDistance(distance), - lastDelay(delay), - lastAttenuation(attenuation), - bounceCount(bounceCount), - - finalized(false), - reflections() -{ -} - -void AudioReflector::addAudioPath(AudioSource source, const glm::vec3& origin, const glm::vec3& initialDirection, - float initialAttenuation, float initialDelay, float initialDistance, bool isDiffusion) { - - AudioPath* path = new AudioPath(source, origin, initialDirection, initialAttenuation, initialDelay, - initialDistance, isDiffusion, 0); - - QVector& audioPaths = source == INBOUND_AUDIO ? _inboundAudioPaths : _localAudioPaths; - - audioPaths.push_back(path); -} - -// NOTE: This is a prototype of an eventual utility that will identify the speaking sources for the inbound audio -// stream. It's not currently called but will be added soon. -void AudioReflector::identifyAudioSources() { - // looking for audio sources.... - foreach (const AvatarSharedPointer& avatarPointer, _avatarManager->getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (!avatar->isInitialized()) { - continue; - } - qDebug() << "avatar["<< avatar <<"] loudness:" << avatar->getAudioLoudness(); - } -} - -void AudioReflector::calculateAllReflections() { - // only recalculate when we've moved, or if the attributes have changed - // TODO: what about case where new voxels are added in front of us??? - bool wantHeadOrientation = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingHeadOriented); - glm::quat orientation = wantHeadOrientation ? _myAvatar->getHead()->getFinalOrientationInWorldFrame() : _myAvatar->getOrientation(); - glm::vec3 origin = _myAvatar->getHead()->getPosition(); - glm::vec3 listenerPosition = _myAvatar->getHead()->getPosition(); - - bool shouldRecalc = _reflections == 0 - || !isSimilarPosition(origin, _origin) - || !isSimilarOrientation(orientation, _orientation) - || !isSimilarPosition(listenerPosition, _listenerPosition) - || haveAttributesChanged(); - - if (shouldRecalc) { - QMutexLocker locker(&_mutex); - quint64 start = usecTimestampNow(); - _origin = origin; - _orientation = orientation; - _listenerPosition = listenerPosition; - analyzePaths(); // actually does the work - quint64 end = usecTimestampNow(); - const bool wantDebugging = false; - if (wantDebugging) { - qDebug() << "newCalculateAllReflections() elapsed=" << (end - start); - } - } -} - -void AudioReflector::drawRays() { - const glm::vec3 RED(1,0,0); - const glm::vec3 GREEN(0,1,0); - const glm::vec3 BLUE(0,0,1); - const glm::vec3 CYAN(0,1,1); - - int diffusionNumber = 0; - - QMutexLocker locker(&_mutex); - - // draw the paths for inbound audio - foreach(AudioPath* const& path, _inboundAudioPaths) { - // if this is an original reflection, draw it in RED - if (path->isDiffusion) { - diffusionNumber++; - drawPath(path, GREEN); - } else { - drawPath(path, RED); - } - } - - bool processLocalAudio = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingProcessLocalAudio) - if (processLocalAudio) { - // draw the paths for local audio - foreach(AudioPath* const& path, _localAudioPaths) { - // if this is an original reflection, draw it in RED - if (path->isDiffusion) { - diffusionNumber++; - drawPath(path, CYAN); - } else { - drawPath(path, BLUE); - } - } - } -} - -void AudioReflector::drawPath(AudioPath* path, const glm::vec3& originalColor) { - glm::vec3 start = path->startPoint; - glm::vec3 color = originalColor; - const float COLOR_ADJUST_PER_BOUNCE = 0.75f; - - foreach (glm::vec3 end, path->reflections) { - drawVector(start, end, color); - start = end; - color = color * COLOR_ADJUST_PER_BOUNCE; - } -} - -void AudioReflector::clearPaths() { - // clear our inbound audio paths - foreach(AudioPath* const& path, _inboundAudioPaths) { - delete path; - } - _inboundAudioPaths.clear(); - _inboundAudiblePoints.clear(); // clear our inbound audible points - - // clear our local audio paths - foreach(AudioPath* const& path, _localAudioPaths) { - delete path; - } - _localAudioPaths.clear(); - _localAudiblePoints.clear(); // clear our local audible points -} - -// Here's how this works: we have an array of AudioPaths, we loop on all of our currently calculating audio -// paths, and calculate one ray per path. If that ray doesn't reflect, or reaches a max distance/attenuation, then it -// is considered finalized. -// If the ray hits a surface, then, based on the characteristics of that surface, it will calculate the new -// attenuation, path length, and delay for the primary path. For surfaces that have diffusion, it will also create -// fanout number of new paths, those new paths will have an origin of the reflection point, and an initial attenuation -// of their diffusion ratio. Those new paths will be added to the active audio paths, and be analyzed for the next loop. -void AudioReflector::analyzePaths() { - clearPaths(); - - // add our initial paths - glm::vec3 right = glm::normalize(_orientation * IDENTITY_RIGHT); - glm::vec3 up = glm::normalize(_orientation * IDENTITY_UP); - glm::vec3 front = glm::normalize(_orientation * IDENTITY_FRONT); - glm::vec3 left = -right; - glm::vec3 down = -up; - glm::vec3 back = -front; - glm::vec3 frontRightUp = glm::normalize(front + right + up); - glm::vec3 frontLeftUp = glm::normalize(front + left + up); - glm::vec3 backRightUp = glm::normalize(back + right + up); - glm::vec3 backLeftUp = glm::normalize(back + left + up); - glm::vec3 frontRightDown = glm::normalize(front + right + down); - glm::vec3 frontLeftDown = glm::normalize(front + left + down); - glm::vec3 backRightDown = glm::normalize(back + right + down); - glm::vec3 backLeftDown = glm::normalize(back + left + down); - - float initialAttenuation = 1.0f; - - bool wantPreDelay = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingPreDelay) - float preDelay = wantPreDelay ? _preDelay : 0.0f; - - // NOTE: we're still calculating our initial paths based on the listeners position. But the analysis code has been - // updated to support individual sound sources (which is how we support diffusion), we can use this new paradigm to - // add support for individual sound sources, and more directional sound sources - - addAudioPath(INBOUND_AUDIO, _origin, front, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, right, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, up, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, down, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, back, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, left, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, frontRightUp, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, frontLeftUp, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, backRightUp, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, backLeftUp, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, frontRightDown, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, frontLeftDown, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, backRightDown, initialAttenuation, preDelay); - addAudioPath(INBOUND_AUDIO, _origin, backLeftDown, initialAttenuation, preDelay); - - // the original paths for the local audio are directional to the front of the origin - addAudioPath(LOCAL_AUDIO, _origin, front, initialAttenuation, preDelay); - addAudioPath(LOCAL_AUDIO, _origin, frontRightUp, initialAttenuation, preDelay); - addAudioPath(LOCAL_AUDIO, _origin, frontLeftUp, initialAttenuation, preDelay); - addAudioPath(LOCAL_AUDIO, _origin, frontRightDown, initialAttenuation, preDelay); - addAudioPath(LOCAL_AUDIO, _origin, frontLeftDown, initialAttenuation, preDelay); - - // loop through all our audio paths and keep analyzing them until they complete - int steps = 0; - int acitvePaths = _inboundAudioPaths.size() + _localAudioPaths.size(); // when we start, all paths are active - while(acitvePaths > 0) { - acitvePaths = analyzePathsSingleStep(); - steps++; - } - _reflections = _inboundAudiblePoints.size() + _localAudiblePoints.size(); - _diffusionPathCount = countDiffusionPaths(); -} - -int AudioReflector::countDiffusionPaths() { - int diffusionCount = 0; - - foreach(AudioPath* const& path, _inboundAudioPaths) { - if (path->isDiffusion) { - diffusionCount++; - } - } - foreach(AudioPath* const& path, _localAudioPaths) { - if (path->isDiffusion) { - diffusionCount++; - } - } - return diffusionCount; -} - -int AudioReflector::analyzePathsSingleStep() { - // iterate all the active sound paths, calculate one step per active path - int activePaths = 0; - - QVector* pathsLists[] = { &_inboundAudioPaths, &_localAudioPaths }; - - for(unsigned int i = 0; i < sizeof(pathsLists) / sizeof(pathsLists[0]); i++) { - - QVector& pathList = *pathsLists[i]; - - foreach(AudioPath* const& path, pathList) { - - glm::vec3 start = path->lastPoint; - glm::vec3 direction = path->lastDirection; - OctreeElement* elementHit; // output from findRayIntersection - float distance; // output from findRayIntersection - BoxFace face; // output from findRayIntersection - - if (!path->finalized) { - activePaths++; - - if (path->bounceCount > ABSOLUTE_MAXIMUM_BOUNCE_COUNT) { - path->finalized = true; - } else if (_voxels->findRayIntersection(start, direction, elementHit, distance, face)) { - // TODO: we need to decide how we want to handle locking on the ray intersection, if we force lock, - // we get an accurate picture, but it could prevent rendering of the voxels. If we trylock (default), - // we might not get ray intersections where they may exist, but we can't really detect that case... - // add last parameter of Octree::Lock to force locking - handlePathPoint(path, distance, elementHit, face); - - } else { - // If we didn't intersect, but this was a diffusion ray, then we will go ahead and cast a short ray out - // from our last known point, in the last known direction, and leave that sound source hanging there - if (path->isDiffusion) { - const float MINIMUM_RANDOM_DISTANCE = 0.25f; - const float MAXIMUM_RANDOM_DISTANCE = 0.5f; - float distance = randFloatInRange(MINIMUM_RANDOM_DISTANCE, MAXIMUM_RANDOM_DISTANCE); - handlePathPoint(path, distance, NULL, UNKNOWN_FACE); - } else { - path->finalized = true; // if it doesn't intersect, then it is finished - } - } - } - } - } - return activePaths; -} - -void AudioReflector::handlePathPoint(AudioPath* path, float distance, OctreeElement* elementHit, BoxFace face) { - glm::vec3 start = path->lastPoint; - glm::vec3 direction = path->lastDirection; - glm::vec3 end = start + (direction * (distance * SLIGHTLY_SHORT)); - - float currentReflectiveAttenuation = path->lastAttenuation; // only the reflective components - float currentDelay = path->lastDelay; // start with our delay so far - float pathDistance = path->lastDistance; - - pathDistance += glm::distance(start, end); - - float toListenerDistance = glm::distance(end, _listenerPosition); - - // adjust our current delay by just the delay from the most recent ray - currentDelay += getDelayFromDistance(distance); - - // now we know the current attenuation for the "perfect" reflection case, but we now incorporate - // our surface materials to determine how much of this ray is absorbed, reflected, and diffused - SurfaceCharacteristics material = getSurfaceCharacteristics(elementHit); - - float reflectiveAttenuation = currentReflectiveAttenuation * material.reflectiveRatio; - float totalDiffusionAttenuation = currentReflectiveAttenuation * material.diffusionRatio; - - bool wantDiffusions = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingWithDiffusions); - int fanout = wantDiffusions ? _diffusionFanout : 0; - - float partialDiffusionAttenuation = fanout < 1 ? 0.0f : totalDiffusionAttenuation / (float)fanout; - - // total delay includes the bounce back to listener - float totalDelay = currentDelay + getDelayFromDistance(toListenerDistance); - float toListenerAttenuation = getDistanceAttenuationCoefficient(toListenerDistance + pathDistance); - - // if our resulting partial diffusion attenuation, is still above our minimum attenuation - // then we add new paths for each diffusion point - if ((partialDiffusionAttenuation * toListenerAttenuation) > MINIMUM_ATTENUATION_TO_REFLECT - && totalDelay < MAXIMUM_DELAY_MS) { - - // diffusions fan out from random places on the semisphere of the collision point - for(int i = 0; i < fanout; i++) { - glm::vec3 diffusion; - - // We're creating a random normal here. But we want it to be relatively dramatic compared to how we handle - // our slightly random surface normals. - const float MINIMUM_RANDOM_LENGTH = 0.5f; - const float MAXIMUM_RANDOM_LENGTH = 1.0f; - float randomness = randFloatInRange(MINIMUM_RANDOM_LENGTH, MAXIMUM_RANDOM_LENGTH); - float remainder = (1.0f - randomness)/2.0f; - float remainderSignA = randomSign(); - float remainderSignB = randomSign(); - - if (face == MIN_X_FACE) { - diffusion = glm::vec3(-randomness, remainder * remainderSignA, remainder * remainderSignB); - } else if (face == MAX_X_FACE) { - diffusion = glm::vec3(randomness, remainder * remainderSignA, remainder * remainderSignB); - } else if (face == MIN_Y_FACE) { - diffusion = glm::vec3(remainder * remainderSignA, -randomness, remainder * remainderSignB); - } else if (face == MAX_Y_FACE) { - diffusion = glm::vec3(remainder * remainderSignA, randomness, remainder * remainderSignB); - } else if (face == MIN_Z_FACE) { - diffusion = glm::vec3(remainder * remainderSignA, remainder * remainderSignB, -randomness); - } else if (face == MAX_Z_FACE) { - diffusion = glm::vec3(remainder * remainderSignA, remainder * remainderSignB, randomness); - } else if (face == UNKNOWN_FACE) { - float randomnessX = randFloatInRange(MINIMUM_RANDOM_LENGTH, MAXIMUM_RANDOM_LENGTH); - float randomnessY = randFloatInRange(MINIMUM_RANDOM_LENGTH, MAXIMUM_RANDOM_LENGTH); - float randomnessZ = randFloatInRange(MINIMUM_RANDOM_LENGTH, MAXIMUM_RANDOM_LENGTH); - diffusion = glm::vec3(direction.x * randomnessX, direction.y * randomnessY, direction.z * randomnessZ); - } - - diffusion = glm::normalize(diffusion); - - // add new audio path for these diffusions, the new path's source is the same as the original source - addAudioPath(path->source, end, diffusion, partialDiffusionAttenuation, currentDelay, pathDistance, true); - } - } else { - const bool wantDebugging = false; - if (wantDebugging) { - if ((partialDiffusionAttenuation * toListenerAttenuation) <= MINIMUM_ATTENUATION_TO_REFLECT) { - qDebug() << "too quiet to diffuse"; - qDebug() << " partialDiffusionAttenuation=" << partialDiffusionAttenuation; - qDebug() << " toListenerAttenuation=" << toListenerAttenuation; - qDebug() << " result=" << (partialDiffusionAttenuation * toListenerAttenuation); - qDebug() << " MINIMUM_ATTENUATION_TO_REFLECT=" << MINIMUM_ATTENUATION_TO_REFLECT; - } - if (totalDelay > MAXIMUM_DELAY_MS) { - qDebug() << "too delayed to diffuse"; - qDebug() << " totalDelay=" << totalDelay; - qDebug() << " MAXIMUM_DELAY_MS=" << MAXIMUM_DELAY_MS; - } - } - } - - // if our reflective attenuation is above our minimum, then add our reflection point and - // allow our path to continue - if (((reflectiveAttenuation + totalDiffusionAttenuation) * toListenerAttenuation) > MINIMUM_ATTENUATION_TO_REFLECT - && totalDelay < MAXIMUM_DELAY_MS) { - - // add this location, as the reflective attenuation as well as the total diffusion attenuation - // NOTE: we add the delay to the audible point, not back to the listener. The additional delay - // and attenuation to the listener is recalculated at the point where we actually inject the - // audio so that it can be adjusted to ear position - AudiblePoint point = {end, currentDelay, (reflectiveAttenuation + totalDiffusionAttenuation), pathDistance}; - - QVector& audiblePoints = path->source == INBOUND_AUDIO ? _inboundAudiblePoints : _localAudiblePoints; - - audiblePoints.push_back(point); - - // add this location to the path points, so we can visualize it - path->reflections.push_back(end); - - // now, if our reflective attenuation is over our minimum then keep going... - if (reflectiveAttenuation * toListenerAttenuation > MINIMUM_ATTENUATION_TO_REFLECT) { - glm::vec3 faceNormal = getFaceNormal(face); - path->lastDirection = glm::normalize(glm::reflect(direction,faceNormal)); - path->lastPoint = end; - path->lastAttenuation = reflectiveAttenuation; - path->lastDelay = currentDelay; - path->lastDistance = pathDistance; - path->bounceCount++; - } else { - path->finalized = true; // if we're too quiet, then we're done - } - } else { - const bool wantDebugging = false; - if (wantDebugging) { - if (((reflectiveAttenuation + totalDiffusionAttenuation) * toListenerAttenuation) <= MINIMUM_ATTENUATION_TO_REFLECT) { - qDebug() << "too quiet to add audible point"; - qDebug() << " reflectiveAttenuation + totalDiffusionAttenuation=" << (reflectiveAttenuation + totalDiffusionAttenuation); - qDebug() << " toListenerAttenuation=" << toListenerAttenuation; - qDebug() << " result=" << ((reflectiveAttenuation + totalDiffusionAttenuation) * toListenerAttenuation); - qDebug() << " MINIMUM_ATTENUATION_TO_REFLECT=" << MINIMUM_ATTENUATION_TO_REFLECT; - } - if (totalDelay > MAXIMUM_DELAY_MS) { - qDebug() << "too delayed to add audible point"; - qDebug() << " totalDelay=" << totalDelay; - qDebug() << " MAXIMUM_DELAY_MS=" << MAXIMUM_DELAY_MS; - } - } - path->finalized = true; // if we're too quiet, then we're done - } -} - -// TODO: eventually we will add support for different surface characteristics based on the element -// that is hit, which is why we pass in the elementHit to this helper function. But for now, all -// surfaces have the same characteristics -SurfaceCharacteristics AudioReflector::getSurfaceCharacteristics(OctreeElement* elementHit) { - SurfaceCharacteristics result = { getReflectiveRatio(), _absorptionRatio, _diffusionRatio }; - return result; -} - -void AudioReflector::setReflectiveRatio(float ratio) { - float safeRatio = std::max(0.0f, std::min(ratio, 1.0f)); - float currentReflectiveRatio = (1.0f - (_absorptionRatio + _diffusionRatio)); - float halfDifference = (safeRatio - currentReflectiveRatio) / 2.0f; - - // evenly distribute the difference between the two other ratios - _absorptionRatio -= halfDifference; - _diffusionRatio -= halfDifference; -} - -void AudioReflector::setAbsorptionRatio(float ratio) { - float safeRatio = std::max(0.0f, std::min(ratio, 1.0f)); - _absorptionRatio = safeRatio; - const float MAX_COMBINED_RATIO = 1.0f; - if (_absorptionRatio + _diffusionRatio > MAX_COMBINED_RATIO) { - _diffusionRatio = MAX_COMBINED_RATIO - _absorptionRatio; - } -} - -void AudioReflector::setDiffusionRatio(float ratio) { - float safeRatio = std::max(0.0f, std::min(ratio, 1.0f)); - _diffusionRatio = safeRatio; - const float MAX_COMBINED_RATIO = 1.0f; - if (_absorptionRatio + _diffusionRatio > MAX_COMBINED_RATIO) { - _absorptionRatio = MAX_COMBINED_RATIO - _diffusionRatio; - } -} - diff --git a/interface/src/AudioReflector.h b/interface/src/AudioReflector.h deleted file mode 100644 index 1bfb52ea09..0000000000 --- a/interface/src/AudioReflector.h +++ /dev/null @@ -1,254 +0,0 @@ -// -// AudioReflector.h -// interface -// -// 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 - -#include - -#include - -#include "Audio.h" -#include "avatar/MyAvatar.h" -#include "avatar/AvatarManager.h" - -enum AudioSource { - LOCAL_AUDIO, - INBOUND_AUDIO -}; - -class AudioPath { -public: - AudioPath(AudioSource source = INBOUND_AUDIO, const glm::vec3& origin = glm::vec3(0.0f), - const glm::vec3& direction = glm::vec3(0.0f), float attenuation = 1.0f, - float delay = 0.0f, float distance = 0.0f, bool isDiffusion = false, int bounceCount = 0); - - AudioSource source; - bool isDiffusion; - glm::vec3 startPoint; - glm::vec3 startDirection; - float startDelay; - float startAttenuation; - - glm::vec3 lastPoint; - glm::vec3 lastDirection; - float lastDistance; - float lastDelay; - float lastAttenuation; - unsigned int bounceCount; - - bool finalized; - QVector reflections; -}; - -class AudiblePoint { -public: - glm::vec3 location; /// location of the audible point - float delay; /// includes total delay including pre delay to the point of the audible location, not to the listener's ears - float attenuation; /// only the reflective & diffusive portion of attenuation, doesn't include distance attenuation - float distance; /// includes total distance to the point of the audible location, not to the listener's ears -}; - -class SurfaceCharacteristics { -public: - float reflectiveRatio; - float absorptionRatio; - float diffusionRatio; -}; - -class AudioReflector : public QObject { - Q_OBJECT -public: - AudioReflector(QObject* parent = NULL); - - // setup functions to configure the resources used by the AudioReflector - void setVoxels(VoxelTree* voxels) { _voxels = voxels; } - void setMyAvatar(MyAvatar* myAvatar) { _myAvatar = myAvatar; } - void setAudio(Audio* audio) { _audio = audio; } - void setAvatarManager(AvatarManager* avatarManager) { _avatarManager = avatarManager; } - - void render(); /// must be called in the application render loop - - void preProcessOriginalInboundAudio(unsigned int sampleTime, QByteArray& samples, const QAudioFormat& format); - void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); - void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); - -public slots: - // statistics - int getReflections() const { return _reflections; } - float getAverageDelayMsecs() const { return _officialAverageDelay; } - float getAverageAttenuation() const { return _officialAverageAttenuation; } - float getMaxDelayMsecs() const { return _officialMaxDelay; } - float getMaxAttenuation() const { return _officialMaxAttenuation; } - float getMinDelayMsecs() const { return _officialMinDelay; } - float getMinAttenuation() const { return _officialMinAttenuation; } - float getDelayFromDistance(float distance); - int getDiffusionPathCount() const { return _diffusionPathCount; } - int getEchoesInjected() const { return _inboundEchoesCount + _localEchoesCount; } - int getEchoesSuppressed() const { return _inboundEchoesSuppressedCount + _localEchoesSuppressedCount; } - - /// ms of delay added to all echos - float getPreDelay() const { return _preDelay; } - void setPreDelay(float preDelay) { _preDelay = preDelay; } - - /// ms per meter that sound travels, larger means slower, which sounds bigger - float getSoundMsPerMeter() const { return _soundMsPerMeter; } - void setSoundMsPerMeter(float soundMsPerMeter) { _soundMsPerMeter = soundMsPerMeter; } - - /// scales attenuation to be louder or softer than the default distance attenuation - float getDistanceAttenuationScalingFactor() const { return _distanceAttenuationScalingFactor; } - void setDistanceAttenuationScalingFactor(float factor) { _distanceAttenuationScalingFactor = factor; } - - /// scales attenuation of local audio to be louder or softer than the default attenuation - float getLocalAudioAttenuationFactor() const { return _localAudioAttenuationFactor; } - void setLocalAudioAttenuationFactor(float factor) { _localAudioAttenuationFactor = factor; } - - /// ms window in which we will suppress echoes to reduce comb filter effects - float getCombFilterWindow() const { return _combFilterWindow; } - void setCombFilterWindow(float value) { _combFilterWindow = value; } - - /// number of points of diffusion from each reflection point, as fanout increases there are more chances for secondary - /// echoes, but each diffusion ray is quieter and therefore more likely to be below the sound floor - int getDiffusionFanout() const { return _diffusionFanout; } - void setDiffusionFanout(int fanout) { _diffusionFanout = fanout; } - - /// ratio 0.0 - 1.0 of amount of each ray that is absorbed upon hitting a surface - float getAbsorptionRatio() const { return _absorptionRatio; } - void setAbsorptionRatio(float ratio); - - // ratio 0.0 - 1.0 of amount of each ray that is diffused upon hitting a surface - float getDiffusionRatio() const { return _diffusionRatio; } - void setDiffusionRatio(float ratio); - - // remaining ratio 0.0 - 1.0 of amount of each ray that is cleanly reflected upon hitting a surface - float getReflectiveRatio() const { return (1.0f - (_absorptionRatio + _diffusionRatio)); } - void setReflectiveRatio(float ratio); - - // wet/dry mix - these don't affect any reflection calculations, only the final mix volumes - float getOriginalSourceAttenuation() const { return _originalSourceAttenuation; } - void setOriginalSourceAttenuation(float value) { _originalSourceAttenuation = value; } - float getEchoesAttenuation() const { return _allEchoesAttenuation; } - void setEchoesAttenuation(float value) { _allEchoesAttenuation = value; } - -signals: - -private: - VoxelTree* _voxels; // used to access voxel scene - MyAvatar* _myAvatar; // access to listener - Audio* _audio; // access to audio API - AvatarManager* _avatarManager; // access to avatar manager API - - // Helpers for drawing - void drawVector(const glm::vec3& start, const glm::vec3& end, const glm::vec3& color); - - // helper for generically calculating attenuation based on distance - float getDistanceAttenuationCoefficient(float distance); - - // statistics - int _reflections; - int _diffusionPathCount; - int _delayCount; - float _totalDelay; - float _averageDelay; - float _maxDelay; - float _minDelay; - float _officialAverageDelay; - float _officialMaxDelay; - float _officialMinDelay; - int _attenuationCount; - float _totalAttenuation; - float _averageAttenuation; - float _maxAttenuation; - float _minAttenuation; - float _officialAverageAttenuation; - float _officialMaxAttenuation; - float _officialMinAttenuation; - - - glm::vec3 _listenerPosition; - glm::vec3 _origin; - glm::quat _orientation; - - QVector _inboundAudioPaths; /// audio paths we're processing for inbound audio - QVector _inboundAudiblePoints; /// the audible points that have been calculated from the inbound audio paths - QMap _inboundAudioDelays; /// delay times for currently injected audio points - QVector _inboundEchoesSuppressed; /// delay times for currently injected audio points - int _inboundEchoesCount; - int _inboundEchoesSuppressedCount; - - QVector _localAudioPaths; /// audio paths we're processing for local audio - QVector _localAudiblePoints; /// the audible points that have been calculated from the local audio paths - QMap _localAudioDelays; /// delay times for currently injected audio points - QVector _localEchoesSuppressed; /// delay times for currently injected audio points - int _localEchoesCount; - int _localEchoesSuppressedCount; - - // adds a sound source to begin an audio path trace, these can be the initial sound sources with their directional properties, - // as well as diffusion sound sources - void addAudioPath(AudioSource source, const glm::vec3& origin, const glm::vec3& initialDirection, float initialAttenuation, - float initialDelay, float initialDistance = 0.0f, bool isDiffusion = false); - - // helper that handles audioPath analysis - int analyzePathsSingleStep(); - void handlePathPoint(AudioPath* path, float distance, OctreeElement* elementHit, BoxFace face); - void clearPaths(); - void analyzePaths(); - void drawRays(); - void drawPath(AudioPath* path, const glm::vec3& originalColor); - void calculateAllReflections(); - int countDiffusionPaths(); - glm::vec3 getFaceNormal(BoxFace face); - void identifyAudioSources(); - - void injectAudiblePoint(AudioSource source, const AudiblePoint& audiblePoint, const QByteArray& samples, unsigned int sampleTime, int sampleRate); - void echoAudio(AudioSource source, unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); - - // return the surface characteristics of the element we hit - SurfaceCharacteristics getSurfaceCharacteristics(OctreeElement* elementHit = NULL); - - - QMutex _mutex; - - float _preDelay; - float _soundMsPerMeter; - float _distanceAttenuationScalingFactor; - float _localAudioAttenuationFactor; - float _combFilterWindow; - int _diffusionFanout; // number of points of diffusion from each reflection point - - // all elements have the same material for now... - float _absorptionRatio; - float _diffusionRatio; - float _reflectiveRatio; - - // wet/dry mix - these don't affect any reflection calculations, only the final mix volumes - float _originalSourceAttenuation; /// each sample of original signal will be multiplied by this - float _allEchoesAttenuation; /// each sample of all echo signals will be multiplied by this - - // remember the last known values at calculation - bool haveAttributesChanged(); - - bool _withDiffusion; - float _lastPreDelay; - float _lastSoundMsPerMeter; - float _lastDistanceAttenuationScalingFactor; - float _lastLocalAudioAttenuationFactor; - int _lastDiffusionFanout; - float _lastAbsorptionRatio; - float _lastDiffusionRatio; - bool _lastDontDistanceAttenuate; - bool _lastAlternateDistanceAttenuate; - - int _injectedEchoes; -}; - - -#endif // interface_AudioReflector_h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ae12b5ff26..5e35f08e95 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1303,6 +1303,10 @@ void Menu::bandwidthDetails() { connect(_bandwidthDialog, SIGNAL(closed()), SLOT(bandwidthDetailsClosed())); _bandwidthDialog->show(); + + if (_hmdToolsDialog) { + _hmdToolsDialog->watchWindow(_bandwidthDialog->windowHandle()); + } } _bandwidthDialog->raise(); } @@ -1384,6 +1388,9 @@ void Menu::toggleConsole() { void Menu::toggleToolWindow() { QMainWindow* toolWindow = Application::getInstance()->getToolWindow(); toolWindow->setVisible(!toolWindow->isVisible()); + if (_hmdToolsDialog) { + _hmdToolsDialog->watchWindow(toolWindow->windowHandle()); + } } void Menu::audioMuteToggled() { @@ -1406,6 +1413,9 @@ void Menu::octreeStatsDetails() { Application::getInstance()->getOcteeSceneStats()); connect(_octreeStatsDialog, SIGNAL(closed()), SLOT(octreeStatsDetailsClosed())); _octreeStatsDialog->show(); + if (_hmdToolsDialog) { + _hmdToolsDialog->watchWindow(_octreeStatsDialog->windowHandle()); + } } _octreeStatsDialog->raise(); } @@ -1586,6 +1596,9 @@ void Menu::lodTools() { _lodToolsDialog = new LodToolsDialog(Application::getInstance()->getGLWidget()); connect(_lodToolsDialog, SIGNAL(closed()), SLOT(lodToolsClosed())); _lodToolsDialog->show(); + if (_hmdToolsDialog) { + _hmdToolsDialog->watchWindow(_lodToolsDialog->windowHandle()); + } } _lodToolsDialog->raise(); } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 138828d3e8..e2c687fff1 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -123,7 +123,6 @@ public: LodToolsDialog* getLodToolsDialog() const { return _lodToolsDialog; } HMDToolsDialog* getHMDToolsDialog() const { return _hmdToolsDialog; } int getMaxVoxels() const { return _maxVoxels; } - QAction* getUseVoxelShader() const { return _useVoxelShader; } bool getShadowsEnabled() const; @@ -304,7 +303,6 @@ private: float _avatarLODIncreaseFPS; float _avatarLODDistanceMultiplier; int _boundaryLevelAdjust; - QAction* _useVoxelShader; int _maxVoxelPacketsPerSecond; QString replaceLastOccurrence(QChar search, QChar replace, QString string); quint64 _lastAdjust; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 26f3bd68a3..2ebf7e1146 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -22,6 +22,7 @@ #include #include "renderer/ProgramObject.h" +#include "renderer/TextureCache.h" class HeightfieldBaseLayerBatch; class HeightfieldSplatBatch; diff --git a/interface/src/entities/RenderableTextEntityItem.cpp b/interface/src/entities/RenderableTextEntityItem.cpp index f790f6fa35..4059ee5751 100644 --- a/interface/src/entities/RenderableTextEntityItem.cpp +++ b/interface/src/entities/RenderableTextEntityItem.cpp @@ -63,7 +63,7 @@ void RenderableTextEntityItem::render(RenderArgs* args) { const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 40.0f; // this is a ratio determined through experimentation - // Same font properties as textWidth() + // Same font properties as textSize() TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); float maxHeight = (float)textRenderer->calculateHeight("Xy") * LINE_SCALE_RATIO; diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 2d876a287f..d753901243 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -841,14 +841,14 @@ void GeometryReader::run() { if (urlValid) { // Let's read the binaries from the network - QByteArray fileBinary = _reply->readAll(); - if (fileBinary.isEmpty() || fileBinary.isNull()) { - throw QString("Read File binary is empty?!"); - } - FBXGeometry fbxgeo; if (_url.path().toLower().endsWith(".svo")) { + QByteArray fileBinary = _reply->readAll(); + if (fileBinary.isEmpty() || fileBinary.isNull()) { + throw QString("Read File binary is empty?!"); + } fbxgeo = readSVO(fileBinary); + } else if (_url.path().toLower().endsWith(".fbx")) { bool grabLightmaps = true; float lightmapLevel = 1.0f; @@ -860,7 +860,7 @@ void GeometryReader::run() { } else if (_url.path().toLower().endsWith("palaceoforinthilian4.fbx")) { lightmapLevel = 3.5f; } - fbxgeo = readFBX(fileBinary, _mapping, grabLightmaps, lightmapLevel); + fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel); } QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo)); } else { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 71f5129a1e..fd54f67377 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -134,38 +134,21 @@ void Model::setOffset(const glm::vec3& offset) { _snappedToRegistrationPoint = false; } -void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit) { +void Model::initProgram(ProgramObject& program, Model::Locations& locations, bool link) { + if (link) { + program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); + program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1); + program.link(); + } program.bind(); -#ifdef Q_OS_MAC - - // HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite - - glBindAttribLocation(program.programId(), 4, "tangent"); - - glLinkProgram(program.programId()); - -#endif - - - - glBindAttribLocation(program.programId(), gpu::Stream::TANGENT, "tangent"); - - glBindAttribLocation(program.programId(), gpu::Stream::TEXCOORD1, "texcoord1"); - - glLinkProgram(program.programId()); - locations.tangent = program.attributeLocation("tangent"); locations.alphaThreshold = program.uniformLocation("alphaThreshold"); - locations.texcoordMatrices = program.uniformLocation("texcoordMatrices"); - locations.emissiveParams = program.uniformLocation("emissiveParams"); - program.setUniformValue("diffuseMap", 0); - program.setUniformValue("normalMap", 1); int loc = program.uniformLocation("specularMap"); @@ -184,50 +167,22 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, int locations.emissiveTextureUnit = -1; } - if (!program.isLinked()) { - program.release(); - } - program.release(); - } - - -void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) { - - initProgram(program, locations, specularTextureUnit); - - - -#ifdef Q_OS_MAC - - // HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite - - glBindAttribLocation(program.programId(), 5, "clusterIndices"); - - glBindAttribLocation(program.programId(), 6, "clusterWeights"); - - glLinkProgram(program.programId()); - -#endif - - // HACK: Assign explicitely the attribute channel to avoid a bug on Yosemite - - glBindAttribLocation(program.programId(), gpu::Stream::SKIN_CLUSTER_INDEX, "clusterIndices"); - - glBindAttribLocation(program.programId(), gpu::Stream::SKIN_CLUSTER_WEIGHT, "clusterWeights"); - - glLinkProgram(program.programId()); +void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { + program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); + program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1); + program.bindAttributeLocation("clusterIndices", gpu::Stream::SKIN_CLUSTER_INDEX); + program.bindAttributeLocation("clusterWeights", gpu::Stream::SKIN_CLUSTER_WEIGHT); + program.link(); + + initProgram(program, locations, false); program.bind(); - locations.clusterMatrices = program.uniformLocation("clusterMatrices"); - - - + locations.clusterMatrices = program.uniformLocation("clusterMatrices"); locations.clusterIndices = program.attributeLocation("clusterIndices"); - locations.clusterWeights = program.attributeLocation("clusterWeights"); program.release(); @@ -269,7 +224,6 @@ void Model::init() { if (!_program.isLinked()) { _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); - _program.link(); initProgram(_program, _locations); @@ -277,116 +231,101 @@ void Model::init() { Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); - _normalMapProgram.link(); - + initProgram(_normalMapProgram, _normalMapLocations); _specularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _specularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); - _specularMapProgram.link(); - + initProgram(_specularMapProgram, _specularMapLocations); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_normal_map.vert"); _normalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); - _normalSpecularMapProgram.link(); - - initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations, 2); + + initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); _translucentProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert"); _translucentProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_translucent.frag"); - _translucentProgram.link(); - + initProgram(_translucentProgram, _translucentLocations); // Lightmap _lightmapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_lightmap.vert"); _lightmapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_lightmap.frag"); - _lightmapProgram.link(); - + initProgram(_lightmapProgram, _lightmapLocations); _lightmapNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_lightmap_normal_map.vert"); _lightmapNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_lightmap_normal_map.frag"); - _lightmapNormalMapProgram.link(); - + initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); _lightmapSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_lightmap.vert"); _lightmapSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_lightmap_specular_map.frag"); - _lightmapSpecularMapProgram.link(); - + initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); _lightmapNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_lightmap_normal_map.vert"); _lightmapNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_lightmap_normal_specular_map.frag"); - _lightmapNormalSpecularMapProgram.link(); - - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations, 2); + + initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); // end lightmap _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); - _shadowProgram.link(); - + _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); - _skinProgram.link(); - + initSkinProgram(_skinProgram, _skinLocations); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_map.frag"); - _skinNormalMapProgram.link(); - + initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_specular_map.frag"); - _skinSpecularMapProgram.link(); - + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_normal_map.vert"); _skinNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_normal_specular_map.frag"); - _skinNormalSpecularMapProgram.link(); - - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); + + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model_shadow.vert"); _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_shadow.frag"); - _skinShadowProgram.link(); - + initSkinProgram(_skinShadowProgram, _skinShadowLocations); _skinTranslucentProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinTranslucentProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model_translucent.frag"); - _skinTranslucentProgram.link(); - + initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); } } @@ -600,8 +539,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { float bestDistance = std::numeric_limits::max(); - float bestTriangleDistance = std::numeric_limits::max(); - bool someTriangleHit = false; float distanceToSubMesh; BoxFace subMeshFace; @@ -615,7 +552,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { if (distanceToSubMesh < bestDistance) { if (pickAgainstTriangles) { - someTriangleHit = false; if (!_calculatedMeshTrianglesValid) { recalculateMeshBoxes(pickAgainstTriangles); } @@ -628,9 +564,6 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g float thisTriangleDistance; if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) { if (thisTriangleDistance < bestDistance) { - bestTriangleDistance = thisTriangleDistance; - someTriangleHit = true; - bestDistance = thisTriangleDistance; intersectedSomething = true; face = subMeshFace; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 43b04b7a46..e875c8f06c 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -347,7 +347,7 @@ private: static Locations _lightmapSpecularMapLocations; static Locations _lightmapNormalSpecularMapLocations; - static void initProgram(ProgramObject& program, Locations& locations, int specularTextureUnit = 1); + static void initProgram(ProgramObject& program, Locations& locations, bool link = true); class SkinLocations : public Locations { public: @@ -363,7 +363,7 @@ private: static SkinLocations _skinShadowLocations; static SkinLocations _skinTranslucentLocations; - static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1); + static void initSkinProgram(ProgramObject& program, SkinLocations& locations); QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp deleted file mode 100644 index 68df69f284..0000000000 --- a/interface/src/renderer/PointShader.cpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// PointShader.cpp -// interface/src/renderer -// -// Created by Brad Hefta-Gaub on 10/30/13. -// Copyright 2013 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 -// - -// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - -#include - -#include "Application.h" -#include "PointShader.h" -#include "ProgramObject.h" -#include "RenderUtil.h" - -PointShader::PointShader() - : _initialized(false) -{ - _program = NULL; -} - -PointShader::~PointShader() { - if (_initialized) { - delete _program; - } -} - -ProgramObject* PointShader::createPointShaderProgram(const QString& name) { - ProgramObject* program = new ProgramObject(); - program->addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/" + name + ".vert" ); - program->link(); - return program; -} - -void PointShader::init() { - if (_initialized) { - qDebug("[ERROR] PointShader is already initialized."); - return; - } - _program = createPointShaderProgram("point_size"); - _initialized = true; -} - -void PointShader::begin() { - _program->bind(); -} - -void PointShader::end() { - _program->release(); -} - -int PointShader::attributeLocation(const char* name) const { - if (_program) { - return _program->attributeLocation(name); - } else { - return -1; - } -} - -int PointShader::uniformLocation(const char* name) const { - if (_program) { - return _program->uniformLocation(name); - } else { - return -1; - } -} - -void PointShader::setUniformValue(int uniformLocation, float value) { - _program->setUniformValue(uniformLocation, value); -} - -void PointShader::setUniformValue(int uniformLocation, const glm::vec3& value) { - _program->setUniformValue(uniformLocation, value.x, value.y, value.z); -} diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h deleted file mode 100644 index 1db4f1b201..0000000000 --- a/interface/src/renderer/PointShader.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// PointShader.h -// interface/src/renderer -// -// Created by Brad Hefta-Gaub on 10/30/13. -// Copyright 2013 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 -// - -#ifndef hifi_PointShader_h -#define hifi_PointShader_h - -#include - -class ProgramObject; - -/// A shader program that draws voxels as points with variable sizes -class PointShader : public QObject { - Q_OBJECT - -public: - PointShader(); - ~PointShader(); - - void init(); - - /// Starts using the voxel point shader program. - void begin(); - - /// Stops using the voxel point shader program. - void end(); - - /// Gets access to attributes from the shader program - int attributeLocation(const char* name) const; - int uniformLocation(const char* name) const; - void setUniformValue(int uniformLocation, float value); - void setUniformValue(int uniformLocation, const glm::vec3& value); - - static ProgramObject* createPointShaderProgram(const QString& name); - -private: - bool _initialized; - ProgramObject* _program; -}; - -#endif // hifi_PointShader_h diff --git a/interface/src/renderer/VoxelShader.cpp b/interface/src/renderer/VoxelShader.cpp deleted file mode 100644 index 0982304adf..0000000000 --- a/interface/src/renderer/VoxelShader.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// VoxelShader.cpp -// interface/src/renderer -// -// Created by Brad Hefta-Gaub on 9/22/13. -// Copyright 2013 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 -// - -// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL -#include "InterfaceConfig.h" - -#include - -#include "Application.h" -#include "VoxelShader.h" -#include "ProgramObject.h" -#include "RenderUtil.h" - -VoxelShader::VoxelShader() - : _initialized(false) -{ - _program = NULL; -} - -VoxelShader::~VoxelShader() { - if (_initialized) { - delete _program; - } -} - -ProgramObject* VoxelShader::createGeometryShaderProgram(const QString& name) { - ProgramObject* program = new ProgramObject(); - program->addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/passthrough.vert" ); - program->addShaderFromSourceFile(QGLShader::Geometry, Application::resourcesPath() + "shaders/" + name + ".geom" ); - program->setGeometryInputType(GL_POINTS); - program->setGeometryOutputType(GL_TRIANGLE_STRIP); - const int VERTICES_PER_FACE = 4; - const int FACES_PER_VOXEL = 6; - const int VERTICES_PER_VOXEL = VERTICES_PER_FACE * FACES_PER_VOXEL; - program->setGeometryOutputVertexCount(VERTICES_PER_VOXEL); - program->link(); - return program; -} - -void VoxelShader::init() { - if (_initialized) { - qDebug("[ERROR] TestProgram is already initialized."); - return; - } - - _program = createGeometryShaderProgram("voxel"); - _initialized = true; -} - -void VoxelShader::begin() { - _program->bind(); -} - -void VoxelShader::end() { - _program->release(); -} - -int VoxelShader::attributeLocation(const char * name) const { - if (_program) { - return _program->attributeLocation(name); - } else { - return -1; - } -} - diff --git a/interface/src/renderer/VoxelShader.h b/interface/src/renderer/VoxelShader.h deleted file mode 100644 index cfcd27bba7..0000000000 --- a/interface/src/renderer/VoxelShader.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// VoxelShader.h -// interface/src/renderer -// -// Created by Brad Hefta-Gaub on 9/23/13. -// Copyright 2013 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 -// - -#ifndef hifi_VoxelShader_h -#define hifi_VoxelShader_h - -#include - -class ProgramObject; - -/// A generic full screen glow effect. -class VoxelShader : public QObject { - Q_OBJECT - -public: - VoxelShader(); - ~VoxelShader(); - - void init(); - - /// Starts using the voxel geometry shader effect. - void begin(); - - /// Stops using the voxel geometry shader effect. - void end(); - - /// Gets access to attributes from the shader program - int attributeLocation(const char * name) const; - - static ProgramObject* createGeometryShaderProgram(const QString& name); - -public slots: - -private: - - bool _initialized; - - ProgramObject* _program; -}; - -#endif // hifi_VoxelShader_h diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 7869926ebe..747b4ae68d 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -124,7 +124,7 @@ void ChatWindow::showEvent(QShowEvent* event) { if (!event->spontaneous()) { _ui->messagePlainTextEdit->setFocus(); } - const QRect parentGeometry = parentWidget()->geometry(); + QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); int menuBarHeight = Menu::getInstance()->geometry().height(); int topMargin = titleBarHeight + menuBarHeight; diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp index ab997a0a75..280354d974 100644 --- a/interface/src/ui/FramelessDialog.cpp +++ b/interface/src/ui/FramelessDialog.cpp @@ -9,8 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include + #include "Application.h" #include "FramelessDialog.h" +#include "Menu.h" const int RESIZE_HANDLE_WIDTH = 7; @@ -90,24 +94,27 @@ void FramelessDialog::showEvent(QShowEvent* event) { } void FramelessDialog::resizeAndPosition(bool resizeParent) { + QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); + QSize parentSize = parentGeometry.size(); + // keep full app height or width depending on position if (_position == POSITION_LEFT || _position == POSITION_RIGHT) { - setFixedHeight(parentWidget()->size().height()); + setFixedHeight(parentSize.height()); } else { - setFixedWidth(parentWidget()->size().width()); + setFixedWidth(parentSize.width()); } // resize parrent if width is smaller than this dialog - if (resizeParent && parentWidget()->size().width() < size().width()) { - parentWidget()->resize(size().width(), parentWidget()->size().height()); + if (resizeParent && parentSize.width() < size().width()) { + parentWidget()->resize(size().width(), parentSize.height()); } if (_position == POSITION_LEFT || _position == POSITION_TOP) { // move to upper left corner - move(parentWidget()->geometry().topLeft()); + move(parentGeometry.topLeft()); } else if (_position == POSITION_RIGHT) { // move to upper right corner - QPoint pos = parentWidget()->geometry().topRight(); + QPoint pos = parentGeometry.topRight(); pos.setX(pos.x() - size().width()); move(pos); } diff --git a/interface/src/ui/HMDToolsDialog.cpp b/interface/src/ui/HMDToolsDialog.cpp index 88924f68d1..ab84980d80 100644 --- a/interface/src/ui/HMDToolsDialog.cpp +++ b/interface/src/ui/HMDToolsDialog.cpp @@ -67,83 +67,41 @@ HMDToolsDialog::HMDToolsDialog(QWidget* parent) : // watch for our dialog window moving screens. If it does we want to enforce our rules about // what screens we're allowed on - QWindow* dialogWindow = windowHandle(); - connect(dialogWindow, &QWindow::screenChanged, this, &HMDToolsDialog::dialogWindowScreenChanged); - connect(dialogWindow, &QWindow::xChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged); - connect(dialogWindow, &QWindow::yChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged); - connect(dialogWindow, &QWindow::widthChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged); - connect(dialogWindow, &QWindow::heightChanged, this, &HMDToolsDialog::dialogWindowGeometryChanged); + watchWindow(windowHandle()); + if (Application::getInstance()->getRunningScriptsWidget()) { + watchWindow(Application::getInstance()->getRunningScriptsWidget()->windowHandle()); + } + if (Application::getInstance()->getToolWindow()) { + watchWindow(Application::getInstance()->getToolWindow()->windowHandle()); + } + if (Menu::getInstance()->getBandwidthDialog()) { + watchWindow(Menu::getInstance()->getBandwidthDialog()->windowHandle()); + } + if (Menu::getInstance()->getOctreeStatsDialog()) { + watchWindow(Menu::getInstance()->getOctreeStatsDialog()->windowHandle()); + } + if (Menu::getInstance()->getLodToolsDialog()) { + watchWindow(Menu::getInstance()->getLodToolsDialog()->windowHandle()); + } // when the application is about to quit, leave HDM mode connect(Application::getInstance(), SIGNAL(aboutToQuit()), this, SLOT(aboutToQuit())); // keep track of changes to the number of screens connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &HMDToolsDialog::screenCountChanged); - } HMDToolsDialog::~HMDToolsDialog() { + foreach(HMDWindowWatcher* watcher, _windowWatchers) { + delete watcher; + } + _windowWatchers.clear(); } void HMDToolsDialog::applicationWindowScreenChanged(QScreen* screen) { _debugDetails->setText(getDebugDetails()); } -void HMDToolsDialog::dialogWindowGeometryChanged(int arg) { - QWindow* dialogWindow = windowHandle(); - _previousDialogRect = rect(); - _previousDialogRect = QRect(dialogWindow->mapToGlobal(_previousDialogRect.topLeft()), - dialogWindow->mapToGlobal(_previousDialogRect.bottomRight())); - _previousDialogScreen = dialogWindow->screen(); -} - -void HMDToolsDialog::dialogWindowScreenChanged(QScreen* screen) { - _debugDetails->setText(getDebugDetails()); - - // if we have more than one screen, and a known hmdScreen then try to - // keep our dialog off of the hmdScreen - if (QApplication::desktop()->screenCount() > 1) { - - // we want to use a local variable here because we are not necesarily in HMD mode - int hmdScreenNumber = OculusManager::getHMDScreen(); - if (_hmdScreenNumber >= 0) { - QScreen* hmdScreen = QGuiApplication::screens()[hmdScreenNumber]; - if (screen == hmdScreen) { - qDebug() << "HMD Tools: Whoa! What are you doing? You don't want to move me to the HMD Screen!"; - QWindow* dialogWindow = windowHandle(); - - // try to pick a better screen - QScreen* betterScreen = NULL; - - QWindow* appWindow = Application::getInstance()->getWindow()->windowHandle(); - QScreen* appScreen = appWindow->screen(); - - if (_previousDialogScreen && _previousDialogScreen != hmdScreen) { - // first, if the previous dialog screen is not the HMD screen, then move it there. - betterScreen = appScreen; - } else if (appScreen != hmdScreen) { - // second, if the application screen is not the HMD screen, then move it there. - betterScreen = appScreen; - } else if (_previousScreen && _previousScreen != hmdScreen) { - // third, if the application screen is the HMD screen, we want to move it to - // the previous screen - betterScreen = _previousScreen; - } else { - // last, if we can't use the previous screen the use the primary desktop screen - int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen(); - QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber]; - betterScreen = desktopPrimaryScreen; - } - - if (betterScreen) { - dialogWindow->setScreen(betterScreen); - dialogWindow->setGeometry(_previousDialogRect); - } - } - } - } -} - QString HMDToolsDialog::getDebugDetails() const { QString results; @@ -305,5 +263,79 @@ void HMDToolsDialog::screenCountChanged(int newCount) { _debugDetails->setText(getDebugDetails()); } +void HMDToolsDialog::watchWindow(QWindow* window) { + qDebug() << "HMDToolsDialog::watchWindow() window:" << window; + if (window && !_windowWatchers.contains(window)) { + HMDWindowWatcher* watcher = new HMDWindowWatcher(window, this); + _windowWatchers[window] = watcher; + } +} + + +HMDWindowWatcher::HMDWindowWatcher(QWindow* window, HMDToolsDialog* hmdTools) : + _window(window), + _hmdTools(hmdTools), + _previousScreen(NULL) +{ + connect(window, &QWindow::screenChanged, this, &HMDWindowWatcher::windowScreenChanged); + connect(window, &QWindow::xChanged, this, &HMDWindowWatcher::windowGeometryChanged); + connect(window, &QWindow::yChanged, this, &HMDWindowWatcher::windowGeometryChanged); + connect(window, &QWindow::widthChanged, this, &HMDWindowWatcher::windowGeometryChanged); + connect(window, &QWindow::heightChanged, this, &HMDWindowWatcher::windowGeometryChanged); +} + +HMDWindowWatcher::~HMDWindowWatcher() { +} + + +void HMDWindowWatcher::windowGeometryChanged(int arg) { + _previousRect = _window->geometry(); + _previousScreen = _window->screen(); +} + +void HMDWindowWatcher::windowScreenChanged(QScreen* screen) { + // if we have more than one screen, and a known hmdScreen then try to + // keep our dialog off of the hmdScreen + if (QApplication::desktop()->screenCount() > 1) { + + // we want to use a local variable here because we are not necesarily in HMD mode + int hmdScreenNumber = OculusManager::getHMDScreen(); + if (hmdScreenNumber >= 0) { + QScreen* hmdScreen = QGuiApplication::screens()[hmdScreenNumber]; + if (screen == hmdScreen) { + qDebug() << "HMD Tools: Whoa! What are you doing? You don't want to move me to the HMD Screen!"; + + // try to pick a better screen + QScreen* betterScreen = NULL; + + QScreen* lastApplicationScreen = _hmdTools->getLastApplicationScreen(); + QWindow* appWindow = Application::getInstance()->getWindow()->windowHandle(); + QScreen* appScreen = appWindow->screen(); + + if (_previousScreen && _previousScreen != hmdScreen) { + // first, if the previous dialog screen is not the HMD screen, then move it there. + betterScreen = _previousScreen; + } else if (appScreen != hmdScreen) { + // second, if the application screen is not the HMD screen, then move it there. + betterScreen = appScreen; + } else if (lastApplicationScreen && lastApplicationScreen != hmdScreen) { + // third, if the application screen is the HMD screen, we want to move it to + // the previous screen + betterScreen = lastApplicationScreen; + } else { + // last, if we can't use the previous screen the use the primary desktop screen + int desktopPrimaryScreenNumber = QApplication::desktop()->primaryScreen(); + QScreen* desktopPrimaryScreen = QGuiApplication::screens()[desktopPrimaryScreenNumber]; + betterScreen = desktopPrimaryScreen; + } + + if (betterScreen) { + _window->setScreen(betterScreen); + _window->setGeometry(_previousRect); + } + } + } + } +} diff --git a/interface/src/ui/HMDToolsDialog.h b/interface/src/ui/HMDToolsDialog.h index e3e5573533..10dc1c5c80 100644 --- a/interface/src/ui/HMDToolsDialog.h +++ b/interface/src/ui/HMDToolsDialog.h @@ -14,6 +14,8 @@ #include +class HMDWindowWatcher; + class HMDToolsDialog : public QDialog { Q_OBJECT public: @@ -22,6 +24,10 @@ public: ~HMDToolsDialog(); QString getDebugDetails() const; + QScreen* getHMDScreen() const { return _hmdScreen; } + QScreen* getLastApplicationScreen() const { return _previousScreen; } + bool hasHMDScreen() const { return _hmdScreenNumber >= -1; } + void watchWindow(QWindow* window); signals: void closed(); @@ -32,8 +38,6 @@ public slots: void activateWindowAfterEnterMode(); void moveWindowAfterLeaveMode(); void applicationWindowScreenChanged(QScreen* screen); - void dialogWindowScreenChanged(QScreen* screen); - void dialogWindowGeometryChanged(int arg); void aboutToQuit(); void screenCountChanged(int newCount); @@ -58,6 +62,27 @@ private: QRect _previousDialogRect; QScreen* _previousDialogScreen; bool _inHDMMode; + + QHash _windowWatchers; +}; + + +class HMDWindowWatcher : public QObject { + Q_OBJECT +public: + // Sets up the UI + HMDWindowWatcher(QWindow* window, HMDToolsDialog* hmdTools); + ~HMDWindowWatcher(); + +public slots: + void windowScreenChanged(QScreen* screen); + void windowGeometryChanged(int arg); + +private: + QWindow* _window; + HMDToolsDialog* _hmdTools; + QRect _previousRect; + QScreen* _previousScreen; }; #endif // hifi_HMDToolsDialog_h diff --git a/interface/src/ui/RunningScriptsWidget.cpp b/interface/src/ui/RunningScriptsWidget.cpp index 29c004bdb7..cfd7428482 100644 --- a/interface/src/ui/RunningScriptsWidget.cpp +++ b/interface/src/ui/RunningScriptsWidget.cpp @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include "Application.h" #include "Menu.h" @@ -82,10 +84,6 @@ void RunningScriptsWidget::loadSelectedScript() { } } -void RunningScriptsWidget::setBoundary(const QRect& rect) { - _boundary = rect; -} - void RunningScriptsWidget::setRunningScripts(const QStringList& list) { setUpdatesEnabled(false); QLayoutItem* widget; @@ -153,7 +151,7 @@ void RunningScriptsWidget::showEvent(QShowEvent* event) { ui->filterLineEdit->setFocus(); } - const QRect parentGeometry = parentWidget()->geometry(); + QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry(); int titleBarHeight = UIUtil::getWindowTitleBarHeight(this); int menuBarHeight = Menu::getInstance()->geometry().height(); int topMargin = titleBarHeight + menuBarHeight; diff --git a/interface/src/ui/RunningScriptsWidget.h b/interface/src/ui/RunningScriptsWidget.h index 7493a1a5ce..69833a890b 100644 --- a/interface/src/ui/RunningScriptsWidget.h +++ b/interface/src/ui/RunningScriptsWidget.h @@ -18,7 +18,6 @@ #include #include "ScriptsModel.h" -#include "FramelessDialog.h" #include "ScriptsTableWidget.h" namespace Ui { @@ -44,7 +43,6 @@ protected: public slots: void scriptStopped(const QString& scriptName); - void setBoundary(const QRect& rect); private slots: void allScriptsStopped(); @@ -61,7 +59,6 @@ private: ScriptsTableWidget* _recentlyLoadedScriptsTable; QStringList _recentlyLoadedScripts; QString _lastStoppedScript; - QRect _boundary; }; #endif // hifi_RunningScriptsWidget_h diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index d0a25f4f4a..9abb3d1b78 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -477,10 +477,6 @@ void Stats::display( VoxelSystem* voxels = Application::getInstance()->getVoxels(); lines = _expanded ? 14 : 3; - bool wantSpatialProcessing = false; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing) - if (_expanded && wantSpatialProcessing) { - lines += 10; // spatial audio processing adds 1 spacing line and 8 extra lines of info - } drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); @@ -669,104 +665,6 @@ void Stats::display( verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color); } - - if (_expanded && wantSpatialProcessing) { - verticalOffset += STATS_PELS_PER_LINE; // space one line... - - const AudioReflector* audioReflector = Application::getInstance()->getAudioReflector(); - - // add some reflection stats - char reflectionsStatus[128]; - - bool includeOriginal = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingIncludeOriginal) - bool separateEars = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSeparateEars) - bool stereoSource = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingStereoSource) - bool randomSurfaces = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingSlightlyRandomSurfaces) - - sprintf(reflectionsStatus, "Reflections: %d, Original: %s, Ears: %s, Source: %s, Normals: %s", - audioReflector->getReflections(), - (includeOriginal ? "included" : "silent"), - (separateEars ? "two" : "one"), - (stereoSource ? "stereo" : "mono"), - (randomSurfaces ? "random" : "regular") - ); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - bool wantPreDelay = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingPreDelay) - float preDelay = wantPreDelay ? audioReflector->getPreDelay() : 0.0f; - - sprintf(reflectionsStatus, "Delay: pre: %6.3f, average %6.3f, max %6.3f, min %6.3f, speed: %6.3f", - preDelay, - audioReflector->getAverageDelayMsecs(), - audioReflector->getMaxDelayMsecs(), - audioReflector->getMinDelayMsecs(), - audioReflector->getSoundMsPerMeter()); - - verticalOffset += STATS_PELS_PER_LINE; - - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingDontDistanceAttenuate); - bool distanceAttenuationDisabled = false; - - // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingAlternateDistanceAttenuate); - bool alternateDistanceAttenuationEnabled = false; - - sprintf(reflectionsStatus, "Attenuation: average %5.3f, max %5.3f, min %5.3f, %s: %5.3f", - audioReflector->getAverageAttenuation(), - audioReflector->getMaxAttenuation(), - audioReflector->getMinAttenuation(), - (distanceAttenuationDisabled ? "Distance Factor [DISABLED]" : - alternateDistanceAttenuationEnabled ? "Distance Factor [ALTERNATE]" : "Distance Factor [STANARD]"), - audioReflector->getDistanceAttenuationScalingFactor()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - bool localAudio = true; // Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingProcessLocalAudio); - sprintf(reflectionsStatus, "Local Audio: %s Attenuation: %5.3f", (localAudio ? "yes" : "no"), - audioReflector->getLocalAudioAttenuationFactor()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - bool diffusionEnabled = true; //Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessingWithDiffusions); - int fanout = diffusionEnabled ? audioReflector->getDiffusionFanout() : 0; - int diffusionPaths = diffusionEnabled ? audioReflector->getDiffusionPathCount() : 0; - sprintf(reflectionsStatus, "Diffusion: %s, Fanout: %d, Paths: %d", - (diffusionEnabled ? "yes" : "no"), fanout, diffusionPaths); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - const float AS_PERCENT = 100.0f; - float reflectiveRatio = audioReflector->getReflectiveRatio() * AS_PERCENT; - float diffusionRatio = audioReflector->getDiffusionRatio() * AS_PERCENT; - float absorptionRatio = audioReflector->getAbsorptionRatio() * AS_PERCENT; - sprintf(reflectionsStatus, "Ratios: Reflective: %5.3f, Diffusion: %5.3f, Absorption: %5.3f", - reflectiveRatio, diffusionRatio, absorptionRatio); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - sprintf(reflectionsStatus, "Comb Filter Window: %5.3f ms, Allowed: %d, Suppressed: %d", - audioReflector->getCombFilterWindow(), - audioReflector->getEchoesInjected(), - audioReflector->getEchoesSuppressed()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, scale, rotation, font, reflectionsStatus, color); - - sprintf(reflectionsStatus, "Wet/Dry Mix: Original: %5.3f Echoes: %5.3f", - audioReflector->getOriginalSourceAttenuation(), - audioReflector->getEchoesAttenuation()); - - verticalOffset += STATS_PELS_PER_LINE; - drawText(horizontalOffset, verticalOffset, 0.10f, 0.0f, 2.0f, reflectionsStatus, color); - - } } void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress, diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 25e667e56c..ace4ecf353 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -432,19 +432,19 @@ bool Overlays::isLoaded(unsigned int id) { return thisOverlay->isLoaded(); } -float Overlays::textWidth(unsigned int id, const QString& text) const { +QSizeF Overlays::textSize(unsigned int id, const QString& text) const { Overlay* thisOverlay = _overlays2D[id]; if (thisOverlay) { if (typeid(*thisOverlay) == typeid(TextOverlay)) { - return static_cast(thisOverlay)->textWidth(text); + return static_cast(thisOverlay)->textSize(text); } } else { thisOverlay = _overlays3D[id]; if (thisOverlay) { if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { - return static_cast(thisOverlay)->textWidth(text); + return static_cast(thisOverlay)->textSize(text); } } } - return 0.0f; + return QSizeF(0.0f, 0.0f); } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 7acc2c7878..fb2c936a64 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -85,9 +85,9 @@ public slots: /// returns whether the overlay's assets are loaded or not bool isLoaded(unsigned int id); - /// returns the width of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text + /// returns the size of the given text in the specified overlay if it is a text overlay: in pixels if it is a 2D text /// overlay; in meters if it is a 3D text overlay - float textWidth(unsigned int id, const QString& text) const; + QSizeF textSize(unsigned int id, const QString& text) const; private: QMap _overlays2D; diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 2e80fae8a0..41e36cb396 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -108,7 +108,7 @@ void Text3DOverlay::render(RenderArgs* args) { const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 40.0f; // this is a ratio determined through experimentation - // Same font properties as textWidth() + // Same font properties as textSize() TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); float maxHeight = (float)textRenderer->calculateHeight("Xy") * LINE_SCALE_RATIO; @@ -236,11 +236,23 @@ Text3DOverlay* Text3DOverlay::createClone() const { return new Text3DOverlay(this);; } -float Text3DOverlay::textWidth(const QString& text) const { +QSizeF Text3DOverlay::textSize(const QString& text) const { + QFont font(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); // Same font properties as render() QFontMetrics fontMetrics(font); - float scaleFactor = _lineHeight * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE; - return scaleFactor * (float)fontMetrics.width(qPrintable(text)); + const float TEXT_SCALE_ADJUST = 1.02f; // Experimentally detemined for the specified font + const int TEXT_HEIGHT_ADJUST = -6; + float scaleFactor = _lineHeight * TEXT_SCALE_ADJUST * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE; + + QStringList lines = text.split(QRegExp("\r\n|\r|\n")); + + float width = 0.0f; + for (int i = 0; i < lines.count(); i += 1) { + width = std::max(width, scaleFactor * (float)fontMetrics.width(qPrintable(lines[i]))); + } + + float height = lines.count() * scaleFactor * (float)(fontMetrics.height() + TEXT_HEIGHT_ADJUST); + + return QSizeF(width, height); } - diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index d74131391a..aefda852db 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -51,7 +51,7 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - float textWidth(const QString& text) const; // Meters + QSizeF textSize(const QString& test) const; // Meters virtual Text3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 272c9bc916..ae8a7cbcfe 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -77,7 +77,7 @@ void TextOverlay::render(RenderArgs* args) { glVertex2f(_bounds.left(), _bounds.bottom()); glEnd(); - // Same font properties as textWidth() + // Same font properties as textSize() TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); const int leftAdjust = -1; // required to make text render relative to left edge of bounds @@ -169,8 +169,20 @@ QScriptValue TextOverlay::getProperty(const QString& property) { return Overlay2D::getProperty(property); } -float TextOverlay::textWidth(const QString& text) const { +QSizeF TextOverlay::textSize(const QString& text) const { + QFont font(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); // Same font properties as render() QFontMetrics fontMetrics(font); - return fontMetrics.width(qPrintable(text)); + const int TEXT_HEIGHT_ADJUST = -2; // Experimentally determined for the specified font + + QStringList lines = text.split(QRegExp("\r\n|\r|\n")); + + int width = 0; + for (int i = 0; i < lines.count(); i += 1) { + width = std::max(width, fontMetrics.width(qPrintable(lines[i]))); + } + + int height = lines.count() * (fontMetrics.height() + TEXT_HEIGHT_ADJUST); + + return QSizeF(width, height); } diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 754faea2bc..793d705d3c 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -59,7 +59,7 @@ public: virtual TextOverlay* createClone() const; virtual QScriptValue getProperty(const QString& property); - float textWidth(const QString& text) const; // Pixels + QSizeF textSize(const QString& test) const; // Pixels private: QString _text; diff --git a/interface/src/voxels/PrimitiveRenderer.cpp b/interface/src/voxels/PrimitiveRenderer.cpp deleted file mode 100644 index a212245289..0000000000 --- a/interface/src/voxels/PrimitiveRenderer.cpp +++ /dev/null @@ -1,742 +0,0 @@ -// -// PrimitiveRenderer.cpp -// interface/src/voxels -// -// 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 -// - -#include - -#include "InterfaceConfig.h" -#include "OctreeElement.h" -#include "PrimitiveRenderer.h" - -Primitive::Primitive() { -} - -Primitive::~Primitive() { -} - -// Simple dispatch between API and SPI - -const VertexElementList& Primitive::vertexElements() const { - return vVertexElements(); -} - -VertexElementIndexList& Primitive::vertexElementIndices() { - return vVertexElementIndices(); -} - -TriElementList& Primitive::triElements() { - return vTriElements(); -} - -void Primitive::releaseVertexElements() { - vReleaseVertexElements(); -} - -unsigned long Primitive::getMemoryUsage() { - return vGetMemoryUsage(); -} - - -Cube::Cube( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) : - _cpuMemoryUsage(0) { - init(x, y, z, s, r, g, b, faceExclusions); -} - -Cube::~Cube() { - terminate(); -} - -void Cube::init( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) { - - initializeVertices(x, y, z, s, r, g, b, faceExclusions); - initializeTris(faceExclusions); -} - -void Cube::terminate() { - - terminateTris(); - terminateVertices(); -} - -void Cube::initializeVertices( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) { - - for (int i = 0; i < _sNumVerticesPerCube; i++) { - // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { - // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { - // uncomment this line to exclude shared faces: - if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { - - VertexElement* v = new VertexElement(); - if (v) { - // Construct vertex position - v->position.x = x + s * _sVertexIndexToConstructionVector[i][0]; - v->position.y = y + s * _sVertexIndexToConstructionVector[i][1]; - v->position.z = z + s * _sVertexIndexToConstructionVector[i][2]; - - // Construct vertex normal - v->normal.x = _sVertexIndexToNormalVector[i >> 2][0]; - v->normal.y = _sVertexIndexToNormalVector[i >> 2][1]; - v->normal.z = _sVertexIndexToNormalVector[i >> 2][2]; - - // Construct vertex color -//#define FALSE_COLOR -#ifndef FALSE_COLOR - v->color.r = r; - v->color.g = g; - v->color.b = b; - v->color.a = 255; -#else - static unsigned char falseColor[6][3] = { - 192, 0, 0, // Bot - 0, 192, 0, // Top - 0, 0, 192, // Right - 192, 0, 192, // Left - 192, 192, 0, // Near - 192, 192, 192 // Far - }; - v->color.r = falseColor[i >> 2][0]; - v->color.g = falseColor[i >> 2][1]; - v->color.b = falseColor[i >> 2][2]; - v->color.a = 255; -#endif - - // Add vertex element to list - _vertices.push_back(v); - _cpuMemoryUsage += sizeof(VertexElement); - _cpuMemoryUsage += sizeof(VertexElement*); - } - } - } -} - -void Cube::terminateVertices() { - - for (VertexElementList::iterator it = _vertices.begin(); it != _vertices.end(); ++it) { - delete *it; - } - _cpuMemoryUsage -= _vertices.size() * (sizeof(VertexElement) + sizeof(VertexElement*)); - _vertices.clear(); -} - -void Cube::initializeTris( - unsigned char faceExclusions - ) { - - int index = 0; - for (int i = 0; i < _sNumFacesPerCube; i++) { - // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i]) { - // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { - // uncomment this line to exclude shared faces: - if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { - - int start = index; - // Create the triangulated face, two tris, six indices referencing four vertices, both - // with cw winding order, such that: - - // A-B - // |\| - // D-C - - // Store triangle ABC - - TriElement* tri = new TriElement(); - if (tri) { - tri->indices[0] = index++; - tri->indices[1] = index++; - tri->indices[2] = index; - - // Add tri element to list - _tris.push_back(tri); - _cpuMemoryUsage += sizeof(TriElement); - _cpuMemoryUsage += sizeof(TriElement*); - } - - // Now store triangle ACD - tri = new TriElement(); - if (tri) { - tri->indices[0] = start; - tri->indices[1] = index++; - tri->indices[2] = index++; - - // Add tri element to list - _tris.push_back(tri); - _cpuMemoryUsage += sizeof(TriElement); - _cpuMemoryUsage += sizeof(TriElement*); - } - } - } -} - -void Cube::terminateTris() { - - for (TriElementList::iterator it = _tris.begin(); it != _tris.end(); ++it) { - delete *it; - } - _cpuMemoryUsage -= _tris.size() * (sizeof(TriElement) + sizeof(TriElement*)); - _tris.clear(); -} - -const VertexElementList& Cube::vVertexElements() const { - return _vertices; -} - -VertexElementIndexList& Cube::vVertexElementIndices() { - return _vertexIndices; -} - -TriElementList& Cube::vTriElements() { - return _tris; -} - -void Cube::vReleaseVertexElements() { - terminateVertices(); -} - -unsigned long Cube::vGetMemoryUsage() { - return _cpuMemoryUsage; -} - -unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { - OctreeElement::HalfSpace::Bottom, - OctreeElement::HalfSpace::Top, - OctreeElement::HalfSpace::Right, - OctreeElement::HalfSpace::Left, - OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Far, -}; - -// Construction vectors ordered such that the vertices of each face are -// clockwise in a right-handed coordinate system with B-L-N at 0,0,0. -float Cube::_sVertexIndexToConstructionVector[24][3] = { - // Bottom - { 0,0,0 }, - { 1,0,0 }, - { 1,0,1 }, - { 0,0,1 }, - // Top - { 0,1,0 }, - { 0,1,1 }, - { 1,1,1 }, - { 1,1,0 }, - // Right - { 1,0,0 }, - { 1,1,0 }, - { 1,1,1 }, - { 1,0,1 }, - // Left - { 0,0,0 }, - { 0,0,1 }, - { 0,1,1 }, - { 0,1,0 }, - // Near - { 0,0,0 }, - { 0,1,0 }, - { 1,1,0 }, - { 1,0,0 }, - // Far - { 0,0,1 }, - { 1,0,1 }, - { 1,1,1 }, - { 0,1,1 }, -}; - -// Normals for a right-handed coordinate system -float Cube::_sVertexIndexToNormalVector[6][3] = { - { 0,-1, 0 }, // Bottom - { 0, 1, 0 }, // Top - { 1, 0, 0 }, // Right - { -1, 0, 0 }, // Left - { 0, 0,-1 }, // Near - { 0, 0, 1 }, // Far -}; - -Renderer::Renderer() { -} - -Renderer::~Renderer() { -} - -// Simple dispatch between API and SPI -int Renderer::add( - Primitive* primitive - ) { - return vAdd(primitive); -} - -void Renderer::remove( - int id - ) { - vRemove(id); -} - -void Renderer::release() { - vRelease(); -} - -void Renderer::render() { - vRender(); -} - -unsigned long Renderer::getMemoryUsage() { - return vGetMemoryUsage(); -} - -unsigned long Renderer::getMemoryUsageGPU() { - return vGetMemoryUsageGPU(); -} - -PrimitiveRenderer::PrimitiveRenderer( - int maxCount - ) : - _maxCount(maxCount), - _triBufferId(0), - _vertexBufferId(0), - - _vertexElementCount(0), - _maxVertexElementCount(0), - - _triElementCount(0), - _maxTriElementCount(0), - - _primitives(), - _primitiveCount(0), - - _gpuMemoryUsage(0), - _cpuMemoryUsage(0) - -{ - init(); -} - -PrimitiveRenderer::~PrimitiveRenderer() { - - terminate(); -} - -void PrimitiveRenderer::init() { - - initializeGL(); - initializeBookkeeping(); -} - -void PrimitiveRenderer::initializeGL() { - - glGenBuffers(1, &_triBufferId); - glGenBuffers(1, &_vertexBufferId); - - // Set up the element array buffer containing the index ids - _maxTriElementCount = _maxCount * 2; - int size = _maxTriElementCount * _sIndicesPerTri * sizeof(GLint); - _gpuMemoryUsage += size; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - // Set up the array buffer in the form of array of structures - // I chose AOS because it maximizes the amount of data tranferred - // by a single glBufferSubData call. - _maxVertexElementCount = _maxCount * 8; - size = _maxVertexElementCount * sizeof(VertexElement); - _gpuMemoryUsage += size; - - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // Initialize the first tri element in the buffer to all zeros, the - // degenerate case - deconstructTriElement(0); - - // Initialize the first vertex element in the buffer to all zeros, the - // degenerate case - deconstructVertexElement(0); -} - -void PrimitiveRenderer::initializeBookkeeping() { - - // Start primitive count at one, because zero is reserved for the degenerate triangle - _primitives.resize(_maxCount + 1); - - // Set the counters - _primitiveCount = 1; - _vertexElementCount = 1; - _triElementCount = 1; - - // Guesstimate the memory consumption - _cpuMemoryUsage = sizeof(PrimitiveRenderer); - _cpuMemoryUsage += _availablePrimitiveIndex.capacity() * sizeof(int); - _cpuMemoryUsage += _availableVertexElementIndex.capacity() * sizeof(int); - _cpuMemoryUsage += _availableTriElementIndex.capacity() * sizeof(int); - _cpuMemoryUsage += _deconstructTriElementIndex.capacity() * sizeof(int); - _cpuMemoryUsage += _constructPrimitiveIndex.capacity() * sizeof(int); -} - -void PrimitiveRenderer::terminate() { - - terminateBookkeeping(); - terminateGL(); -} - -void PrimitiveRenderer::terminateGL() { - - if (_vertexBufferId) { - glDeleteBuffers(1, &_vertexBufferId); - _vertexBufferId = 0; - } - - if (_triBufferId) { - glDeleteBuffers(1, &_triBufferId); - _triBufferId = 0; - } -} - -void PrimitiveRenderer::terminateBookkeeping() { - - // Delete all of the primitives - for (int i = _primitiveCount + 1; --i > 0; ) { - Primitive* primitive = _primitives[i]; - if (primitive) { - _cpuMemoryUsage -= primitive->getMemoryUsage(); - _primitives[i] = 0; - delete primitive; - } - } - - // Drain the queues - _availablePrimitiveIndex.clear(); - _availableVertexElementIndex.clear(); - _availableTriElementIndex.clear(); - _deconstructTriElementIndex.clear(); - _constructPrimitiveIndex.clear(); - - _cpuMemoryUsage = sizeof(PrimitiveRenderer) + _primitives.size() * sizeof(Primitive *); -} - -void PrimitiveRenderer::constructElements( - Primitive* primitive - ) { - - // Load vertex elements - VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); - const VertexElementList& vertices = primitive->vertexElements(); - { - for (VertexElementList::const_iterator it = vertices.begin(); it != vertices.end(); ++it ) { - int index = getAvailableVertexElementIndex(); - if (index != 0) { - // Store the vertex element index in the primitive's - // vertex element index list - vertexElementIndexList.push_back(index); - - VertexElement* vertex = *it; - transferVertexElement(index, vertex); - } else { - break; - } - } - } - - // Load tri elements - if (vertexElementIndexList.size() == vertices.size()) { - TriElementList& tris = primitive->triElements(); - - for (TriElementList::iterator it = tris.begin(); it != tris.end(); ++it) { - TriElement* tri = *it; - int index = getAvailableTriElementIndex(); - if (index != 0) { - int k; - k = tri->indices[0]; - tri->indices[0] = vertexElementIndexList[k]; - - k = tri->indices[1]; - tri->indices[1] = vertexElementIndexList[k]; - - k = tri->indices[2]; - tri->indices[2] = vertexElementIndexList[k]; - - tri->id = index; - transferTriElement(index, tri->indices); - } else { - break; - } - } - } else { - // TODO: failure mode - } -} - -void PrimitiveRenderer::deconstructElements( - Primitive* primitive - ) { - - // Schedule the tri elements of the face for deconstruction - { - TriElementList& tris = primitive->triElements(); - - for (TriElementList::const_iterator it = tris.begin(); it != tris.end(); ++it) { - const TriElement* tri = *it; - - if (tri->id) { - // Put the tri element index into decon queue - _deconstructTriElementIndex.push(tri->id); - } - } - } - - // Return the vertex element index to the available queue, it is not necessary - // to zero the data - { - VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); - - for (VertexElementIndexList::const_iterator it = vertexIndexList.begin(); it != vertexIndexList.end(); ++it) { - int index = *it; - - if (index) { - // Put the vertex element index into the available queue - _availableVertexElementIndex.push(index); - } - } - } - - delete primitive; -} - -int PrimitiveRenderer::getAvailablePrimitiveIndex() { - - int index; - - // Check the available primitive index queue first for an available index. - if (!_availablePrimitiveIndex.isEmpty()) { - index = _availablePrimitiveIndex.pop(); - } else if (_primitiveCount < _maxCount) { - // There are no primitive indices available from the queue, - // make one up - index = _primitiveCount++; - } else { - index = 0; - } - return index; -} - -int PrimitiveRenderer::getAvailableVertexElementIndex() { - - int index; - - // Check the available vertex element queue first for an available index. - if (!_availableVertexElementIndex.isEmpty()) { - index = _availableVertexElementIndex.pop(); - } else if (_vertexElementCount < _maxVertexElementCount) { - // There are no vertex elements available from the queue, - // grab one from the end of the list - index = _vertexElementCount++; - } else { - index = 0; - } - return index; -} - -int PrimitiveRenderer::getAvailableTriElementIndex() { - - int index; - - // Check the tri elements scheduled for deconstruction queue first to - // intercept and reuse an index without it having to be destroyed - if (!_deconstructTriElementIndex.isEmpty()) { - index = _deconstructTriElementIndex.pop(); - } else if (!_availableTriElementIndex.isEmpty()) { - // Nothing available in the deconstruction queue, now - // check the available tri element queue for an available index. - index = _availableTriElementIndex.pop(); - } else if (_triElementCount < _maxTriElementCount) { - // There are no reusable tri elements available from the queue, - // grab one from the end of the list - index = _triElementCount++; - } else { - index = 0; - } - return index; -} - -void PrimitiveRenderer::deconstructTriElement( - int idx - ) { - - // Set the tri element to the degenerate case. - static int degenerate[3] = { 0, 0, 0 }; - transferTriElement(idx, degenerate); - -} - -void PrimitiveRenderer::deconstructVertexElement( - int idx - ) { - - // Set the vertex element to the degenerate case. - VertexElement degenerate; - memset(°enerate, 0, sizeof(degenerate)); - - transferVertexElement(idx, °enerate); - -} - -void PrimitiveRenderer::transferVertexElement( - int idx, - VertexElement* vertex - ) { - - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - glBufferSubData(GL_ARRAY_BUFFER, idx * sizeof(VertexElement), sizeof(VertexElement), vertex); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void PrimitiveRenderer::transferTriElement( - int idx, - int tri[3] - ) { - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * _sBytesPerTriElement, _sBytesPerTriElement, tri); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -int PrimitiveRenderer::vAdd( - Primitive* primitive - ) { - - QMutexLocker lock(&_guard); - int id = getAvailablePrimitiveIndex(); - if (id != 0) { - // Take ownership of primitive, including responsibility - // for destruction - _primitives[id] = primitive; - _constructPrimitiveIndex.push(id); - _cpuMemoryUsage += primitive->getMemoryUsage(); - } - return id; -} - -void PrimitiveRenderer::vRemove( - int id - ) { - - if (id != 0) { - QMutexLocker lock(&_guard); - - // Locate and remove the primitive by id in the vector map - Primitive* primitive = _primitives[id]; - if (primitive) { - _primitives[id] = 0; - _cpuMemoryUsage -= primitive->getMemoryUsage(); - deconstructElements(primitive); - - // Queue the index onto the available primitive stack. - _availablePrimitiveIndex.push(id); - } - } -} - -void PrimitiveRenderer::vRelease() { - - QMutexLocker lock(&_guard); - - terminateBookkeeping(); - initializeBookkeeping(); -} - -void PrimitiveRenderer::vRender() { - - int id; - QMutexLocker lock(&_guard); - - // Iterate over the set of triangle element array buffer ids scheduled for - // destruction. Set the triangle element to the degenerate case. Queue the id - // onto the available tri element stack. - while (!_deconstructTriElementIndex.isEmpty()) { - id = _deconstructTriElementIndex.pop(); - deconstructTriElement(id); - _availableTriElementIndex.push(id); - } - - // Iterate over the set of primitive ids scheduled for construction. Transfer - // primitive data to the GPU. - while (!_constructPrimitiveIndex.isEmpty()) { - id = _constructPrimitiveIndex.pop(); - Primitive* primitive = _primitives[id]; - if (primitive) { - constructElements(primitive); - - // No need to keep an extra copy of the vertices - _cpuMemoryUsage -= primitive->getMemoryUsage(); - primitive->releaseVertexElements(); - _cpuMemoryUsage += primitive->getMemoryUsage(); - } - } - - // The application uses clockwise winding for the definition of front face, this renderer - // aalso uses clockwise (that is the gl default) to construct the triangulation - // so... - //glFrontFace(GL_CW); - glEnable(GL_CULL_FACE); - - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexElement), 0); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexElement), (const GLvoid*)12); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (const GLvoid*)24); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glDrawElements(GL_TRIANGLES, 3 * _triElementCount, GL_UNSIGNED_INT, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glDisable(GL_CULL_FACE); -} - -unsigned long PrimitiveRenderer::vGetMemoryUsage() { - return _cpuMemoryUsage; -} - -unsigned long PrimitiveRenderer::vGetMemoryUsageGPU() { - return _gpuMemoryUsage; -} diff --git a/interface/src/voxels/PrimitiveRenderer.h b/interface/src/voxels/PrimitiveRenderer.h deleted file mode 100644 index 06dac119b0..0000000000 --- a/interface/src/voxels/PrimitiveRenderer.h +++ /dev/null @@ -1,503 +0,0 @@ -// -// PrimitiveRenderer.h -// interface/src/voxels -// -// Created by Norman Craft. -// 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 -// - -#ifndef hifi_PrimitiveRenderer_h -#define hifi_PrimitiveRenderer_h - -#include -#include -#include - -/// Vertex element structure. -/// Using the array of structures approach to specifying -/// vertex data to GL cuts down on the calls to glBufferSubData -/// -typedef - struct __VertexElement { - struct __position { - float x; - float y; - float z; - } position; - struct __normal { - float x; - float y; - float z; - } normal; - struct __color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - } color; - } VertexElement; - -/// Triangle element index structure. -/// Specify the vertex indices of the triangle and its element index. -/// -typedef - struct __TriElement { - int indices[3]; - int id; - - } TriElement; - -/// Vertex element list container. -/// -typedef QVector VertexElementList; - -/// Vertex element index list container. -/// -typedef QVector VertexElementIndexList; - -/// Triangle element list container -/// -typedef QVector TriElementList; - -/// -/// @class Primitive -/// Primitive Interface class. -/// Abstract class for accessing vertex and tri elements of geometric primitives -/// -/// -class Primitive { -public: - virtual ~Primitive(); - - // API methods go here - - /// Vertex element accessor. - /// @return A list of vertex elements of the primitive - /// - const VertexElementList& vertexElements() const; - - /// Vertex element index accessor. - /// @return A list of vertex element indices of the primitive - /// - VertexElementIndexList& vertexElementIndices(); - - /// Tri element accessor. - /// @return A list of tri elements of the primitive - /// - TriElementList& triElements(); - - /// Release vertex elements. - /// - void releaseVertexElements(); - - /// Get memory usage. - /// - unsigned long getMemoryUsage(); - -protected: - /// Default constructor prohibited to API user, restricted to service implementer. - /// - Primitive(); - -private: - /// Copy constructor prohibited. - /// - Primitive( - const Primitive& copy - ); - - // SPI methods are defined here - - /// Vertex element accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual const VertexElementList& vVertexElements() const = 0; - - /// Vertex element index accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual VertexElementIndexList& vVertexElementIndices() = 0; - - /// Tri element accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual TriElementList& vTriElements() = 0; - - /// Release vertex elements. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual void vReleaseVertexElements() = 0; - - /// Get memory usage. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual unsigned long vGetMemoryUsage() = 0; - -}; - - -/// -/// @class Cube -/// Class for accessing the vertex and triangle elements of a cube -/// -class Cube: public Primitive { -public: - /// Configuration dependency injection constructor. - /// - Cube( - 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(); - -private: - /// Copy constructor prohibited. - /// - Cube ( - const Cube& cube - ); - - /// Cube initialization - /// - void init( - 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, ///< 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 - - const VertexElementList& vVertexElements() const; - VertexElementIndexList& vVertexElementIndices(); - TriElementList& vTriElements(); - void vReleaseVertexElements(); - unsigned long vGetMemoryUsage(); - -private: - VertexElementList _vertices; ///< Vertex element list - VertexElementIndexList _vertexIndices; ///< Vertex element index list - TriElementList _tris; ///< Tri element list - - unsigned long _cpuMemoryUsage; ///< Memory allocation of object - - 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 - -}; - - -/// -/// @class Renderer -/// GL renderer interface class. -/// Abstract class for rendering geometric primitives in GL -/// -class Renderer { -public: - virtual ~Renderer(); - - // API methods go here - - /// Add primitive to renderer database. - /// - int add( - Primitive* primitive ///< Primitive instance to be added - ); - - /// Remove primitive from renderer database. - /// - void remove( - int id ///< Primitive id to be removed - ); - - /// Clear all primitives from renderer database - /// - void release(); - - /// Render primitive database. - /// The render method assumes appropriate GL context and state has - /// already been provided for - /// - void render(); - - /// Get memory usage. - /// - unsigned long getMemoryUsage(); - - /// Get GPU memory usage. - /// - unsigned long getMemoryUsageGPU(); - -protected: - /// Default constructor prohibited to API user, restricted to service implementer. - /// - Renderer(); - -private: - /// Copy constructor prohibited. - /// - Renderer( - const Renderer& copy - ); - - // SPI methods are defined here - - /// Add primitive to renderer database. - /// Service implementer to provide private override for this method - /// in derived class - /// @return Primitive id - /// - virtual int vAdd( - Primitive* primitive ///< Primitive instance to be added - ) = 0; - - /// Remove primitive from renderer database. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual void vRemove( - int id ///< Primitive id - ) = 0; - - /// Clear all primitives from renderer database - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual void vRelease() = 0; - - /// Render primitive database. - /// Service implementer to provide private virtual override for this method - /// in derived class - /// - virtual void vRender() = 0; - - /// Get memory usage. - /// - virtual unsigned long vGetMemoryUsage() = 0; - - /// Get GPU memory usage. - /// - virtual unsigned long vGetMemoryUsageGPU() = 0; - -}; - -/// -/// @class PrimitiveRenderer -/// Renderer implementation class for the rendering of geometric primitives -/// using GL element array and GL array buffers -/// -class PrimitiveRenderer : public Renderer { -public: - /// Configuration dependency injection constructor. - /// - PrimitiveRenderer( - int maxCount ///< Max count - ); - - ~PrimitiveRenderer(); - -private: - /// Default constructor prohibited. - /// - PrimitiveRenderer(); - - /// Copy constructor prohibited. - /// - PrimitiveRenderer( - const PrimitiveRenderer& renderer - ); - - void init(); - void terminate(); - - /// Allocate and initialize GL buffers. - /// - void initializeGL(); - - /// Terminate and deallocate GL buffers. - /// - void terminateGL(); - - void initializeBookkeeping(); - void terminateBookkeeping(); - - /// Construct the elements of the faces of the primitive. - /// - void constructElements( - Primitive* primitive ///< Primitive instance - ); - - /// Deconstruct the elements of the faces of the primitive. - /// - void deconstructElements( - Primitive* primitive ///< Primitive instance - ); - - /// Deconstruct the triangle element from the GL buffer. - /// - void deconstructTriElement( - int idx ///< Triangle element index - ); - - /// Deconstruct the vertex element from the GL buffer. - /// - void deconstructVertexElement( - int idx ///< Vertex element index - ); - - /// Transfer the vertex element to the GL buffer. - /// - void transferVertexElement( - int idx, ///< Vertex element index - VertexElement *vertex ///< Vertex element instance - ); - - /// Transfer the triangle element to the GL buffer. - /// - void transferTriElement( - int idx, ///< Triangle element index - int tri[3] ///< Triangle element data - ); - - /// Get available primitive index. - /// Get an available primitive index from either the recycling - /// queue or incrementing the counter - /// - int getAvailablePrimitiveIndex(); - - /// Get available vertex element index. - /// Get an available vertex element index from either the recycling - /// queue or incrementing the counter - /// - int getAvailableVertexElementIndex(); - - /// Get available triangle element index. - /// Get an available triangle element index from either the elements - /// scheduled for deconstruction queue, the recycling - /// queue or incrementing the counter - /// - int getAvailableTriElementIndex(); - - // SPI virtual override methods go here - - /// Add primitive to renderer database. - /// - int vAdd( - Primitive* primitive ///< Primitive instance to be added - ); - - /// Remove primitive from renderer database. - /// - void vRemove( - int id ///< Primitive id to be removed - ); - - /// Clear all primitives from renderer database - /// - void vRelease(); - - /// Render triangle database. - /// - void vRender(); - - /// Get memory usage. - /// - unsigned long vGetMemoryUsage(); - - /// Get gpu memory usage. - /// - unsigned long vGetMemoryUsageGPU(); - -private: - - int _maxCount; ///< Maximum count of tris - - // GL related parameters - - GLuint _triBufferId; ///< GL element array buffer id - GLuint _vertexBufferId; ///< GL vertex array buffer id - - // Book keeping parameters - - int _vertexElementCount; ///< Count of vertices - int _maxVertexElementCount; ///< Max count of vertices - - int _triElementCount; ///< Count of triangles - int _maxTriElementCount; ///< Max count of triangles - - QVector _primitives; ///< Vector of primitive - int _primitiveCount; ///< Count of primitives - - QStack _availablePrimitiveIndex; ///< Queue of primitive indices available - QStack _availableVertexElementIndex; ///< Queue of vertex element indices available - QStack _availableTriElementIndex; ///< Queue of triangle element indices available - QStack _deconstructTriElementIndex; ///< Queue of triangle element indices requiring deletion from GL - QStack _constructPrimitiveIndex; ///< Queue of primitives requiring addition to GL - - QMutex _guard; - - // Statistics parameters, not necessary for proper operation - - unsigned long _gpuMemoryUsage; ///< GPU memory used by this instance - unsigned long _cpuMemoryUsage; ///< CPU memory used by this instance - - - static const int _sIndicesPerTri = 3; - static const int _sBytesPerTriElement = sizeof(GLint) * _sIndicesPerTri; -}; - - -#endif // hifi_PrimitiveRenderer_h diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index 8d16245962..2f4fd3f0fa 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -68,10 +68,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) _initialized(false), _writeArraysLock(QReadWriteLock::Recursive), _readArraysLock(QReadWriteLock::Recursive), - _inOcclusions(false), - _showCulledSharedFaces(false), - _usePrimitiveRenderer(false), - _renderer(0), _drawHaze(false), _farHazeDistance(300.0f), _hazeColor(grayColor) @@ -92,13 +88,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) _viewFrustum = Application::getInstance()->getViewFrustum(); - _useVoxelShader = false; - _voxelsAsPoints = false; - _voxelShaderModeWhenVoxelsAsPointsEnabled = false; - - _writeVoxelShaderData = NULL; - _readVoxelShaderData = NULL; - _readVerticesArray = NULL; _writeVerticesArray = NULL; _readColorsArray = NULL; @@ -119,7 +108,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) void VoxelSystem::elementDeleted(OctreeElement* element) { VoxelTreeElement* voxel = (VoxelTreeElement*)element; if (voxel->getVoxelSystem() == this) { - if ((_voxelsInWriteArrays != 0) || _usePrimitiveRenderer) { + if ((_voxelsInWriteArrays != 0)) { forceRemoveNodeFromArrays(voxel); } else { if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { @@ -270,109 +259,30 @@ void VoxelSystem::setMaxVoxels(unsigned long maxVoxels) { } } -// This is called by the main application thread on both the initialization of the application and when -// the use voxel shader menu item is chosen -void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { - if (_useVoxelShader == useVoxelShader) { - return; - } - - bool wasInitialized = _initialized; - if (wasInitialized) { - clearAllNodesBufferIndex(); - cleanupVoxelMemory(); - } - _useVoxelShader = useVoxelShader; - _usePrimitiveRenderer = false; - if (wasInitialized) { - initVoxelMemory(); - } - - if (wasInitialized) { - forceRedrawEntireTree(); - } -} - -void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { - if (_voxelsAsPoints == voxelsAsPoints) { - return; - } - - bool wasInitialized = _initialized; - - // If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode. - // Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode, - // then set it to voxel shader mode. - if (voxelsAsPoints) { - Menu::getInstance()->getUseVoxelShader()->setEnabled(false); - - // If enabling this... then do it before checking voxel shader status, that way, if voxel - // shader is already enabled, we just start drawing as points. - _voxelsAsPoints = true; - - if (!_useVoxelShader) { - setUseVoxelShader(true); - _voxelShaderModeWhenVoxelsAsPointsEnabled = false; - } else { - _voxelShaderModeWhenVoxelsAsPointsEnabled = true; - } - } else { - Menu::getInstance()->getUseVoxelShader()->setEnabled(true); - // if we're turning OFF voxels as point mode, then we check what the state of voxel shader was when we enabled - // voxels as points, if it was OFF, then we return it to that value. - if (_voxelShaderModeWhenVoxelsAsPointsEnabled == false) { - setUseVoxelShader(false); - } - // If disabling this... then do it AFTER checking previous voxel shader status, that way, if voxel - // shader is was not enabled, we switch back to normal mode before turning off points. - _voxelsAsPoints = false; - } - - // Set our voxels as points - if (wasInitialized) { - forceRedrawEntireTree(); - } -} - void VoxelSystem::cleanupVoxelMemory() { if (_initialized) { _readArraysLock.lockForWrite(); _initialized = false; // no longer initialized - if (_useVoxelShader) { - // these are used when in VoxelShader mode. - glDeleteBuffers(1, &_vboVoxelsID); - glDeleteBuffers(1, &_vboVoxelsIndicesID); + // Destroy glBuffers + glDeleteBuffers(1, &_vboVerticesID); + glDeleteBuffers(1, &_vboColorsID); - delete[] _writeVoxelShaderData; - delete[] _readVoxelShaderData; + glDeleteBuffers(1, &_vboIndicesTop); + glDeleteBuffers(1, &_vboIndicesBottom); + glDeleteBuffers(1, &_vboIndicesLeft); + glDeleteBuffers(1, &_vboIndicesRight); + glDeleteBuffers(1, &_vboIndicesFront); + glDeleteBuffers(1, &_vboIndicesBack); - _writeVoxelShaderData = _readVoxelShaderData = NULL; + delete[] _readVerticesArray; + delete[] _writeVerticesArray; + delete[] _readColorsArray; + delete[] _writeColorsArray; - } else { - // Destroy glBuffers - glDeleteBuffers(1, &_vboVerticesID); - glDeleteBuffers(1, &_vboColorsID); - - glDeleteBuffers(1, &_vboIndicesTop); - glDeleteBuffers(1, &_vboIndicesBottom); - glDeleteBuffers(1, &_vboIndicesLeft); - glDeleteBuffers(1, &_vboIndicesRight); - glDeleteBuffers(1, &_vboIndicesFront); - glDeleteBuffers(1, &_vboIndicesBack); - - delete[] _readVerticesArray; - delete[] _writeVerticesArray; - delete[] _readColorsArray; - delete[] _writeColorsArray; - - _readVerticesArray = NULL; - _writeVerticesArray = NULL; - _readColorsArray = NULL; - _writeColorsArray = NULL; - } - - delete _renderer; - _renderer = 0; + _readVerticesArray = NULL; + _writeVerticesArray = NULL; + _readColorsArray = NULL; + _writeColorsArray = NULL; delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; @@ -417,105 +327,56 @@ void VoxelSystem::initVoxelMemory() { _memoryUsageRAM = 0; _memoryUsageVBO = 0; // our VBO allocations as we know them - // if _voxelsAsPoints then we must have _useVoxelShader - if (_voxelsAsPoints && !_useVoxelShader) { - _useVoxelShader = true; + // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead + // rendering the voxel faces in 6 passes that use a global call to glNormal3f() + setupFaceIndices(_vboIndicesTop, identityIndicesTop); + setupFaceIndices(_vboIndicesBottom, identityIndicesBottom); + setupFaceIndices(_vboIndicesLeft, identityIndicesLeft); + setupFaceIndices(_vboIndicesRight, identityIndicesRight); + setupFaceIndices(_vboIndicesFront, identityIndicesFront); + setupFaceIndices(_vboIndicesBack, identityIndicesBack); + + // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel + int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; + glGenBuffers(1, &_vboVerticesID); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels; + + // VBO for colorsArray + glGenBuffers(1, &_vboColorsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels; + + // we will track individual dirty sections with these arrays of bools + _writeVoxelDirtyArray = new bool[_maxVoxels]; + memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); + _memoryUsageRAM += (sizeof(bool) * _maxVoxels); + + _readVoxelDirtyArray = new bool[_maxVoxels]; + memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); + _memoryUsageRAM += (sizeof(bool) * _maxVoxels); + + // prep the data structures for incoming voxel data + _writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); + _readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); + + _writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); + _readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); + + // create our simple fragment shader if we're the first system to init + if (!_program.isLinked()) { + _program.addShaderFromSourceFile(QGLShader::Vertex, + Application::resourcesPath() + "shaders/voxel.vert"); + _program.addShaderFromSourceFile(QGLShader::Fragment, + Application::resourcesPath() + "shaders/voxel.frag"); + _program.link(); } - - if (_useVoxelShader) { - GLuint* indicesArray = new GLuint[_maxVoxels]; - - // populate the indicesArray - // this will not change given new voxels, so we can set it all up now - for (unsigned long n = 0; n < _maxVoxels; n++) { - indicesArray[n] = n; - } - - // bind the indices VBO to the actual indices array - glGenBuffers(1, &_vboVoxelsIndicesID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW); - _memoryUsageVBO += sizeof(GLuint) * _maxVoxels; - - glGenBuffers(1, &_vboVoxelsID); - glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); - glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += _maxVoxels * sizeof(VoxelShaderVBOData); - - // delete the indices and normals arrays that are no longer needed - delete[] indicesArray; - - // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[_maxVoxels]; - memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (_maxVoxels * sizeof(bool)); - - _readVoxelDirtyArray = new bool[_maxVoxels]; - memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (_maxVoxels * sizeof(bool)); - - // prep the data structures for incoming voxel data - _writeVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; - _memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels); - - _readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; - _memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels); - - } else { - - // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead - // rendering the voxel faces in 6 passes that use a global call to glNormal3f() - setupFaceIndices(_vboIndicesTop, identityIndicesTop); - setupFaceIndices(_vboIndicesBottom, identityIndicesBottom); - setupFaceIndices(_vboIndicesLeft, identityIndicesLeft); - setupFaceIndices(_vboIndicesRight, identityIndicesRight); - setupFaceIndices(_vboIndicesFront, identityIndicesFront); - setupFaceIndices(_vboIndicesBack, identityIndicesBack); - - // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - glGenBuffers(1, &_vboVerticesID); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels; - - // VBO for colorsArray - glGenBuffers(1, &_vboColorsID); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels; - - // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[_maxVoxels]; - memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (sizeof(bool) * _maxVoxels); - - _readVoxelDirtyArray = new bool[_maxVoxels]; - memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); - _memoryUsageRAM += (sizeof(bool) * _maxVoxels); - - // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); - _readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); - - _writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); - _readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); - - // create our simple fragment shader if we're the first system to init - if (!_program.isLinked()) { - _program.addShaderFromSourceFile(QGLShader::Vertex, - Application::resourcesPath() + "shaders/voxel.vert"); - _program.addShaderFromSourceFile(QGLShader::Fragment, - Application::resourcesPath() + "shaders/voxel.frag"); - _program.link(); - } - } - _renderer = new PrimitiveRenderer(_maxVoxels); - _initialized = true; _writeArraysLock.unlock(); @@ -641,10 +502,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _callsToTreesToArrays++; if (_writeRenderFullVBO) { - if (_usePrimitiveRenderer) { - _renderer->release(); - clearAllNodesBufferIndex(); - } clearFreeBufferIndexes(); } _voxelsUpdated = newTreeToArrays(_tree->getRoot()); @@ -655,24 +512,17 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _voxelsUpdated = 0; } - if (_usePrimitiveRenderer) { - if (_voxelsUpdated) { - _voxelsDirty=true; - } - } else { - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - _readArraysLock.lockForWrite(); - - if (_voxelsUpdated) { - _voxelsDirty=true; - } - - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(didWriteFullVBO); - _readArraysLock.unlock(); + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + _readArraysLock.lockForWrite(); + if (_voxelsUpdated) { + _voxelsDirty=true; } + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(didWriteFullVBO); + _readArraysLock.unlock(); + quint64 end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; _setupNewVoxelsForDrawingLastFinished = end; @@ -699,26 +549,22 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { return; // bail early, it hasn't been long enough since the last time we ran } - if (_usePrimitiveRenderer) { - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - _voxelsUpdated = 0; - } else { - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); - _readArraysLock.lockForWrite(); - } - - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(_writeRenderFullVBO); - - // after... - _voxelsUpdated = 0; - _readArraysLock.unlock(); + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); + _readArraysLock.lockForWrite(); } + + _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty + + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(_writeRenderFullVBO); + + // after... + _voxelsUpdated = 0; + _readArraysLock.unlock(); + quint64 end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; _setupNewVoxelsForDrawingLastFinished = end; @@ -882,25 +728,18 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { int segmentLength = (segmentEnd - segmentStart) + 1; - if (_useVoxelShader) { - GLsizeiptr segmentSizeBytes = segmentLength * sizeof(VoxelShaderVBOData); - void* readDataAt = &_readVoxelShaderData[segmentStart]; - void* writeDataAt = &_writeVoxelShaderData[segmentStart]; - memcpy(readDataAt, writeDataAt, segmentSizeBytes); - } else { - // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; + // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel + int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); + GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); + GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); + GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel); + memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); - } + segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); + GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel); + GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel); + memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); } void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { @@ -999,22 +838,13 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { return 0; } - if (_usePrimitiveRenderer) { - if (node->isKnownBufferIndex()) { - int primitiveIndex = node->getBufferIndex(); - _renderer->remove(primitiveIndex); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - return 1; - } - } else { - // if the node is not in the VBOs then we have nothing to do! - if (node->isKnownBufferIndex()) { - // If this node has not yet been written to the array, then add it to the end of the array. - glBufferIndex nodeIndex = node->getBufferIndex(); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! - return 1; // updated! - } + // if the node is not in the VBOs then we have nothing to do! + if (node->isKnownBufferIndex()) { + // If this node has not yet been written to the array, then add it to the end of the array. + glBufferIndex nodeIndex = node->getBufferIndex(); + node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); + freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! + return 1; // updated! } return 0; // not-updated } @@ -1046,43 +876,17 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo float voxelScale = node->getScale(); nodeColor const & color = node->getColor(); - if (_usePrimitiveRenderer) { - if (node->isKnownBufferIndex()) { - int primitiveIndex = node->getBufferIndex(); - _renderer->remove(primitiveIndex); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - } else { - node->setVoxelSystem(this); - } - unsigned char occlusions; - if (_showCulledSharedFaces) { - occlusions = ~node->getInteriorOcclusions(); - } else { - occlusions = node->getInteriorOcclusions(); - } - if (occlusions != OctreeElement::HalfSpace::All) { - Cube* cube = new Cube( - startVertex.x, startVertex.y, startVertex.z, voxelScale, - color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], - occlusions); - if (cube) { - int primitiveIndex = _renderer->add(cube); - node->setBufferIndex(primitiveIndex); - } - } + glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; + if (reuseIndex && node->isKnownBufferIndex()) { + nodeIndex = node->getBufferIndex(); } else { - glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; - if (reuseIndex && node->isKnownBufferIndex()) { - nodeIndex = node->getBufferIndex(); - } else { - nodeIndex = getNextBufferIndex(); - node->setBufferIndex(nodeIndex); - node->setVoxelSystem(this); - } - - // populate the array with points for the 8 vertices and RGB color for each added vertex - updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); + nodeIndex = getNextBufferIndex(); + node->setBufferIndex(nodeIndex); + node->setVoxelSystem(this); } + + // populate the array with points for the 8 vertices and RGB color for each added vertex + updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); return 1; // updated! } else { // If we shouldn't render, and we're in reuseIndex mode, then free our index, this only operates @@ -1101,31 +905,15 @@ void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& if (_initialized && nodeIndex <= _maxVoxels) { _writeVoxelDirtyArray[nodeIndex] = true; - if (_useVoxelShader) { - // write in position, scale, and color for the voxel - - if (_writeVoxelShaderData) { - VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; - writeVerticesAt->x = startVertex.x * TREE_SCALE; - writeVerticesAt->y = startVertex.y * TREE_SCALE; - writeVerticesAt->z = startVertex.z * TREE_SCALE; - writeVerticesAt->s = voxelScale * TREE_SCALE; - writeVerticesAt->r = color[RED_INDEX]; - writeVerticesAt->g = color[GREEN_INDEX]; - writeVerticesAt->b = color[BLUE_INDEX]; - } - } else { - if (_writeVerticesArray && _writeColorsArray) { - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - for (int j = 0; j < vertexPointsPerVoxel; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); - *(writeColorsAt +j) = color[j % 3]; - } + if (_writeVerticesArray && _writeColorsArray) { + int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; + for (int j = 0; j < vertexPointsPerVoxel; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); + *(writeColorsAt +j) = color[j % 3]; } } - } } @@ -1225,24 +1013,22 @@ void VoxelSystem::updateVBOs() { }; // would like to include _callsToTreesToArrays PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); - if (! _usePrimitiveRenderer) { - if (_voxelsDirty) { - - // attempt to lock the read arrays, to for copying from them to the actual GPU VBOs. - // if we fail to get the lock, that's ok, our VBOs will update on the next frame... - const int WAIT_FOR_LOCK_IN_MS = 5; - if (_readArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { - if (_readRenderFullVBO) { - updateFullVBOs(); - } else { - updatePartialVBOs(); - } - _voxelsDirty = false; - _readRenderFullVBO = false; - _readArraysLock.unlock(); + if (_voxelsDirty) { + + // attempt to lock the read arrays, to for copying from them to the actual GPU VBOs. + // if we fail to get the lock, that's ok, our VBOs will update on the next frame... + const int WAIT_FOR_LOCK_IN_MS = 5; + if (_readArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) { + if (_readRenderFullVBO) { + updateFullVBOs(); } else { - qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()"; + updatePartialVBOs(); } + _voxelsDirty = false; + _readRenderFullVBO = false; + _readArraysLock.unlock(); + } else { + qDebug() << "updateVBOs().... couldn't get _readArraysLock.tryLockForRead()"; } } _callsToTreesToArrays = 0; // clear it @@ -1253,44 +1039,34 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarning, "updateVBOSegment()"); - if (_useVoxelShader) { - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData); - GLsizeiptr segmentSizeBytes = segmentLength * sizeof(VoxelShaderVBOData); - void* readVerticesFrom = &_readVoxelShaderData[segmentStart]; + int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); - glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); + { + PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);"); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + } + + { + PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);"); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - } else { - int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); + } - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);"); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - } + segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte); + segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel); - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);"); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - } + { + PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);"); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + } - segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte); - segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel); - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);"); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - } - - { - PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);"); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); - } + { + PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);"); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } } @@ -1306,75 +1082,11 @@ void VoxelSystem::render() { updateVBOs(); - // if not don't... then do... - if (_useVoxelShader) { - PerformanceWarning warn(showWarnings,"render().. _useVoxelShader openGL.."); - - - //Define this somewhere in your header file - #define BUFFER_OFFSET(i) ((void*)(i)) - - glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices - - int attributeLocation; - - if (!_voxelsAsPoints) { - Application::getInstance()->getVoxelShader().begin(); - attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); - glEnableVertexAttribArray(attributeLocation); - glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); - } else { - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - - glm::vec2 viewDimensions = Application::getInstance()->getViewportDimensions(); - float viewportWidth = viewDimensions.x; - float viewportHeight = viewDimensions.y; - glm::vec3 cameraPosition = Application::getInstance()->getViewFrustum()->getPosition(); - PointShader& pointShader = Application::getInstance()->getPointShader(); - - pointShader.begin(); - - pointShader.setUniformValue(pointShader.uniformLocation("viewportWidth"), viewportWidth); - pointShader.setUniformValue(pointShader.uniformLocation("viewportHeight"), viewportHeight); - pointShader.setUniformValue(pointShader.uniformLocation("cameraPosition"), cameraPosition); - - attributeLocation = pointShader.attributeLocation("voxelSizeIn"); - glEnableVertexAttribArray(attributeLocation); - glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); - } - - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboVoxelsIndicesID); - - glDrawElements(GL_POINTS, _voxelsInReadArrays, GL_UNSIGNED_INT, BUFFER_OFFSET(0)); //The starting point of the IBO - - // deactivate vertex and color arrays after drawing - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - // bind with 0 to switch back to normal operation - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - if (!_voxelsAsPoints) { - Application::getInstance()->getVoxelShader().end(); - glDisableVertexAttribArray(attributeLocation); - } else { - Application::getInstance()->getPointShader().end(); - glDisableVertexAttribArray(attributeLocation); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - } - } else - if (!_usePrimitiveRenderer) { - if (_drawHaze) { - glEnable(GL_FOG); - } + if (_drawHaze) { + glEnable(GL_FOG); + } + { PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); { @@ -1450,16 +1162,10 @@ void VoxelSystem::render() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - - if (_drawHaze) { - glDisable(GL_FOG); - } } - else { - applyScaleAndBindProgram(texture); - _renderer->render(); - removeScaleAndReleaseProgram(texture); - + + if (_drawHaze) { + glDisable(GL_FOG); } } @@ -1502,12 +1208,6 @@ void VoxelSystem::killLocalVoxels() { _tree->getRoot()->setVoxelSystem(voxelSystem); _tree->unlock(); clearFreeBufferIndexes(); - if (_usePrimitiveRenderer) { - if (_renderer) { - _renderer->release(); - } - clearAllNodesBufferIndex(); - } _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); } @@ -1535,178 +1235,6 @@ void VoxelSystem::clearAllNodesBufferIndex() { } } -bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - - // Nothing to do at the leaf level - if (voxel->isLeaf()) { - return false; - } - - // Bit mask of occluded shared faces indexed by child - unsigned char occludedSharedFace[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - // Traverse all pair combinations of children - for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - - VoxelTreeElement* childA = voxel->getChildAtIndex(i); - if (childA) { - - // Get the child A's occluding faces, for a leaf that will be - // all six voxel faces, and for a non leaf, that will be - // all faces which are completely covered by four child octants. - unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); - - for (int j = i; --j >= 0; ) { - - VoxelTreeElement* childB = voxel->getChildAtIndex(j); - if (childB) { - - // Get child B's occluding faces - unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); - - // Determine the shared halfspace partition between siblings A and B, - // i.e., near/far, left/right, or top/bottom - unsigned char partitionA = _sOctantIndexToSharedBitMask[i][j] & - exteriorOcclusionsA; - unsigned char partitionB = _sOctantIndexToSharedBitMask[i][j] & - exteriorOcclusionsB; - - // Determine which face of each sibling is occluded. - - // The _sOctantIndexToBitMask is a partition occupancy mask. For - // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels - // exist, the shared partition is top-bottom (TB), and thus the occluded - // shared face of the NLT voxel is its bottom face. - occludedSharedFace[i] |= (partitionB & _sOctantIndexToBitMask[i]); - occludedSharedFace[j] |= (partitionA & _sOctantIndexToBitMask[j]); - } - } - // Exchange bit pairs, left to right, vice versa, etc. - occludedSharedFace[i] = _sSwizzledOcclusionBits[occludedSharedFace[i]]; - // Combine this voxel's interior excluded shared face only to those children which are coincident - // with the excluded face. - occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & _sOctantIndexToBitMask[i]); - - // Inform the child - childA->setInteriorOcclusions(occludedSharedFace[i]); - if (occludedSharedFace[i] != OctreeElement::HalfSpace::None) { - //const glm::vec3& v = voxel->getCorner(); - //float s = voxel->getScale(); - - //qDebug("Child %d of voxel at %f %f %f size: %f has %02x occlusions", i, v.x, v.y, v.z, s, occludedSharedFace[i]); - } - } - } - return true; -} - -bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - - // Nothing to do at the leaf level - if (voxel->isLeaf()) { - // By definition the the exterior faces of a leaf voxel are - // always occluders. - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); - // And the sibling occluders - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - return false; - } else { - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - } - - // Count of exterior occluding faces of this voxel element indexed - // by half space partition - unsigned int exteriorOcclusionsCt[6] = { 0, 0, 0, 0, 0, 0 }; - - // Traverse all children - for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - - VoxelTreeElement* child = voxel->getChildAtIndex(i); - if (child) { - - // Get the child's occluding faces, for a leaf, that will be - // all six voxel faces, and for a non leaf, that will be - // all faces which are completely covered by four child octants. - unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); - exteriorOcclusionsOfChild &= _sOctantIndexToBitMask[i]; - - for (int j = 6; --j >= 0; ) { - - // Determine if the halfspace partition indexed by 1 << j is - // present in the exterior occlusions of the child. - unsigned char partition = exteriorOcclusionsOfChild & (1 << j); - - if (partition) { - exteriorOcclusionsCt[j]++; - } - } - } - } - { - // Derive the exterior occlusions of the voxel elements from the exclusions - // of its children - unsigned char exteriorOcclusions = OctreeElement::HalfSpace::None; - for (int i = 6; --i >= 0; ) { - if (exteriorOcclusionsCt[i] == _sNumOctantsPerHemiVoxel) { - - // Exactly four octants qualify for full exterior occlusion - exteriorOcclusions |= (1 << i); - } - } - - // Inform the voxel element - voxel->setExteriorOcclusions(exteriorOcclusions); - - if (exteriorOcclusions == OctreeElement::HalfSpace::All) { - //const glm::vec3& v = voxel->getCorner(); - //float s = voxel->getScale(); - - //qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s); - - // 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(); - - //qDebug("Partially occupied voxel at %f %f %f size: %f with %02x", v.x, v.y, v.z, s, exteriorOcclusions); - } - } - return true; -} - -void VoxelSystem::inspectForOcclusions() { - - if (_inOcclusions) { - return; - } - _inOcclusions = true; - _nodeCount = 0; - - bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); - - _tree->lockForRead(); - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); - _nodeCount = 0; - _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); - _tree->unlock(); - - if (showDebugDetails) { - qDebug("inspecting all occlusions of %d nodes", _nodeCount); - } - _inOcclusions = false; -} - bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { _nodeCount++; element->setDirtyBit(); @@ -2131,170 +1659,3 @@ void VoxelSystem::bindPerlinModulateProgram() { } } -// Swizzle value of bit pairs of the value of index -unsigned short VoxelSystem::_sSwizzledOcclusionBits[64] = { - 0x0000, // 00000000 - 0x0002, // 00000001 - 0x0001, // 00000010 - 0x0003, // 00000011 - 0x0008, // 00000100 - 0x000a, // 00000101 - 0x0009, // 00000110 - 0x000b, // 00000111 - 0x0004, // 00001000 - 0x0006, // 00001001 - 0x0005, // 00001010 - 0x0007, // 00001011 - 0x000c, // 00001100 - 0x000e, // 00001101 - 0x000d, // 00001110 - 0x000f, // 00001111 - 0x0020, // 00010000 - 0x0022, // 00010001 - 0x0021, // 00010010 - 0x0023, // 00010011 - 0x0028, // 00010100 - 0x002a, // 00010101 - 0x0029, // 00010110 - 0x002b, // 00010111 - 0x0024, // 00011000 - 0x0026, // 00011001 - 0x0025, // 00011010 - 0x0027, // 00011011 - 0x002c, // 00011100 - 0x002e, // 00011101 - 0x002d, // 00011110 - 0x002f, // 00011111 - 0x0010, // 00100000 - 0x0012, // 00100001 - 0x0011, // 00100010 - 0x0013, // 00100011 - 0x0018, // 00100100 - 0x001a, // 00100101 - 0x0019, // 00100110 - 0x001b, // 00100111 - 0x0014, // 00101000 - 0x0016, // 00101001 - 0x0015, // 00101010 - 0x0017, // 00101011 - 0x001c, // 00101100 - 0x001e, // 00101101 - 0x001d, // 00101110 - 0x001f, // 00101111 - 0x0030, // 00110000 - 0x0032, // 00110001 - 0x0031, // 00110010 - 0x0033, // 00110011 - 0x0038, // 00110100 - 0x003a, // 00110101 - 0x0039, // 00110110 - 0x003b, // 00110111 - 0x0034, // 00111000 - 0x0036, // 00111001 - 0x0035, // 00111010 - 0x0037, // 00111011 - 0x003c, // 00111100 - 0x003e, // 00111101 - 0x003d, // 00111110 - 0x003f, // 00111111 -}; - -// Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index -// value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* -// correspond to the "ChildIndex" enum value in OctreeElement.h -unsigned char VoxelSystem::_sOctantIndexToBitMask[8] = { - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, -}; - -// Two dimensional array map indexed by octant row and column. The mask value -// indicates the two faces shared by the octants -unsigned char VoxelSystem::_sOctantIndexToSharedBitMask[8][8] = { - { // Index 0: Bottom-Left-Near - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 1: Bottom-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Far - 0, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 2: Top-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Far - 0, // Bottom-Right-Near - 0, // Bottom-Right-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 3: Top-Left-Far - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Near - 0, // Top-Left-Far - 0, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Far - }, - { // Index 4: Bottom-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - 0, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 5: Bottom-Right-Far - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Far - 0, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Far - }, - { // Index 6: Top-Right-Near - 0, // Bottom-Left-Near - 0, // Bottom-Left-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Far - }, - { // Index 7: Top-Right-Far - 0, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Near - 0, // Top-Right-Far - }, -}; - diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index 8e60cbe073..b6413a0f68 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -25,22 +25,12 @@ #include "Camera.h" #include "Util.h" #include "world.h" -#include "renderer/VoxelShader.h" -#include "PrimitiveRenderer.h" class ProgramObject; const int NUM_CHILDREN = 8; -struct VoxelShaderVBOData -{ - float x, y, z; // position - float s; // size - unsigned char r,g,b; // color -}; - - class VoxelSystem : public NodeData, public OctreeElementDeleteHook, public OctreeElementUpdateHook { Q_OBJECT @@ -80,7 +70,6 @@ public: void killLocalVoxels(); virtual void hideOutOfView(bool forceFullFrustum = false); - void inspectForOcclusions(); bool hasViewChanged(); bool isViewChanging(); @@ -97,8 +86,6 @@ public slots: void clearAllNodesBufferIndex(); void setDisableFastVoxelPipeline(bool disableFastVoxelPipeline); - void setUseVoxelShader(bool useVoxelShader); - void setVoxelsAsPoints(bool voxelsAsPoints); protected: float _treeScale; @@ -140,8 +127,6 @@ private: static bool killSourceVoxelsOperation(OctreeElement* element, void* extraData); static bool forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData); static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); - static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); - static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); @@ -191,14 +176,8 @@ private: void initVoxelMemory(); void cleanupVoxelMemory(); - bool _useVoxelShader; - bool _voxelsAsPoints; - bool _voxelShaderModeWhenVoxelsAsPointsEnabled; - GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO GLuint _vboVoxelsIndicesID; /// when using voxel shader, we'll use this VBO for our indexes - VoxelShaderVBOData* _writeVoxelShaderData; - VoxelShaderVBOData* _readVoxelShaderData; GLuint _vboVerticesID; GLuint _vboColorsID; @@ -258,17 +237,6 @@ private: float _lastKnownVoxelSizeScale; int _lastKnownBoundaryLevelAdjust; - bool _inOcclusions; - bool _showCulledSharedFaces; ///< Flag visibility of culled faces - bool _usePrimitiveRenderer; ///< Flag primitive renderer for use - PrimitiveRenderer* _renderer; ///< Voxel renderer - - static const unsigned int _sNumOctantsPerHemiVoxel = 4; - static int _sCorrectedChildIndex[8]; - static unsigned short _sSwizzledOcclusionBits[64]; ///< Swizzle value of bit pairs of the value of index - static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask - static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask - // haze bool _drawHaze; float _farHazeDistance; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index cb35f5d246..c747bf6d9e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -138,7 +138,15 @@ static int fbxGeometryMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType >(); -template QVariant readBinaryArray(QDataStream& in) { +template int streamSize() { + return sizeof(T); +} + +template int streamSize() { + return 1; +} + +template QVariant readBinaryArray(QDataStream& in, int& position) { quint32 arrayLength; quint32 encoding; quint32 compressedLength; @@ -146,6 +154,7 @@ template QVariant readBinaryArray(QDataStream& in) { in >> arrayLength; in >> encoding; in >> compressedLength; + position += sizeof(quint32) * 3; QVector values; const unsigned int DEFLATE_ENCODING = 1; @@ -154,6 +163,7 @@ template QVariant readBinaryArray(QDataStream& in) { QByteArray compressed(sizeof(quint32) + compressedLength, 0); *((quint32*)compressed.data()) = qToBigEndian(arrayLength * sizeof(T)); in.readRawData(compressed.data() + sizeof(quint32), compressedLength); + position += compressedLength; QByteArray uncompressed = qUncompress(compressed); QDataStream uncompressedIn(uncompressed); uncompressedIn.setByteOrder(QDataStream::LittleEndian); @@ -167,65 +177,74 @@ template QVariant readBinaryArray(QDataStream& in) { for (quint32 i = 0; i < arrayLength; i++) { T value; in >> value; + position += streamSize(); values.append(value); } } return QVariant::fromValue(values); } -QVariant parseBinaryFBXProperty(QDataStream& in) { +QVariant parseBinaryFBXProperty(QDataStream& in, int& position) { char ch; in.device()->getChar(&ch); + position++; switch (ch) { case 'Y': { qint16 value; in >> value; + position += sizeof(qint16); return QVariant::fromValue(value); } case 'C': { bool value; in >> value; + position++; return QVariant::fromValue(value); } case 'I': { qint32 value; in >> value; + position += sizeof(qint32); return QVariant::fromValue(value); } case 'F': { float value; in >> value; + position += sizeof(float); return QVariant::fromValue(value); } case 'D': { double value; in >> value; + position += sizeof(double); return QVariant::fromValue(value); } case 'L': { qint64 value; in >> value; + position += sizeof(qint64); return QVariant::fromValue(value); } case 'f': { - return readBinaryArray(in); + return readBinaryArray(in, position); } case 'd': { - return readBinaryArray(in); + return readBinaryArray(in, position); } case 'l': { - return readBinaryArray(in); + return readBinaryArray(in, position); } case 'i': { - return readBinaryArray(in); + return readBinaryArray(in, position); } case 'b': { - return readBinaryArray(in); + return readBinaryArray(in, position); } case 'S': case 'R': { quint32 length; in >> length; + position += sizeof(quint32) + length; return QVariant::fromValue(in.device()->read(length)); } default: @@ -233,8 +252,8 @@ QVariant parseBinaryFBXProperty(QDataStream& in) { } } -FBXNode parseBinaryFBXNode(QDataStream& in) { - quint32 endOffset; +FBXNode parseBinaryFBXNode(QDataStream& in, int& position) { + qint32 endOffset; quint32 propertyCount; quint32 propertyListLength; quint8 nameLength; @@ -243,21 +262,23 @@ FBXNode parseBinaryFBXNode(QDataStream& in) { in >> propertyCount; in >> propertyListLength; in >> nameLength; + position += sizeof(quint32) * 3 + sizeof(quint8); FBXNode node; - const unsigned int MIN_VALID_OFFSET = 40; + const int MIN_VALID_OFFSET = 40; if (endOffset < MIN_VALID_OFFSET || nameLength == 0) { // use a null name to indicate a null node return node; } node.name = in.device()->read(nameLength); + position += nameLength; for (quint32 i = 0; i < propertyCount; i++) { - node.properties.append(parseBinaryFBXProperty(in)); + node.properties.append(parseBinaryFBXProperty(in, position)); } - while (endOffset > in.device()->pos()) { - FBXNode child = parseBinaryFBXNode(in); + while (endOffset > position) { + FBXNode child = parseBinaryFBXNode(in, position); if (child.name.isNull()) { return node; @@ -416,11 +437,12 @@ FBXNode parseFBX(QIODevice* device) { // skip the rest of the header const int HEADER_SIZE = 27; in.skipRawData(HEADER_SIZE); + int position = HEADER_SIZE; // parse the top-level node FBXNode top; while (device->bytesAvailable()) { - FBXNode next = parseBinaryFBXNode(in); + FBXNode next = parseBinaryFBXNode(in, position); if (next.name.isNull()) { return top; @@ -2516,7 +2538,11 @@ QByteArray writeMapping(const QVariantHash& mapping) { FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast(&model)); buffer.open(QIODevice::ReadOnly); - return extractFBXGeometry(parseFBX(&buffer), mapping, loadLightmaps, lightmapLevel); + return readFBX(&buffer, mapping, loadLightmaps, lightmapLevel); +} + +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { + return extractFBXGeometry(parseFBX(device), mapping, loadLightmaps, lightmapLevel); } bool addMeshVoxelsOperation(OctreeElement* element, void* extraData) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 659893c128..736da3a349 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -24,6 +24,8 @@ #include #include +class QIODevice; + class FBXNode; typedef QList FBXNodeList; @@ -272,6 +274,10 @@ QByteArray writeMapping(const QVariantHash& mapping); /// \exception QString if an error occurs in parsing FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); +/// Reads FBX geometry from the supplied model and mapping data. +/// \exception QString if an error occurs in parsing +FBXGeometry readFBX(QIODevice* device, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); + /// Reads SVO geometry from the supplied model data. FBXGeometry readSVO(const QByteArray& model); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index d64752dce0..6091b0cdd2 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -73,6 +73,7 @@ void DomainHandler::hardReset() { qDebug() << "Hard reset in NodeList DomainHandler."; _iceDomainID = QUuid(); + _iceServerSockAddr = HifiSockAddr(); _hostname = QString(); _sockAddr.setAddress(QHostAddress::Null); } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d6aad45b0d..0c92125b53 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -728,6 +728,10 @@ bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc } recurseTreeWithOperation(findRayIntersectionOp, &args); + + if (args.found) { + args.distance *= (float)(TREE_SCALE); // scale back up to meters + } if (gotLock) { unlock(); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index cc8db8783f..4099384aea 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -39,6 +39,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); + qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); } QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) { @@ -206,3 +207,14 @@ void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid) { uuid = fromString; } +QScriptValue qSizeFToScriptValue(QScriptEngine* engine, const QSizeF& qSizeF) { + QScriptValue obj = engine->newObject(); + obj.setProperty("width", qSizeF.width()); + obj.setProperty("height", qSizeF.height()); + return obj; +} + +void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF) { + qSizeF.setWidth(object.property("width").toVariant().toFloat()); + qSizeF.setHeight(object.property("height").toVariant().toFloat()); +} diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index b9278c9f2d..ca4898b65c 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -81,4 +81,8 @@ void collisionFromScriptValue(const QScriptValue &object, Collision& collision); QScriptValue quuidToScriptValue(QScriptEngine* engine, const QUuid& uuid); void quuidFromScriptValue(const QScriptValue& object, QUuid& uuid); +//Q_DECLARE_METATYPE(QSizeF) // Don't need to to this becase it's arleady a meta type +QScriptValue qSizeFToScriptValue(QScriptEngine* engine, const QSizeF& qSizeF); +void qSizeFFromScriptValue(const QScriptValue& object, QSizeF& qSizeF); + #endif // hifi_RegisteredMetaTypes_h diff --git a/libraries/shared/src/ShutdownEventListener.cpp b/libraries/shared/src/ShutdownEventListener.cpp index 6cd7592b69..94975b2418 100644 --- a/libraries/shared/src/ShutdownEventListener.cpp +++ b/libraries/shared/src/ShutdownEventListener.cpp @@ -9,21 +9,43 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "ShutdownEventListener.h" #ifdef Q_OS_WIN #include +#else +#include #endif -ShutdownEventListener::ShutdownEventListener(QObject* parent) : QObject(parent) { +ShutdownEventListener& ShutdownEventListener::getInstance() { + static ShutdownEventListener staticInstance; + return staticInstance; } +void signalHandler(int param) { + // tell the qApp it should quit + QMetaObject::invokeMethod(qApp, "quit"); +} + +ShutdownEventListener::ShutdownEventListener(QObject* parent) : + QObject(parent) +{ +#ifndef Q_OS_WIN + // be a signal handler for SIGTERM so we can stop our children when we get it + signal(SIGTERM, signalHandler); +#endif +} + + bool ShutdownEventListener::nativeEventFilter(const QByteArray &eventType, void* msg, long* result) { #ifdef Q_OS_WIN if (eventType == "windows_generic_MSG") { MSG* message = (MSG*)msg; if (message->message == WM_CLOSE) { - emit receivedCloseEvent(); + // tell our registered application to quit + QMetaObject::invokeMethod(qApp, "quit"); } } #endif diff --git a/libraries/shared/src/ShutdownEventListener.h b/libraries/shared/src/ShutdownEventListener.h index e39770c13d..f6d50401b2 100644 --- a/libraries/shared/src/ShutdownEventListener.h +++ b/libraries/shared/src/ShutdownEventListener.h @@ -18,12 +18,11 @@ class ShutdownEventListener : public QObject, public QAbstractNativeEventFilter { Q_OBJECT public: - ShutdownEventListener(QObject* parent = NULL); + static ShutdownEventListener& getInstance(); virtual bool nativeEventFilter(const QByteArray& eventType, void* message, long* result); - -signals: - void receivedCloseEvent(); +private: + ShutdownEventListener(QObject* parent = 0); }; #endif // hifi_ShutdownEventListener_h