From 23450e929bb7927d4c9be20fcda5b471ad5055c8 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 13 Sep 2016 14:21:43 -0700
Subject: [PATCH 01/28] Add special avatar id for attaching overlays

---
 interface/src/Application.cpp                 | 39 ++++++++++---------
 interface/src/Application.h                   |  2 +-
 interface/src/InterfaceParentFinder.cpp       |  8 ++++
 interface/src/Menu.cpp                        | 30 +++++++-------
 interface/src/avatar/AvatarActionHold.cpp     |  2 +-
 interface/src/avatar/AvatarManager.cpp        |  5 ++-
 interface/src/avatar/AvatarManager.h          |  2 +-
 .../src/scripting/HMDScriptingInterface.cpp   |  2 +-
 interface/src/ui/OverlayConductor.cpp         |  6 +--
 interface/src/ui/PreferencesDialog.cpp        |  2 +-
 interface/src/ui/Stats.cpp                    |  2 +-
 interface/src/ui/overlays/OverlaysPayload.cpp |  2 +-
 libraries/shared/src/SpatiallyNestable.cpp    |  2 +-
 13 files changed, 58 insertions(+), 46 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index ec0a2687ba..1361938fbb 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -671,10 +671,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     // send a location update immediately
     discoverabilityManager->updateLocation();
 
+    auto myAvatar = getMyAvatar();
+
     connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded);
     connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled);
     connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated);
-    connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
+    connect(nodeList.data(), &NodeList::uuidChanged, myAvatar.get(), &MyAvatar::setSessionUUID);
     connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID);
     connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
 
@@ -704,7 +706,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount);
 
     // Save avatar location immediately after a teleport.
-    connect(getMyAvatar(), &MyAvatar::positionGoneTo,
+    connect(myAvatar.get(), &MyAvatar::positionGoneTo,
         DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
 
     auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
@@ -741,7 +743,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent);
 
     // send the identity packet for our avatar each second to our avatar mixer
-    connect(&identityPacketTimer, &QTimer::timeout, getMyAvatar(), &MyAvatar::sendIdentityPacket);
+    connect(&identityPacketTimer, &QTimer::timeout, myAvatar.get(), &MyAvatar::sendIdentityPacket);
     identityPacketTimer.start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
 
     const char** constArgv = const_cast<const char**>(argv);
@@ -820,7 +822,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     // Tell our entity edit sender about our known jurisdictions
     _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
-    _entityEditSender.setMyAvatar(getMyAvatar());
+    _entityEditSender.setMyAvatar(myAvatar.get());
 
     // For now we're going to set the PPS for outbound packets to be super high, this is
     // probably not the right long term solution. But for now, we're going to do this to
@@ -841,7 +843,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
         bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
 
     // FIXME -- I'm a little concerned about this.
-    connect(getMyAvatar()->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded,
+    connect(myAvatar->getSkeletonModel().get(), &SkeletonModel::skeletonLoaded,
         this, &Application::checkSkeleton, Qt::QueuedConnection);
 
     // Setup the userInputMapper with the actions
@@ -1055,7 +1057,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     applicationUpdater->checkForUpdate();
 
     // Now that menu is initialized we can sync myAvatar with it's state.
-    getMyAvatar()->updateMotionBehaviorFromMenu();
+    myAvatar->updateMotionBehaviorFromMenu();
 
 // FIXME spacemouse code still needs cleanup
 #if 0
@@ -1090,10 +1092,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     static int SEND_STATS_INTERVAL_MS = 10000;
     static int NEARBY_AVATAR_RADIUS_METERS = 10;
 
-    static glm::vec3 lastAvatarPosition = getMyAvatar()->getPosition();
+    static glm::vec3 lastAvatarPosition = myAvatar->getPosition();
     static glm::mat4 lastHMDHeadPose = getHMDSensorPose();
-    static controller::Pose lastLeftHandPose = getMyAvatar()->getLeftHandPose();
-    static controller::Pose lastRightHandPose = getMyAvatar()->getRightHandPose();
+    static controller::Pose lastLeftHandPose = myAvatar->getLeftHandPose();
+    static controller::Pose lastRightHandPose = myAvatar->getRightHandPose();
 
     // Periodically send fps as a user activity event
     QTimer* sendStatsTimer = new QTimer(this);
@@ -1141,7 +1143,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
         properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
 
-        glm::vec3 avatarPosition = getMyAvatar()->getPosition();
+        auto myAvatar = getMyAvatar();
+        glm::vec3 avatarPosition = myAvatar->getPosition();
         properties["avatar_has_moved"] = lastAvatarPosition != avatarPosition;
         lastAvatarPosition = avatarPosition;
 
@@ -1156,8 +1159,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
         properties["hmd_head_pose_changed"] = isHMDMode() && (hmdHeadPose != lastHMDHeadPose);
         lastHMDHeadPose = hmdHeadPose;
 
-        auto leftHandPose = getMyAvatar()->getLeftHandPose();
-        auto rightHandPose = getMyAvatar()->getRightHandPose();
+        auto leftHandPose = myAvatar->getLeftHandPose();
+        auto rightHandPose = myAvatar->getRightHandPose();
         // controller::Pose considers two poses to be different if either are invalid. In our case, we actually
         // want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first.
         properties["hand_pose_changed"] =
@@ -1204,7 +1207,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
 
     OctreeEditPacketSender* packetSender = entityScriptingInterface->getPacketSender();
     EntityEditPacketSender* entityPacketSender = static_cast<EntityEditPacketSender*>(packetSender);
-    entityPacketSender->setMyAvatar(getMyAvatar());
+    entityPacketSender->setMyAvatar(myAvatar.get());
 
     connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
     qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
@@ -1581,7 +1584,7 @@ void Application::initializeUi() {
     FileScriptingInterface* fileDownload = new FileScriptingInterface(engine);
     rootContext->setContextProperty("File", fileDownload);
     connect(fileDownload, &FileScriptingInterface::unzipSuccess, this, &Application::showAssetServerWidget);
-    rootContext->setContextProperty("MyAvatar", getMyAvatar());
+    rootContext->setContextProperty("MyAvatar", getMyAvatar().get());
     rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
     rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
     rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
@@ -3331,7 +3334,7 @@ void Application::init() {
             entity->setCollisionSound(sound);
         }
     }, Qt::QueuedConnection);
-    connect(getMyAvatar(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {
+    connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) {
         if (auto avatar = getMyAvatar()) {
             auto sound = DependencyManager::get<SoundCache>()->getSound(newURL);
             avatar->setCollisionSound(sound);
@@ -3387,7 +3390,7 @@ void Application::updateMyAvatarLookAtPosition() {
         }
     } else {
         AvatarSharedPointer lookingAt = myAvatar->getLookAtTargetAvatar().lock();
-        if (lookingAt && myAvatar != lookingAt.get()) {
+        if (lookingAt && myAvatar.get() != lookingAt.get()) {
             //  If I am looking at someone else, look directly at one of their eyes
             isLookingAtSomeone = true;
             auto lookingAtHead = static_pointer_cast<Avatar>(lookingAt)->getHead();
@@ -4236,7 +4239,7 @@ PickRay Application::computePickRay(float x, float y) const {
     return result;
 }
 
-MyAvatar* Application::getMyAvatar() const {
+std::shared_ptr<MyAvatar> Application::getMyAvatar() const {
     return DependencyManager::get<AvatarManager>()->getMyAvatar();
 }
 
@@ -4824,7 +4827,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
     scriptEngine->registerGlobalObject("Rates", new RatesScriptingInterface(this));
 
     // hook our avatar and avatar hash map object into this script engine
-    scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar());
+    scriptEngine->registerGlobalObject("MyAvatar", getMyAvatar().get());
     qScriptRegisterMetaType(scriptEngine, audioListenModeToScriptValue, audioListenModeFromScriptValue);
 
     scriptEngine->registerGlobalObject("AvatarList", DependencyManager::get<AvatarManager>().data());
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 02682defca..dd4610453b 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -401,7 +401,7 @@ private:
 
     int sendNackPackets();
 
-    MyAvatar* getMyAvatar() const;
+    std::shared_ptr<MyAvatar> getMyAvatar() const;
 
     void checkSkeleton() const;
 
diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp
index b1db63debd..7c6c23616d 100644
--- a/interface/src/InterfaceParentFinder.cpp
+++ b/interface/src/InterfaceParentFinder.cpp
@@ -13,9 +13,12 @@
 #include <EntityTree.h>
 #include <EntityTreeRenderer.h>
 #include <avatar/AvatarManager.h>
+#include <AvatarData.h>
 
 #include "InterfaceParentFinder.h"
 
+
+
 SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const {
     SpatiallyNestableWeakPointer parent;
 
@@ -45,6 +48,11 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& s
         return parent;
     }
 
+    if (parentID == AVATAR_SELF_ID) {
+        success = true;
+        return avatarManager->getMyAvatar();
+    }
+
     success = false;
     return parent;
 }
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 08abbf63d2..79033dbff7 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -166,7 +166,7 @@ Menu::Menu() {
     // Avatar menu ----------------------------------
     MenuWrapper* avatarMenu = addMenu("Avatar");
     auto avatarManager = DependencyManager::get<AvatarManager>();
-    QObject* avatar = avatarManager->getMyAvatar();
+    auto avatar = avatarManager->getMyAvatar();
 
     // Avatar > Attachments...
     auto action = addActionToQMenuAndActionHash(avatarMenu, MenuOption::Attachments);
@@ -182,19 +182,19 @@ Menu::Menu() {
     addActionToQMenuAndActionHash(avatarSizeMenu,
         MenuOption::IncreaseAvatarSize,
         0, // QML Qt::Key_Plus,
-        avatar, SLOT(increaseSize()));
+        avatar.get(), SLOT(increaseSize()));
 
     // Avatar > Size > Decrease
     addActionToQMenuAndActionHash(avatarSizeMenu,
         MenuOption::DecreaseAvatarSize,
         0, // QML Qt::Key_Minus,
-        avatar, SLOT(decreaseSize()));
+        avatar.get(), SLOT(decreaseSize()));
 
     // Avatar > Size > Reset
     addActionToQMenuAndActionHash(avatarSizeMenu,
         MenuOption::ResetAvatarSize,
         0, // QML Qt::Key_Equal,
-        avatar, SLOT(resetSize()));
+        avatar.get(), SLOT(resetSize()));
 
     // Avatar > Reset Sensors
     addActionToQMenuAndActionHash(avatarMenu,
@@ -486,38 +486,38 @@ Menu::Menu() {
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderOtherLookAtVectors, 0, false);
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false);
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false,
-        avatar, SLOT(setEnableDebugDrawDefaultPose(bool)));
+        avatar.get(), SLOT(setEnableDebugDrawDefaultPose(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawAnimPose, 0, false,
-        avatar, SLOT(setEnableDebugDrawAnimPose(bool)));
+        avatar.get(), SLOT(setEnableDebugDrawAnimPose(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawPosition, 0, false,
-        avatar, SLOT(setEnableDebugDrawPosition(bool)));
+        avatar.get(), SLOT(setEnableDebugDrawPosition(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true,
-        avatar, SLOT(setEnableMeshVisible(bool)));
+        avatar.get(), SLOT(setEnableMeshVisible(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false);
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::TurnWithHead, 0, false);
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::UseAnimPreAndPostRotations, 0, true,
-        avatar, SLOT(setUseAnimPreAndPostRotations(bool)));
+        avatar.get(), SLOT(setUseAnimPreAndPostRotations(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true,
-        avatar, SLOT(setEnableInverseKinematics(bool)));
+        avatar.get(), SLOT(setEnableInverseKinematics(bool)));
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
-        avatar, SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
+        avatar.get(), SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
 
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ActionMotorControl,
-        Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()),
+        Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar.get(), SLOT(updateMotionBehaviorFromMenu()),
         UNSPECIFIED_POSITION, "Developer");
 
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ScriptedMotorControl, 0, true,
-        avatar, SLOT(updateMotionBehaviorFromMenu()),
+        avatar.get(), SLOT(updateMotionBehaviorFromMenu()),
         UNSPECIFIED_POSITION, "Developer");
 
     addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableCharacterController, 0, true,
-        avatar, SLOT(updateMotionBehaviorFromMenu()),
+        avatar.get(), SLOT(updateMotionBehaviorFromMenu()),
         UNSPECIFIED_POSITION, "Developer");
 
     // Developer > Hands >>>
     MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false,
-        avatar, SLOT(setEnableDebugDrawHandControllers(bool)));
+        avatar.get(), SLOT(setEnableDebugDrawHandControllers(bool)));
     addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true,
         qApp, SLOT(setLowVelocityFilter(bool)));
 
diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp
index 51171b9c6b..20d27fe548 100644
--- a/interface/src/avatar/AvatarActionHold.cpp
+++ b/interface/src/avatar/AvatarActionHold.cpp
@@ -37,7 +37,7 @@ AvatarActionHold::~AvatarActionHold() {
 }
 
 bool AvatarActionHold::getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation) {
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
     MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr;
     if (!controller) {
         qDebug() << "AvatarActionHold::getAvatarRigidBodyLocation failed to get character controller";
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 441130bd83..18856ff914 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -31,6 +31,7 @@
 #include <SettingHandle.h>
 #include <UsersScriptingInterface.h>
 #include <UUID.h>
+#include <AvatarData.h>
 
 #include "Application.h"
 #include "Avatar.h"
@@ -323,7 +324,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
         // an id of null. Thus this code handles any collision in which one of the participating objects is
         // my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
         if (collision.idA.isNull() || collision.idB.isNull()) {
-            MyAvatar* myAvatar = getMyAvatar();
+            auto myAvatar = getMyAvatar();
             auto collisionSound = myAvatar->getCollisionSound();
             if (collisionSound) {
                 const auto characterController = myAvatar->getCharacterController();
@@ -399,7 +400,7 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
 
 
 AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) {
-    if (sessionID == _myAvatar->getSessionUUID()) {
+    if (sessionID == AVATAR_SELF_ID || sessionID == _myAvatar->getSessionUUID()) {
         return _myAvatar;
     }
 
diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index f09aa9791c..8cdb8006e6 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -39,7 +39,7 @@ public:
 
     void init();
 
-    MyAvatar* getMyAvatar() { return _myAvatar.get(); }
+    std::shared_ptr<MyAvatar> getMyAvatar() { return _myAvatar; }
     AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) override;
 
     void updateMyAvatar(float deltaTime);
diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp
index b031e05789..a4676428a9 100644
--- a/interface/src/scripting/HMDScriptingInterface.cpp
+++ b/interface/src/scripting/HMDScriptingInterface.cpp
@@ -79,7 +79,7 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
 }
 
 glm::mat4 HMDScriptingInterface::getWorldHMDMatrix() const {
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
     return myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
 }
 
diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp
index 2ee106b6b3..dbf58c5cbc 100644
--- a/interface/src/ui/OverlayConductor.cpp
+++ b/interface/src/ui/OverlayConductor.cpp
@@ -43,7 +43,7 @@ bool OverlayConductor::headOutsideOverlay() const {
 
 bool OverlayConductor::updateAvatarIsAtRest() {
 
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
 
     const quint64 REST_ENABLE_TIME_USECS = 1000 * 1000; // 1 s
     const quint64 REST_DISABLE_TIME_USECS = 200 * 1000;  // 200 ms
@@ -69,7 +69,7 @@ bool OverlayConductor::updateAvatarIsAtRest() {
 }
 
 bool OverlayConductor::updateAvatarHasDriveInput() {
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
 
     const quint64 DRIVE_ENABLE_TIME_USECS = 200 * 1000;  // 200 ms
     const quint64 DRIVE_DISABLE_TIME_USECS = 1000 * 1000; // 1 s
@@ -103,7 +103,7 @@ void OverlayConductor::update(float dt) {
     auto offscreenUi = DependencyManager::get<OffscreenUi>();
     bool currentVisible = !offscreenUi->getDesktop()->property("pinned").toBool();
 
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
     // centerUI when hmd mode is first enabled and mounted
     if (qApp->isHMDMode() && qApp->getActiveDisplayPlugin()->isDisplayVisible()) {
         if (!_hmdMode) {
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 2a0094de29..c47da011e0 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -32,7 +32,7 @@
 void setupPreferences() {
     auto preferences = DependencyManager::get<Preferences>();
 
-    MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+    auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
     static const QString AVATAR_BASICS { "Avatar Basics" };
     {
         auto getter = [=]()->QString { return myAvatar->getDisplayName(); };
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index fbe272a562..8141d1a0db 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -170,7 +170,7 @@ void Stats::updateStats(bool force) {
     STAT_UPDATE(entitiesPing, octreeServerCount ? totalPingOctree / octreeServerCount : -1);
 
     // Third column, avatar stats
-    MyAvatar* myAvatar = avatarManager->getMyAvatar();
+    auto myAvatar = avatarManager->getMyAvatar();
     glm::vec3 avatarPos = myAvatar->getPosition();
     STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z));
     STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.01f);
diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp
index 174873a5c7..7cc74d60e0 100644
--- a/interface/src/ui/overlays/OverlaysPayload.cpp
+++ b/interface/src/ui/overlays/OverlaysPayload.cpp
@@ -64,7 +64,7 @@ namespace render {
         if (args) {
             if (overlay->getAnchor() == Overlay::MY_AVATAR) {
                 auto batch = args->_batch;
-                MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+                auto avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
                 glm::quat myAvatarRotation = avatar->getOrientation();
                 glm::vec3 myAvatarPosition = avatar->getPosition();
                 float angle = glm::degrees(glm::angle(myAvatarRotation));
diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp
index b37fcd3699..19fa9f81b3 100644
--- a/libraries/shared/src/SpatiallyNestable.cpp
+++ b/libraries/shared/src/SpatiallyNestable.cpp
@@ -856,7 +856,7 @@ QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
     _childrenLock.withReadLock([&] {
         foreach(SpatiallyNestableWeakPointer childWP, _children.values()) {
             SpatiallyNestablePointer child = childWP.lock();
-            if (child && child->_parentKnowsMe && child->getParentID() == getID()) {
+            if (child && child->_parentKnowsMe && (child->getParentID() == getID() || child->getParentID() == QUuid("{00000000-0000-0000-0000-000000000001}"))) {
                 children << child;
             }
         }

From 5e8c8f84b5e5a9d75c00818b6e756bd7f881af65 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 13 Sep 2016 16:24:22 -0700
Subject: [PATCH 02/28] Handle edge cases of AVATAR_SELF_ID being used with
 entities

---
 libraries/avatars/src/AvatarData.h                  | 5 +----
 libraries/entities/src/EntityScriptingInterface.cpp | 9 +++++++++
 libraries/shared/src/SharedUtil.h                   | 6 ++++++
 libraries/shared/src/SpatiallyNestable.cpp          | 7 ++++++-
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 715c24b8ee..a5314bf4a8 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -55,6 +55,7 @@ typedef unsigned long long quint64;
 #include <NumericalConstants.h>
 #include <Packed.h>
 #include <ThreadSafeValueCache.h>
+#include <SharedUtil.h>
 
 #include "AABox.h"
 #include "HeadData.h"
@@ -138,10 +139,6 @@ class AttachmentData;
 class Transform;
 using TransformPointer = std::shared_ptr<Transform>;
 
-// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead.  This allows
-// the value to be reset when the sessionID changes.
-const QUuid AVATAR_SELF_ID = QUuid("{00000000-0000-0000-0000-000000000001}");
-
 class AvatarData : public QObject, public SpatiallyNestable {
     Q_OBJECT
 
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index fe7fccaece..656a6bd281 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -12,6 +12,7 @@
 
 #include "EntityItemID.h"
 #include <VariantMapToScriptValue.h>
+#include <SharedUtil.h>
 #include <SpatialParentFinder.h>
 
 #include "EntitiesLogging.h"
@@ -181,6 +182,11 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
         propertiesWithSimID.setOwningAvatarID(myNodeID);
     }
 
+    if (propertiesWithSimID.getParentID() == AVATAR_SELF_ID) {
+        qDebug() << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
+        propertiesWithSimID.setParentID(QUuid());
+    }
+
     auto dimensions = propertiesWithSimID.getDimensions();
     float volume = dimensions.x * dimensions.y * dimensions.z;
     auto density = propertiesWithSimID.getDensity();
@@ -357,6 +363,9 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
 
             if (!scriptSideProperties.parentIDChanged()) {
                 properties.setParentID(entity->getParentID());
+            } else if (scriptSideProperties.getParentID() == AVATAR_SELF_ID) {
+                qDebug() << "ERROR: Cannot set entity parent ID to the local-only MyAvatar ID";
+                properties.setParentID(QUuid());
             }
             if (!scriptSideProperties.parentJointIndexChanged()) {
                 properties.setParentJointIndex(entity->getParentJointIndex());
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index f3e5625484..0470a032ce 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -23,6 +23,12 @@
 
 #include <QtCore/QDebug>
 #include <QtCore/QCoreApplication>
+#include <QUuid>
+
+
+// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead.  This allows
+// the value to be reset when the sessionID changes.
+const QUuid AVATAR_SELF_ID = QUuid("{00000000-0000-0000-0000-000000000001}");
 
 // Access to the global instance pointer to enable setting / unsetting
 template <typename T>
diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp
index 19fa9f81b3..f75557f73f 100644
--- a/libraries/shared/src/SpatiallyNestable.cpp
+++ b/libraries/shared/src/SpatiallyNestable.cpp
@@ -12,6 +12,7 @@
 #include <QQueue>
 
 #include "DependencyManager.h"
+#include "SharedUtil.h"
 #include "SpatiallyNestable.h"
 
 const float defaultAACubeSize = 1.0f;
@@ -856,7 +857,11 @@ QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
     _childrenLock.withReadLock([&] {
         foreach(SpatiallyNestableWeakPointer childWP, _children.values()) {
             SpatiallyNestablePointer child = childWP.lock();
-            if (child && child->_parentKnowsMe && (child->getParentID() == getID() || child->getParentID() == QUuid("{00000000-0000-0000-0000-000000000001}"))) {
+            // An object can set MyAvatar to be its parent using two IDs: the session ID and the special AVATAR_SELF_ID
+            // Because we only recognize an object as having one ID, we need to check for the second possible ID here.
+            // In practice, the AVATAR_SELF_ID should only be used for local-only objects.
+            if (child && child->_parentKnowsMe && (child->getParentID() == getID() ||
+                    (getNestableType() == NestableType::Avatar && child->getParentID() == AVATAR_SELF_ID))) {
                 children << child;
             }
         }

From e50649102678dde1b8e2d497125f97900eeb684a Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 13 Sep 2016 16:35:13 -0700
Subject: [PATCH 03/28] Remove blank lines

---
 interface/src/InterfaceParentFinder.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp
index 7c6c23616d..1979f8344b 100644
--- a/interface/src/InterfaceParentFinder.cpp
+++ b/interface/src/InterfaceParentFinder.cpp
@@ -17,8 +17,6 @@
 
 #include "InterfaceParentFinder.h"
 
-
-
 SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID, bool& success, SpatialParentTree* entityTree) const {
     SpatiallyNestableWeakPointer parent;
 

From f28962af129335d2a79b1d741229c64ba2e3d8ad Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 11:10:21 -0700
Subject: [PATCH 04/28] Remove dead class from oglplus helpers

---
 libraries/gl/src/gl/OglplusHelpers.cpp | 81 --------------------------
 libraries/gl/src/gl/OglplusHelpers.h   | 27 ---------
 2 files changed, 108 deletions(-)

diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp
index fc02d75329..587c6488c8 100644
--- a/libraries/gl/src/gl/OglplusHelpers.cpp
+++ b/libraries/gl/src/gl/OglplusHelpers.cpp
@@ -480,84 +480,3 @@ ShapeWrapperPtr loadLaser(const ProgramPtr& program) {
     return std::make_shared<shapes::ShapeWrapper>(shapes::ShapeWrapper("Position", shapes::Laser(), *program));
 }
 
-void TextureRecycler::setSize(const uvec2& size) {
-    if (size == _size) {
-        return;
-    }
-    _size = size;
-    while (!_readyTextures.empty()) {
-        _readyTextures.pop();
-    }
-    std::set<Map::key_type> toDelete;
-    std::for_each(_allTextures.begin(), _allTextures.end(), [&](Map::const_reference item) {
-        if (!item.second._active && item.second._size != _size) {
-            toDelete.insert(item.first);
-        }
-    });
-    std::for_each(toDelete.begin(), toDelete.end(), [&](Map::key_type key) {
-        _allTextures.erase(key);
-    });
-}
-
-void TextureRecycler::clear() {
-    while (!_readyTextures.empty()) {
-        _readyTextures.pop();
-    }
-    _allTextures.clear();
-}
-
-TexturePtr TextureRecycler::getNextTexture() {
-    using namespace oglplus;
-    if (_readyTextures.empty()) {
-        TexturePtr newTexture(new Texture());
-
-        if (_useMipmaps) {
-            Context::Bound(oglplus::Texture::Target::_2D, *newTexture)
-                .MinFilter(TextureMinFilter::LinearMipmapLinear)
-                .MagFilter(TextureMagFilter::Linear)
-                .WrapS(TextureWrap::ClampToEdge)
-                .WrapT(TextureWrap::ClampToEdge)
-                .Anisotropy(8.0f)
-                .LODBias(-0.2f)
-                .Image2D(0, PixelDataInternalFormat::RGBA8,
-                         _size.x, _size.y,
-                         0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr);
-        } else {
-            Context::Bound(oglplus::Texture::Target::_2D, *newTexture)
-                .MinFilter(TextureMinFilter::Linear)
-                .MagFilter(TextureMagFilter::Linear)
-                .WrapS(TextureWrap::ClampToEdge)
-                .WrapT(TextureWrap::ClampToEdge)
-                .Image2D(0, PixelDataInternalFormat::RGBA8,
-                         _size.x, _size.y,
-                         0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr);
-        }
-        GLuint texId = GetName(*newTexture);
-        _allTextures[texId] = TexInfo{ newTexture, _size };
-        _readyTextures.push(newTexture);
-    }
-
-    TexturePtr result = _readyTextures.front();
-    _readyTextures.pop();
-
-    GLuint texId = GetName(*result);
-    auto& item = _allTextures[texId];
-    item._active = true;
-
-    return result;
-}
-
-void TextureRecycler::recycleTexture(GLuint texture) {
-    Q_ASSERT(_allTextures.count(texture));
-    auto& item = _allTextures[texture];
-    Q_ASSERT(item._active);
-    item._active = false;
-    if (item._size != _size) {
-        // Buh-bye
-        _allTextures.erase(texture);
-        return;
-    }
-
-    _readyTextures.push(item._tex);
-}
-
diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h
index ab47689312..52e63f9431 100644
--- a/libraries/gl/src/gl/OglplusHelpers.h
+++ b/libraries/gl/src/gl/OglplusHelpers.h
@@ -188,30 +188,3 @@ protected:
 
 using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
 
-class TextureRecycler {
-public:
-    TextureRecycler(bool useMipmaps) : _useMipmaps(useMipmaps) {}
-    void setSize(const uvec2& size);
-    void clear();
-    TexturePtr getNextTexture();
-    void recycleTexture(GLuint texture);
-
-private:
-
-    struct TexInfo {
-        TexturePtr _tex;
-        uvec2 _size;
-        bool _active{ false };
-
-        TexInfo() {}
-        TexInfo(TexturePtr tex, const uvec2& size) : _tex(tex), _size(size) {}
-    };
-
-    using Map = std::map<GLuint, TexInfo>;
-    using Queue = std::queue<TexturePtr>;
-
-    Map _allTextures;
-    Queue _readyTextures;
-    uvec2 _size{ 1920, 1080 };
-    bool _useMipmaps;
-};

From d83d3fe98e826e0bd924fd7de349401e1a1f54dc Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 11:11:55 -0700
Subject: [PATCH 05/28] Make shader compilation from non-GPU code easier

---
 libraries/gl/src/gl/GLShaders.cpp        | 189 +++++++++++++++++++++++
 libraries/gl/src/gl/GLShaders.h          |  29 ++++
 libraries/gpu-gl/src/gpu/gl/GLShader.cpp |  10 +-
 libraries/gpu-gl/src/gpu/gl/GLShared.cpp | 181 ----------------------
 libraries/gpu-gl/src/gpu/gl/GLShared.h   |   2 -
 5 files changed, 226 insertions(+), 185 deletions(-)
 create mode 100644 libraries/gl/src/gl/GLShaders.cpp
 create mode 100644 libraries/gl/src/gl/GLShaders.h

diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp
new file mode 100644
index 0000000000..b8e1bf7391
--- /dev/null
+++ b/libraries/gl/src/gl/GLShaders.cpp
@@ -0,0 +1,189 @@
+#include "GLShaders.h"
+
+#include "GLLogging.h"
+
+namespace gl {
+
+
+#ifdef SEPARATE_PROGRAM
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject) {
+#else
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject) {
+#endif
+    if (shaderSource.empty()) {
+        qCDebug(glLogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
+        return false;
+    }
+
+    // Create the shader object
+    GLuint glshader = glCreateShader(shaderDomain);
+    if (!glshader) {
+        qCDebug(glLogging) << "GLShader::compileShader - failed to create the gl shader object";
+        return false;
+    }
+
+    // Assign the source
+    const int NUM_SOURCE_STRINGS = 2;
+    const GLchar* srcstr[] = { defines.c_str(), shaderSource.c_str() };
+    glShaderSource(glshader, NUM_SOURCE_STRINGS, srcstr, NULL);
+
+    // Compile !
+    glCompileShader(glshader);
+
+    // check if shader compiled
+    GLint compiled = 0;
+    glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
+
+    // if compilation fails
+    if (!compiled) {
+
+        // save the source code to a temp file so we can debug easily
+        /*
+        std::ofstream filestream;
+        filestream.open("debugshader.glsl");
+        if (filestream.is_open()) {
+        filestream << srcstr[0];
+        filestream << srcstr[1];
+        filestream.close();
+        }
+        */
+
+        GLint infoLength = 0;
+        glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
+
+        char* temp = new char[infoLength];
+        glGetShaderInfoLog(glshader, infoLength, NULL, temp);
+
+
+        /*
+        filestream.open("debugshader.glsl.info.txt");
+        if (filestream.is_open()) {
+        filestream << std::string(temp);
+        filestream.close();
+        }
+        */
+
+        qCWarning(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
+        for (auto s : srcstr) {
+            qCWarning(glLogging) << s;
+        }
+        qCWarning(glLogging) << "GLShader::compileShader - errors:";
+        qCWarning(glLogging) << temp;
+        delete[] temp;
+
+        glDeleteShader(glshader);
+        return false;
+    }
+
+    GLuint glprogram = 0;
+#ifdef SEPARATE_PROGRAM
+    // so far so good, program is almost done, need to link:
+    GLuint glprogram = glCreateProgram();
+    if (!glprogram) {
+        qCDebug(glLogging) << "GLShader::compileShader - failed to create the gl shader & gl program object";
+        return false;
+    }
+
+    glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE);
+    glAttachShader(glprogram, glshader);
+    glLinkProgram(glprogram);
+
+    GLint linked = 0;
+    glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
+
+    if (!linked) {
+        /*
+        // save the source code to a temp file so we can debug easily
+        std::ofstream filestream;
+        filestream.open("debugshader.glsl");
+        if (filestream.is_open()) {
+        filestream << shaderSource->source;
+        filestream.close();
+        }
+        */
+
+        GLint infoLength = 0;
+        glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
+
+        char* temp = new char[infoLength];
+        glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
+
+        qCDebug(glLogging) << "GLShader::compileShader -  failed to LINK the gl program object :";
+        qCDebug(glLogging) << temp;
+
+        /*
+        filestream.open("debugshader.glsl.info.txt");
+        if (filestream.is_open()) {
+        filestream << String(temp);
+        filestream.close();
+        }
+        */
+        delete[] temp;
+
+        glDeleteShader(glshader);
+        glDeleteProgram(glprogram);
+        return false;
+    }
+    programObject = glprogram;
+#endif
+    shaderObject = glshader;
+    return true;
+}
+
+GLuint compileProgram(const std::vector<GLuint>& glshaders) {
+    // A brand new program:
+    GLuint glprogram = glCreateProgram();
+    if (!glprogram) {
+        qCDebug(glLogging) << "GLShader::compileProgram - failed to create the gl program object";
+        return 0;
+    }
+
+    // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
+    // Create the program from the sub shaders
+    for (auto so : glshaders) {
+        glAttachShader(glprogram, so);
+    }
+
+    // Link!
+    glLinkProgram(glprogram);
+
+    GLint linked = 0;
+    glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
+
+    if (!linked) {
+        /*
+        // save the source code to a temp file so we can debug easily
+        std::ofstream filestream;
+        filestream.open("debugshader.glsl");
+        if (filestream.is_open()) {
+        filestream << shaderSource->source;
+        filestream.close();
+        }
+        */
+
+        GLint infoLength = 0;
+        glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
+
+        char* temp = new char[infoLength];
+        glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
+
+        qCDebug(glLogging) << "GLShader::compileProgram -  failed to LINK the gl program object :";
+        qCDebug(glLogging) << temp;
+
+        /*
+        filestream.open("debugshader.glsl.info.txt");
+        if (filestream.is_open()) {
+        filestream << std::string(temp);
+        filestream.close();
+        }
+        */
+        delete[] temp;
+
+        glDeleteProgram(glprogram);
+        return 0;
+    }
+
+    return glprogram;
+}
+
+}
diff --git a/libraries/gl/src/gl/GLShaders.h b/libraries/gl/src/gl/GLShaders.h
new file mode 100644
index 0000000000..b8c8b6770b
--- /dev/null
+++ b/libraries/gl/src/gl/GLShaders.h
@@ -0,0 +1,29 @@
+//
+//  Created by Bradley Austin Davis 2016/09/27
+//  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
+//
+
+#pragma once
+#ifndef hifi_GLShaders_h
+#define hifi_GLShaders_h
+
+#include "Config.h"
+
+#include <vector>
+#include <string>
+
+namespace gl {
+#ifdef SEPARATE_PROGRAM
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject);
+#else
+    bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject);
+#endif
+
+    GLuint compileProgram(const std::vector<GLuint>& glshaders);
+
+}
+
+#endif
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
index a2f44b9938..f8d493c25b 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp
@@ -6,6 +6,8 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 #include "GLShader.h"
+#include <gl/GLShaders.h>
+
 #include "GLBackend.h"
 
 using namespace gpu;
@@ -68,7 +70,11 @@ GLShader* compileBackendShader(GLBackend& backend, const Shader& shader) {
 
         std::string shaderDefines = glslVersion + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n" + VERSION_DEFINES[version];
 
-        bool result = compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram);
+#ifdef SEPARATE_PROGRAM
+        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, shaderObject.glprogram);
+#else
+        bool result = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader);
+#endif
         if (!result) {
             return nullptr;
         }
@@ -103,7 +109,7 @@ GLShader* compileBackendProgram(GLBackend& backend, const Shader& program) {
             }
         }
 
-        GLuint glprogram = compileProgram(shaderGLObjects);
+        GLuint glprogram = ::gl::compileProgram(shaderGLObjects);
         if (glprogram == 0) {
             return nullptr;
         }
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp
index af03da1931..943cb3c7b5 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShared.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLShared.cpp
@@ -692,187 +692,6 @@ int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Sh
     return 0; //inputsCount;
 }
 
-
-bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject) {
-    if (shaderSource.empty()) {
-        qCDebug(gpugllogging) << "GLShader::compileShader - no GLSL shader source code ? so failed to create";
-        return false;
-    }
-
-    // Create the shader object
-    GLuint glshader = glCreateShader(shaderDomain);
-    if (!glshader) {
-        qCDebug(gpugllogging) << "GLShader::compileShader - failed to create the gl shader object";
-        return false;
-    }
-
-    // Assign the source
-    const int NUM_SOURCE_STRINGS = 2;
-    const GLchar* srcstr[] = { defines.c_str(), shaderSource.c_str() };
-    glShaderSource(glshader, NUM_SOURCE_STRINGS, srcstr, NULL);
-
-    // Compile !
-    glCompileShader(glshader);
-
-    // check if shader compiled
-    GLint compiled = 0;
-    glGetShaderiv(glshader, GL_COMPILE_STATUS, &compiled);
-
-    // if compilation fails
-    if (!compiled) {
-
-        // save the source code to a temp file so we can debug easily
-        /*
-        std::ofstream filestream;
-        filestream.open("debugshader.glsl");
-        if (filestream.is_open()) {
-        filestream << srcstr[0];
-        filestream << srcstr[1];
-        filestream.close();
-        }
-        */
-
-        GLint infoLength = 0;
-        glGetShaderiv(glshader, GL_INFO_LOG_LENGTH, &infoLength);
-
-        char* temp = new char[infoLength];
-        glGetShaderInfoLog(glshader, infoLength, NULL, temp);
-
-
-        /*
-        filestream.open("debugshader.glsl.info.txt");
-        if (filestream.is_open()) {
-        filestream << std::string(temp);
-        filestream.close();
-        }
-        */
-
-        qCWarning(gpugllogging) << "GLShader::compileShader - failed to compile the gl shader object:";
-        for (auto s : srcstr) {
-            qCWarning(gpugllogging) << s;
-        }
-        qCWarning(gpugllogging) << "GLShader::compileShader - errors:";
-        qCWarning(gpugllogging) << temp;
-        delete[] temp;
-
-        glDeleteShader(glshader);
-        return false;
-    }
-
-    GLuint glprogram = 0;
-#ifdef SEPARATE_PROGRAM
-    // so far so good, program is almost done, need to link:
-    GLuint glprogram = glCreateProgram();
-    if (!glprogram) {
-        qCDebug(gpugllogging) << "GLShader::compileShader - failed to create the gl shader & gl program object";
-        return false;
-    }
-
-    glProgramParameteri(glprogram, GL_PROGRAM_SEPARABLE, GL_TRUE);
-    glAttachShader(glprogram, glshader);
-    glLinkProgram(glprogram);
-
-    GLint linked = 0;
-    glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
-
-    if (!linked) {
-        /*
-        // save the source code to a temp file so we can debug easily
-        std::ofstream filestream;
-        filestream.open("debugshader.glsl");
-        if (filestream.is_open()) {
-        filestream << shaderSource->source;
-        filestream.close();
-        }
-        */
-
-        GLint infoLength = 0;
-        glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
-
-        char* temp = new char[infoLength];
-        glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
-
-        qCDebug(gpugllogging) << "GLShader::compileShader -  failed to LINK the gl program object :";
-        qCDebug(gpugllogging) << temp;
-
-        /*
-        filestream.open("debugshader.glsl.info.txt");
-        if (filestream.is_open()) {
-        filestream << String(temp);
-        filestream.close();
-        }
-        */
-        delete[] temp;
-
-        glDeleteShader(glshader);
-        glDeleteProgram(glprogram);
-        return false;
-    }
-#endif
-
-    shaderObject = glshader;
-    programObject = glprogram;
-
-    return true;
-}
-
-GLuint compileProgram(const std::vector<GLuint>& glshaders) {
-    // A brand new program:
-    GLuint glprogram = glCreateProgram();
-    if (!glprogram) {
-        qCDebug(gpugllogging) << "GLShader::compileProgram - failed to create the gl program object";
-        return 0;
-    }
-
-    // glProgramParameteri(glprogram, GL_PROGRAM_, GL_TRUE);
-    // Create the program from the sub shaders
-    for (auto so : glshaders) {
-        glAttachShader(glprogram, so);
-    }
-
-    // Link!
-    glLinkProgram(glprogram);
-
-    GLint linked = 0;
-    glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
-
-    if (!linked) {
-        /*
-        // save the source code to a temp file so we can debug easily
-        std::ofstream filestream;
-        filestream.open("debugshader.glsl");
-        if (filestream.is_open()) {
-        filestream << shaderSource->source;
-        filestream.close();
-        }
-        */
-
-        GLint infoLength = 0;
-        glGetProgramiv(glprogram, GL_INFO_LOG_LENGTH, &infoLength);
-
-        char* temp = new char[infoLength];
-        glGetProgramInfoLog(glprogram, infoLength, NULL, temp);
-
-        qCDebug(gpugllogging) << "GLShader::compileProgram -  failed to LINK the gl program object :";
-        qCDebug(gpugllogging) << temp;
-
-        /*
-        filestream.open("debugshader.glsl.info.txt");
-        if (filestream.is_open()) {
-        filestream << std::string(temp);
-        filestream.close();
-        }
-        */
-        delete[] temp;
-
-        glDeleteProgram(glprogram);
-        return 0;
-    }
-
-    return glprogram;
-}
-
-
 void makeProgramBindings(ShaderObject& shaderObject) {
     if (!shaderObject.glprogram) {
         return;
diff --git a/libraries/gpu-gl/src/gpu/gl/GLShared.h b/libraries/gpu-gl/src/gpu/gl/GLShared.h
index b5dece7cf4..1b2724fe38 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLShared.h
+++ b/libraries/gpu-gl/src/gpu/gl/GLShared.h
@@ -44,8 +44,6 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
 int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
 int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
 int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
-bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const std::string& defines, GLuint &shaderObject, GLuint &programObject);
-GLuint compileProgram(const std::vector<GLuint>& glshaders);
 void makeProgramBindings(ShaderObject& shaderObject);
 
 enum GLSyncState {

From d3d3aa587cbaeb1d8736c8340b77597f922f23ee Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 11:12:11 -0700
Subject: [PATCH 06/28] Remove oglplus usage from OpenVR

---
 .../resources/shaders/hmd_reproject.frag      |  78 ------
 .../resources/shaders/hmd_reproject.vert      |  20 --
 plugins/openvr/src/OpenVrDisplayPlugin.cpp    | 258 +++++++++++++-----
 3 files changed, 185 insertions(+), 171 deletions(-)
 delete mode 100644 interface/resources/shaders/hmd_reproject.frag
 delete mode 100644 interface/resources/shaders/hmd_reproject.vert

diff --git a/interface/resources/shaders/hmd_reproject.frag b/interface/resources/shaders/hmd_reproject.frag
deleted file mode 100644
index adda0315a3..0000000000
--- a/interface/resources/shaders/hmd_reproject.frag
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-//  Created by Bradley Austin Davis on 2016/07/11
-//  Copyright 2013-2016 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
-//
-
-#version 410 core
-
-uniform sampler2D sampler;
-uniform mat3 reprojection = mat3(1);
-uniform mat4 inverseProjections[2];
-uniform mat4 projections[2];
-
-in vec2 vTexCoord;
-in vec3 vPosition;
-
-out vec4 FragColor;
-
-void main() {
-    vec2 uv = vTexCoord;
-
-    mat4 eyeInverseProjection;
-    mat4 eyeProjection;
-    
-    float xoffset = 1.0;
-    vec2 uvmin = vec2(0.0);
-    vec2 uvmax = vec2(1.0);
-    // determine the correct projection and inverse projection to use.
-    if (vTexCoord.x < 0.5) {
-        uvmax.x = 0.5;
-        eyeInverseProjection = inverseProjections[0];
-        eyeProjection = projections[0];
-    } else {
-        xoffset = -1.0;
-        uvmin.x = 0.5;
-        uvmax.x = 1.0;
-        eyeInverseProjection = inverseProjections[1];
-        eyeProjection = projections[1];
-    }
-
-    // Account for stereo in calculating the per-eye NDC coordinates
-    vec4 ndcSpace = vec4(vPosition, 1.0);
-    ndcSpace.x *= 2.0;
-    ndcSpace.x += xoffset;
-    
-    // Convert from NDC to eyespace
-    vec4 eyeSpace = eyeInverseProjection * ndcSpace;
-    eyeSpace /= eyeSpace.w;
-
-    // Convert to a noramlized ray 
-    vec3 ray = eyeSpace.xyz;
-    ray = normalize(ray);
-
-    // Adjust the ray by the rotation
-    ray = reprojection * ray;
-
-    // Project back on to the texture plane
-    ray *= eyeSpace.z / ray.z;
-
-    // Update the eyespace vector
-    eyeSpace.xyz = ray;
-
-    // Reproject back into NDC
-    ndcSpace = eyeProjection * eyeSpace;
-    ndcSpace /= ndcSpace.w;
-    ndcSpace.x -= xoffset;
-    ndcSpace.x /= 2.0;
-    
-    // Calculate the new UV coordinates
-    uv = (ndcSpace.xy / 2.0) + 0.5;
-    if (any(greaterThan(uv, uvmax)) || any(lessThan(uv, uvmin))) {
-        FragColor = vec4(0.0, 0.0, 0.0, 1.0);
-    } else {
-        FragColor = texture(sampler, uv);
-    }
-}
\ No newline at end of file
diff --git a/interface/resources/shaders/hmd_reproject.vert b/interface/resources/shaders/hmd_reproject.vert
deleted file mode 100644
index 923375613a..0000000000
--- a/interface/resources/shaders/hmd_reproject.vert
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-//  Created by Bradley Austin Davis on 2016/07/11
-//  Copyright 2013-2016 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
-//
-
-#version 410 core
-in vec3 Position;
-in vec2 TexCoord;
-
-out vec3 vPosition;
-out vec2 vTexCoord;
-
-void main() {
-  gl_Position = vec4(Position, 1);
-  vTexCoord = TexCoord;
-  vPosition = Position;
-}
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index 4c4fcbbd37..9247ebea0b 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -9,10 +9,13 @@
 
 #include <QtCore/QThread>
 #include <QtCore/QLoggingCategory>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDateTime>
 
 #include <GLMHelpers.h>
 
 #include <gl/Context.h>
+#include <gl/GLShaders.h>
 
 #include <gpu/Frame.h>
 #include <gpu/gl/GLBackend.h>
@@ -25,7 +28,6 @@
 #include <display-plugins/CompositorHelper.h>
 #include <ui-plugins/PluginContainer.h>
 #include <gl/OffscreenGLCanvas.h>
-#include <gl/OglplusHelpers.h>
 
 #include "OpenVrHelpers.h"
 
@@ -45,13 +47,111 @@ static vr::VRTextureBounds_t OPENVR_TEXTURE_BOUNDS_RIGHT{ 0.5f, 0, 1, 1 };
 
 #if OPENVR_THREADED_SUBMIT
 
-static QString readFile(const QString& filename) {
-    QFile file(filename);
-    file.open(QFile::Text | QFile::ReadOnly);
-    QString result;
-    result.append(QTextStream(&file).readAll());
-    return result;
+#define REPROJECTION_BINDING 1
+
+static const char* HMD_REPROJECTION_VERT = R"SHADER(
+#version 450 core
+
+out vec3 vPosition;
+out vec2 vTexCoord;
+
+void main(void) {
+    const float depth = 0.0;
+    const vec4 UNIT_QUAD[4] = vec4[4](
+        vec4(-1.0, -1.0, depth, 1.0),
+        vec4(1.0, -1.0, depth, 1.0),
+        vec4(-1.0, 1.0, depth, 1.0),
+        vec4(1.0, 1.0, depth, 1.0)
+    );
+    vec4 pos = UNIT_QUAD[gl_VertexID];
+
+    gl_Position = pos;
+    vPosition = pos.xyz;
+    vTexCoord = (pos.xy + 1.0) * 0.5;
 }
+)SHADER";
+
+static const char* HMD_REPROJECTION_FRAG = R"SHADER(
+#version 450 core
+
+uniform sampler2D sampler;
+layout(binding = 1, std140) uniform Reprojection
+{
+    mat4 projections[2];
+    mat4 inverseProjections[2];
+    mat4 reprojection;
+};
+
+in vec3 vPosition;
+in vec2 vTexCoord;
+
+out vec4 FragColor;
+
+void main() {
+    vec2 uv = vTexCoord;
+    
+    mat4 eyeInverseProjection;
+    mat4 eyeProjection;
+    
+    float xoffset = 1.0;
+    vec2 uvmin = vec2(0.0);
+    vec2 uvmax = vec2(1.0);
+    // determine the correct projection and inverse projection to use.
+    if (vTexCoord.x < 0.5) {
+        uvmax.x = 0.5;
+        eyeInverseProjection = inverseProjections[0];
+        eyeProjection = projections[0];
+    } else {
+        xoffset = -1.0;
+        uvmin.x = 0.5;
+        uvmax.x = 1.0;
+        eyeInverseProjection = inverseProjections[1];
+        eyeProjection = projections[1];
+    }
+
+    // Account for stereo in calculating the per-eye NDC coordinates
+    vec4 ndcSpace = vec4(vPosition, 1.0);
+    ndcSpace.x *= 2.0;
+    ndcSpace.x += xoffset;
+    
+    // Convert from NDC to eyespace
+    vec4 eyeSpace = eyeInverseProjection * ndcSpace;
+    eyeSpace /= eyeSpace.w;
+
+    // Convert to a noramlized ray 
+    vec3 ray = eyeSpace.xyz;
+    ray = normalize(ray);
+
+    // Adjust the ray by the rotation
+    ray = mat3(reprojection) * ray;
+
+    // Project back on to the texture plane
+    ray *= eyeSpace.z / ray.z;
+
+    // Update the eyespace vector
+    eyeSpace.xyz = ray;
+
+    // Reproject back into NDC
+    ndcSpace = eyeProjection * eyeSpace;
+    ndcSpace /= ndcSpace.w;
+    ndcSpace.x -= xoffset;
+    ndcSpace.x /= 2.0;
+    
+    // Calculate the new UV coordinates
+    uv = (ndcSpace.xy / 2.0) + 0.5;
+    if (any(greaterThan(uv, uvmax)) || any(lessThan(uv, uvmin))) {
+        FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+    } else {
+        FragColor = texture(sampler, uv);
+    }
+}
+)SHADER";
+
+struct Reprojection {
+    mat4 projections[2];
+    mat4 inverseProjections[2];
+    mat4 reprojection;
+};
 
 class OpenVrSubmitThread : public QThread, public Dependency {
 public:
@@ -60,54 +160,11 @@ public:
     using Lock = std::unique_lock<Mutex>;
     friend class OpenVrDisplayPlugin;
     std::shared_ptr<gl::OffscreenContext> _canvas;
-    BasicFramebufferWrapperPtr _framebuffer;
-    ProgramPtr _program;
-    ShapeWrapperPtr _plane;
-    struct ReprojectionUniforms {
-        int32_t reprojectionMatrix{ -1 };
-        int32_t inverseProjectionMatrix{ -1 };
-        int32_t projectionMatrix{ -1 };
-    } _reprojectionUniforms;
-
 
     OpenVrSubmitThread(OpenVrDisplayPlugin& plugin) : _plugin(plugin) { 
         setObjectName("OpenVR Submit Thread");
     }
 
-    void updateReprojectionProgram() {
-        static const QString vsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.vert";
-        static const QString fsFile = PathUtils::resourcesPath() + "/shaders/hmd_reproject.frag";
-#if LIVE_SHADER_RELOAD
-        static qint64 vsBuiltAge = 0;
-        static qint64 fsBuiltAge = 0;
-        QFileInfo vsInfo(vsFile);
-        QFileInfo fsInfo(fsFile);
-        auto vsAge = vsInfo.lastModified().toMSecsSinceEpoch();
-        auto fsAge = fsInfo.lastModified().toMSecsSinceEpoch();
-        if (!_reprojectionProgram || vsAge > vsBuiltAge || fsAge > fsBuiltAge) {
-            vsBuiltAge = vsAge;
-            fsBuiltAge = fsAge;
-#else
-        if (!_program) {
-#endif
-            QString vsSource = readFile(vsFile);
-            QString fsSource = readFile(fsFile);
-            ProgramPtr program;
-            try {
-                compileProgram(program, vsSource.toLocal8Bit().toStdString(), fsSource.toLocal8Bit().toStdString());
-                if (program) {
-                    using namespace oglplus;
-                    _reprojectionUniforms.reprojectionMatrix = Uniform<glm::mat3>(*program, "reprojection").Location();
-                    _reprojectionUniforms.inverseProjectionMatrix = Uniform<glm::mat4>(*program, "inverseProjections").Location();
-                    _reprojectionUniforms.projectionMatrix = Uniform<glm::mat4>(*program, "projections").Location();
-                    _program = program;
-                }
-            } catch (std::runtime_error& error) {
-                qWarning() << "Error building reprojection shader " << error.what();
-            }
-        }
-    }
-
     void updateSource() {
         _plugin.withNonPresentThreadLock([&] {
             while (!_queue.empty()) {
@@ -130,15 +187,57 @@ public:
         });
     }
 
+    GLuint _program { 0 };
+
+    void updateProgram() {
+        if (!_program) {
+            std::string vsSource = HMD_REPROJECTION_VERT;
+            std::string fsSource = HMD_REPROJECTION_FRAG;
+            GLuint vertexShader { 0 }, fragmentShader { 0 };
+            ::gl::compileShader(GL_VERTEX_SHADER, vsSource, "", vertexShader);
+            ::gl::compileShader(GL_FRAGMENT_SHADER, fsSource, "", fragmentShader);
+            _program = ::gl::compileProgram({ { vertexShader, fragmentShader } });
+            glDeleteShader(vertexShader);
+            glDeleteShader(fragmentShader);
+            qDebug() << "Rebuild proigram";
+        }
+    }
+
+#define COLOR_BUFFER_COUNT 4
+
     void run() override {
+
+        GLuint _framebuffer { 0 };
+        std::array<GLuint, COLOR_BUFFER_COUNT> _colors;
+        size_t currentColorBuffer { 0 };
+        size_t globalColorBufferCount { 0 };
+        GLuint _uniformBuffer { 0 };
+        GLuint _vao { 0 };
+        GLuint _depth { 0 };
+        Reprojection _reprojection;
+
         QThread::currentThread()->setPriority(QThread::Priority::TimeCriticalPriority);
         _canvas->makeCurrent();
+
+        glCreateBuffers(1, &_uniformBuffer);
+        glNamedBufferStorage(_uniformBuffer, sizeof(Reprojection), 0, GL_DYNAMIC_STORAGE_BIT);
+        glCreateVertexArrays(1, &_vao);
+        glBindVertexArray(_vao);
+
+
+        glCreateFramebuffers(1, &_framebuffer);
+        {
+            glCreateRenderbuffers(1, &_depth);
+            glNamedRenderbufferStorage(_depth, GL_DEPTH24_STENCIL8, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y);
+            glNamedFramebufferRenderbuffer(_framebuffer, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depth);
+            glCreateTextures(GL_TEXTURE_2D, COLOR_BUFFER_COUNT, &_colors[0]);
+            for (size_t i = 0; i < COLOR_BUFFER_COUNT; ++i) {
+                glTextureStorage2D(_colors[i], 1, GL_RGBA8, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y);
+            }
+        }
+
         glDisable(GL_DEPTH_TEST);
         glViewport(0, 0, _plugin._renderTargetSize.x, _plugin._renderTargetSize.y);
-        _framebuffer = std::make_shared<BasicFramebufferWrapper>();
-        _framebuffer->Init(_plugin._renderTargetSize);
-        updateReprojectionProgram();
-        _plane = loadPlane(_program);
         _canvas->doneCurrent();
         while (!_quit) {
             _canvas->makeCurrent();
@@ -149,29 +248,35 @@ public:
                 continue;
             }
 
+
+            updateProgram();
             {
                 auto presentRotation = glm::mat3(_nextRender.poses[0]);
                 auto renderRotation = glm::mat3(_current.pose);
-                auto correction = glm::inverse(renderRotation) * presentRotation;
-                _framebuffer->Bound([&] {
+                for (size_t i = 0; i < 2; ++i) {
+                    _reprojection.projections[i] = _plugin._eyeProjections[i];
+                    _reprojection.inverseProjections[i] = _plugin._eyeInverseProjections[i];
+                }
+                _reprojection.reprojection = glm::inverse(renderRotation) * presentRotation;
+                glNamedBufferSubData(_uniformBuffer, 0, sizeof(Reprojection), &_reprojection);
+                glNamedFramebufferTexture(_framebuffer, GL_COLOR_ATTACHMENT0, _colors[currentColorBuffer], 0);
+                glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _framebuffer);
+                {
+                    glClearColor(1, 1, 0, 1);
+                    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+                    glTextureParameteri(_current.textureID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+                    glTextureParameteri(_current.textureID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+                    glUseProgram(_program);
+                    glBindBufferBase(GL_UNIFORM_BUFFER, REPROJECTION_BINDING, _uniformBuffer);
                     glBindTexture(GL_TEXTURE_2D, _current.textureID);
-                    _program->Use();
-                    using namespace oglplus;
-                    Texture::MinFilter(TextureTarget::_2D, TextureMinFilter::Linear);
-                    Texture::MagFilter(TextureTarget::_2D, TextureMagFilter::Linear);
-                    Uniform<glm::mat3>(*_program, _reprojectionUniforms.reprojectionMatrix).Set(correction);
-                    //Uniform<glm::mat4>(*_reprojectionProgram, PROJECTION_MATRIX_LOCATION).Set(_eyeProjections);
-                    //Uniform<glm::mat4>(*_reprojectionProgram, INVERSE_PROJECTION_MATRIX_LOCATION).Set(_eyeInverseProjections);
-                    // FIXME what's the right oglplus mechanism to do this?  It's not that ^^^ ... better yet, switch to a uniform buffer
-                    glUniformMatrix4fv(_reprojectionUniforms.inverseProjectionMatrix, 2, GL_FALSE, &(_plugin._eyeInverseProjections[0][0][0]));
-                    glUniformMatrix4fv(_reprojectionUniforms.projectionMatrix, 2, GL_FALSE, &(_plugin._eyeProjections[0][0][0]));
-                    _plane->UseInProgram(*_program);
-                    _plane->Draw();
-                });
+                    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+                }
+
+                glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
                 static const vr::VRTextureBounds_t leftBounds{ 0, 0, 0.5f, 1 };
                 static const vr::VRTextureBounds_t rightBounds{ 0.5f, 0, 1, 1 };
                 
-                vr::Texture_t texture{ (void*)oglplus::GetName(_framebuffer->color), vr::API_OpenGL, vr::ColorSpace_Auto };
+                vr::Texture_t texture{ (void*)_colors[currentColorBuffer], vr::API_OpenGL, vr::ColorSpace_Auto };
                 vr::VRCompositor()->Submit(vr::Eye_Left, &texture, &leftBounds);
                 vr::VRCompositor()->Submit(vr::Eye_Right, &texture, &rightBounds);
                 _plugin._presentRate.increment();
@@ -199,14 +304,21 @@ public:
                     ++_presentCount;
                     _presented.notify_one();
                 });
+
+                ++globalColorBufferCount;
+                currentColorBuffer = globalColorBufferCount % COLOR_BUFFER_COUNT;
             }
             _canvas->doneCurrent();
         }
 
         _canvas->makeCurrent();
-        _plane.reset();
-        _program.reset();
-        _framebuffer.reset();
+        glDeleteBuffers(1, &_uniformBuffer);
+        glDeleteFramebuffers(1, &_framebuffer);
+        CHECK_GL_ERROR();
+        glDeleteTextures(4, &_colors[0]);
+        glDeleteProgram(_program);
+        glBindVertexArray(0);
+        glDeleteVertexArrays(1, &_vao);
         _canvas->doneCurrent();
     }
 

From 488d191428526a4c9715fcac1babfe5b459b5cf5 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 11:17:17 -0700
Subject: [PATCH 07/28] Remove all oglplus usage and references

---
 cmake/externals/oglplus/CMakeLists.txt        |  21 -
 cmake/macros/TargetOglplus.cmake              |  21 -
 cmake/modules/FindOGLPLUS.cmake               |  24 -
 libraries/display-plugins/CMakeLists.txt      |   4 -
 libraries/gl/CMakeLists.txt                   |   1 -
 libraries/gl/src/gl/OglplusHelpers.cpp        | 482 -------------
 libraries/gl/src/gl/OglplusHelpers.h          | 190 ------
 libraries/render-utils/CMakeLists.txt         |   1 -
 .../src/OculusLegacyDisplayPlugin.cpp         |   4 -
 tests/render-perf/src/TextOverlay.hpp         |  31 +-
 tests/shaders/CMakeLists.txt                  |   2 -
 tests/ui/src/oldmain.cpp                      | 643 ------------------
 12 files changed, 19 insertions(+), 1405 deletions(-)
 delete mode 100644 cmake/externals/oglplus/CMakeLists.txt
 delete mode 100644 cmake/macros/TargetOglplus.cmake
 delete mode 100644 cmake/modules/FindOGLPLUS.cmake
 delete mode 100644 libraries/gl/src/gl/OglplusHelpers.cpp
 delete mode 100644 libraries/gl/src/gl/OglplusHelpers.h
 delete mode 100644 tests/ui/src/oldmain.cpp

diff --git a/cmake/externals/oglplus/CMakeLists.txt b/cmake/externals/oglplus/CMakeLists.txt
deleted file mode 100644
index 089ee5bb95..0000000000
--- a/cmake/externals/oglplus/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-set(EXTERNAL_NAME oglplus)
-string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
-
-include(ExternalProject)
-ExternalProject_Add(
-    ${EXTERNAL_NAME}
-    URL http://hifi-public.s3.amazonaws.com/dependencies/oglplus-0.63.0.zip
-    URL_MD5 de984ab245b185b45c87415c0e052135
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND ""
-    INSTALL_COMMAND ""
-    LOG_DOWNLOAD 1
-)
-
-# Hide this external target (for ide users)
-set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
-
-ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR)
-
-set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include ${SOURCE_DIR}/implement CACHE TYPE INTERNAL)
-
diff --git a/cmake/macros/TargetOglplus.cmake b/cmake/macros/TargetOglplus.cmake
deleted file mode 100644
index 16a50f3dd7..0000000000
--- a/cmake/macros/TargetOglplus.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-# 
-#  Copyright 2015 High Fidelity, Inc.
-#  Created by Bradley Austin Davis on 2015/10/10
-#
-#  Distributed under the Apache License, Version 2.0.
-#  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-# 
-macro(TARGET_OGLPLUS)
-    # our OGL plus setup requires glew
-    target_glew()
-    
-    # our OGL plus setup requires boostconfig
-    add_dependency_external_projects(boostconfig)
-    find_package(BoostConfig REQUIRED)
-    target_include_directories(${TARGET_NAME} PUBLIC ${BOOSTCONFIG_INCLUDE_DIRS})
-
-    
-    add_dependency_external_projects(oglplus)
-    find_package(OGLPLUS REQUIRED)
-    target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
-endmacro()
\ No newline at end of file
diff --git a/cmake/modules/FindOGLPLUS.cmake b/cmake/modules/FindOGLPLUS.cmake
deleted file mode 100644
index 6ba883ee2c..0000000000
--- a/cmake/modules/FindOGLPLUS.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-# 
-#  Try to find OGLPLUS include path.
-#  Once done this will define
-#
-#  OGLPLUS_INCLUDE_DIRS
-# 
-#  Created by Bradley Austin Davis on 2015/05/22
-#  Copyright 2015 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
-# 
-
-# setup hints for OGLPLUS search
-include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
-hifi_library_search_hints("oglplus")
-
-# locate header
-find_path(OGLPLUS_INCLUDE_DIRS "oglplus/fwd.hpp" HINTS ${OGLPLUS_SEARCH_DIRS})
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(OGLPLUS DEFAULT_MSG OGLPLUS_INCLUDE_DIRS)
-
-mark_as_advanced(OGLPLUS_INCLUDE_DIRS OGLPLUS_SEARCH_DIRS)
\ No newline at end of file
diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt
index 5621a9c7b0..b7542c1d86 100644
--- a/libraries/display-plugins/CMakeLists.txt
+++ b/libraries/display-plugins/CMakeLists.txt
@@ -6,7 +6,3 @@ link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui render-utils)
 target_opengl()
 
 GroupSources("src/display-plugins")
-
-if (NOT ANDROID)
-  target_oglplus()
-endif ()
diff --git a/libraries/gl/CMakeLists.txt b/libraries/gl/CMakeLists.txt
index 0c29bf691a..3e2097e89e 100644
--- a/libraries/gl/CMakeLists.txt
+++ b/libraries/gl/CMakeLists.txt
@@ -6,5 +6,4 @@ target_opengl()
 
 if (NOT ANDROID)
   target_glew()
-  target_oglplus()
 endif ()
diff --git a/libraries/gl/src/gl/OglplusHelpers.cpp b/libraries/gl/src/gl/OglplusHelpers.cpp
deleted file mode 100644
index 587c6488c8..0000000000
--- a/libraries/gl/src/gl/OglplusHelpers.cpp
+++ /dev/null
@@ -1,482 +0,0 @@
-//
-//  Created by Bradley Austin Davis on 2015/05/29
-//  Copyright 2015 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 "OglplusHelpers.h"
-
-#include <set>
-#include <oglplus/shapes/plane.hpp>
-#include <oglplus/shapes/sky_box.hpp>
-#include "GLLogging.h"
-
-using namespace oglplus;
-using namespace oglplus::shapes;
-
-static const char * SIMPLE_TEXTURED_VS = R"VS(#version 410 core
-#pragma line __LINE__
-
-uniform mat4 mvp = mat4(1);
-
-in vec3 Position;
-in vec2 TexCoord;
-
-out vec3 vPosition;
-out vec2 vTexCoord;
-
-void main() {
-  gl_Position = mvp * vec4(Position, 1);
-  vTexCoord = TexCoord;
-  vPosition = Position;
-}
-
-)VS";
-
-static const char * SIMPLE_TEXTURED_FS = R"FS(#version 410 core
-#pragma line __LINE__
-
-uniform sampler2D sampler;
-uniform float alpha = 1.0;
-
-in vec3 vPosition;
-in vec2 vTexCoord;
-
-out vec4 FragColor;
-
-void main() {
-    FragColor = texture(sampler, vTexCoord);
-    FragColor.a *= alpha;
-    if (FragColor.a <= 0.0) {
-        discard;
-    }
-}
-
-)FS";
-
-
-static const char * SIMPLE_TEXTURED_CUBEMAP_FS = R"FS(#version 410 core
-#pragma line __LINE__
-
-uniform samplerCube sampler;
-uniform float alpha = 1.0;
-
-in vec3 vPosition;
-in vec3 vTexCoord;
-
-out vec4 FragColor;
-
-void main() {
-
-    FragColor = texture(sampler, vPosition);
-    FragColor.a *= alpha;
-}
-
-)FS";
-
-
-ProgramPtr loadDefaultShader() {
-    ProgramPtr result;
-    compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_FS);
-    return result;
-}
-
-ProgramPtr loadCubemapShader() {
-    ProgramPtr result;
-    compileProgram(result, SIMPLE_TEXTURED_VS, SIMPLE_TEXTURED_CUBEMAP_FS);
-    return result;
-}
-
-void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs) {
-    using namespace oglplus;
-    try {
-        result = std::make_shared<Program>();
-        // attach the shaders to the program
-        result->AttachShader(
-            VertexShader()
-            .Source(GLSLSource(vs))
-            .Compile()
-            );
-        result->AttachShader(
-            GeometryShader()
-            .Source(GLSLSource(gs))
-            .Compile()
-            );
-        result->AttachShader(
-            FragmentShader()
-            .Source(GLSLSource(fs))
-            .Compile()
-            );
-        result->Link();
-    } catch (ProgramBuildError& err) {
-        Q_UNUSED(err);
-        qWarning() << err.Log().c_str();
-        Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
-        qFatal("%s", (const char*)err.Message);
-        result.reset();
-    }
-}
-
-void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs) {
-    using namespace oglplus;
-    try {
-        result = std::make_shared<Program>();
-        // attach the shaders to the program
-        result->AttachShader(
-            VertexShader()
-            .Source(GLSLSource(vs))
-            .Compile()
-            );
-        result->AttachShader(
-            FragmentShader()
-            .Source(GLSLSource(fs))
-            .Compile()
-            );
-        result->Link();
-    } catch (ProgramBuildError& err) {
-        Q_UNUSED(err);
-        qWarning() << err.Log().c_str();
-        Q_ASSERT_X(false, "compileProgram", "Failed to build shader program");
-        qFatal("%s", (const char*) err.Message);
-        result.reset();
-    }
-}
-
-
-ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect) {
-    using namespace oglplus;
-    Vec3f a(1, 0, 0);
-    Vec3f b(0, 1, 0);
-    if (aspect > 1) {
-        b[1] /= aspect;
-    } else {
-        a[0] *= aspect;
-    }
-    return ShapeWrapperPtr(
-        new shapes::ShapeWrapper({ "Position", "TexCoord" }, shapes::Plane(a, b), *program)
-    );
-}
-
-ShapeWrapperPtr loadSkybox(ProgramPtr program) {
-    return ShapeWrapperPtr(new shapes::ShapeWrapper(std::initializer_list<std::string>{ "Position" }, shapes::SkyBox(), *program));
-}
-
-// Return a point's cartesian coordinates on a sphere from pitch and yaw
-static glm::vec3 getPoint(float yaw, float pitch) {
-    return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
-        glm::sin(-pitch),
-        glm::cos(-pitch) * (-glm::cos(yaw)));
-}
-
-
-class SphereSection : public DrawingInstructionWriter, public DrawMode {
-public:
-    using IndexArray = std::vector<GLuint>;
-    using PosArray = std::vector<float>;
-    using TexArray = std::vector<float>;
-    /// The type of the index container returned by Indices()
-    // vertex positions
-    PosArray _pos_data;
-    // vertex tex coords
-    TexArray _tex_data;
-    IndexArray _idx_data;
-    unsigned int _prim_count{ 0 };
-
-public:
-    SphereSection(
-        const float fov,
-        const float aspectRatio,
-        const int slices_,
-        const int stacks_) {
-        //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm
-        if (fov >= PI) {
-            qCDebug(glLogging) << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues";
-        }
-
-        int gridSize = std::max(slices_, stacks_);
-        int gridSizeLog2 = 1;
-        while (1 << gridSizeLog2 < gridSize) {
-            ++gridSizeLog2;
-        }
-        gridSize = (1 << gridSizeLog2) + 1;
-        // Compute number of vertices needed
-        int vertices = gridSize * gridSize;
-        _pos_data.resize(vertices * 3);
-        _tex_data.resize(vertices * 2);
-
-        // Compute vertices positions and texture UV coordinate
-        for (int y = 0; y <= gridSize; ++y) {
-            for (int x = 0; x <= gridSize; ++x) {
-
-            }
-        }
-        for (int i = 0; i < gridSize; i++) {
-            float stacksRatio = (float)i / (float)(gridSize - 1); // First stack is 0.0f, last stack is 1.0f
-            // abs(theta) <= fov / 2.0f
-            float pitch = -fov * (stacksRatio - 0.5f);
-            for (int j = 0; j < gridSize; j++) {
-                float slicesRatio = (float)j / (float)(gridSize - 1); // First slice is 0.0f, last slice is 1.0f
-                // abs(phi) <= fov * aspectRatio / 2.0f
-                float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
-                int vertex = i * gridSize + j;
-                int posOffset = vertex * 3;
-                int texOffset = vertex * 2;
-                vec3 pos = getPoint(yaw, pitch);
-                _pos_data[posOffset] = pos.x;
-                _pos_data[posOffset + 1] = pos.y;
-                _pos_data[posOffset + 2] = pos.z;
-                _tex_data[texOffset] = slicesRatio;
-                _tex_data[texOffset + 1] = stacksRatio;
-            }
-        } // done with vertices
-
-        int rowLen = gridSize;
-
-        // gridsize now refers to the triangles, not the vertices, so reduce by one
-        // or die by fencepost error http://en.wikipedia.org/wiki/Off-by-one_error
-        --gridSize;
-        int quads = gridSize * gridSize;
-        for (int t = 0; t < quads; ++t) {
-            int x = 
-                ((t & 0x0001) >> 0) |
-                ((t & 0x0004) >> 1) |
-                ((t & 0x0010) >> 2) |
-                ((t & 0x0040) >> 3) |
-                ((t & 0x0100) >> 4) |
-                ((t & 0x0400) >> 5) |
-                ((t & 0x1000) >> 6) |
-                ((t & 0x4000) >> 7);
-            int y = 
-                ((t & 0x0002) >> 1) |
-                ((t & 0x0008) >> 2) |
-                ((t & 0x0020) >> 3) |
-                ((t & 0x0080) >> 4) |
-                ((t & 0x0200) >> 5) |
-                ((t & 0x0800) >> 6) |
-                ((t & 0x2000) >> 7) |
-                ((t & 0x8000) >> 8);
-            int i = x * (rowLen) + y;
-
-            _idx_data.push_back(i);
-            _idx_data.push_back(i + 1);
-            _idx_data.push_back(i + rowLen + 1);
-
-            _idx_data.push_back(i + rowLen + 1);
-            _idx_data.push_back(i + rowLen);
-            _idx_data.push_back(i);
-        }
-        _prim_count = quads * 2;
-    }
-
-    /// Returns the winding direction of faces
-    FaceOrientation FaceWinding(void) const {
-        return FaceOrientation::CCW;
-    }
-
-    typedef GLuint(SphereSection::*VertexAttribFunc)(std::vector<GLfloat>&) const;
-
-    /// Makes the vertex positions and returns the number of values per vertex
-    template <typename T>
-    GLuint Positions(std::vector<T>& dest) const {
-        dest.clear();
-        dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
-        return 3;
-    }
-
-    /// Makes the vertex normals and returns the number of values per vertex
-    template <typename T>
-    GLuint Normals(std::vector<T>& dest) const {
-        dest.clear();
-        return 3;
-    }
-
-    /// Makes the vertex tangents and returns the number of values per vertex
-    template <typename T>
-    GLuint Tangents(std::vector<T>& dest) const {
-        dest.clear();
-        return 3;
-    }
-
-    /// Makes the vertex bi-tangents and returns the number of values per vertex
-    template <typename T>
-    GLuint Bitangents(std::vector<T>& dest) const {
-        dest.clear();
-        return 3;
-    }
-
-    /// Makes the texture coordinates returns the number of values per vertex
-    template <typename T>
-    GLuint TexCoordinates(std::vector<T>& dest) const {
-        dest.clear();
-        dest.insert(dest.begin(), _tex_data.begin(), _tex_data.end());
-        return 2;
-    }
-
-    typedef VertexAttribsInfo<
-        SphereSection,
-        std::tuple<
-        VertexPositionsTag,
-        VertexNormalsTag,
-        VertexTangentsTag,
-        VertexBitangentsTag,
-        VertexTexCoordinatesTag
-        >
-    > VertexAttribs;
-
-    Spheref MakeBoundingSphere(void) const {
-        GLfloat min_x = _pos_data[3], max_x = _pos_data[3];
-        GLfloat min_y = _pos_data[4], max_y = _pos_data[4];
-        GLfloat min_z = _pos_data[5], max_z = _pos_data[5];
-        for (std::size_t v = 0, vn = _pos_data.size() / 3; v != vn; ++v) {
-            GLfloat x = _pos_data[v * 3 + 0];
-            GLfloat y = _pos_data[v * 3 + 1];
-            GLfloat z = _pos_data[v * 3 + 2];
-
-            if (min_x > x) min_x = x;
-            if (min_y > y) min_y = y;
-            if (min_z > z) min_z = z;
-            if (max_x < x) max_x = x;
-            if (max_y < y) max_y = y;
-            if (max_z < z) max_z = z;
-        }
-
-        Vec3f c(
-            (min_x + max_x) * 0.5f,
-            (min_y + max_y) * 0.5f,
-            (min_z + max_z) * 0.5f
-            );
-
-        return Spheref(
-            c.x(), c.y(), c.z(),
-            Distance(c, Vec3f(min_x, min_y, min_z))
-            );
-    }
-
-    /// Queries the bounding sphere coordinates and dimensions
-    template <typename T>
-    void BoundingSphere(oglplus::Sphere<T>& bounding_sphere) const {
-        bounding_sphere = oglplus::Sphere<T>(MakeBoundingSphere());
-    }
-
-
-    /// Returns element indices that are used with the drawing instructions
-    const IndexArray & Indices(Default = Default()) const {
-        return _idx_data;
-    }
-
-    /// Returns the instructions for rendering of faces
-    DrawingInstructions Instructions(PrimitiveType primitive) const {
-        DrawingInstructions instr = MakeInstructions();
-        DrawOperation operation;
-        operation.method = DrawOperation::Method::DrawElements;
-        operation.mode = primitive;
-        operation.first = 0;
-        operation.count = _prim_count * 3;
-        operation.restart_index = DrawOperation::NoRestartIndex();
-        operation.phase = 0;
-        AddInstruction(instr, operation);
-        return instr;
-    }
-
-    /// Returns the instructions for rendering of faces
-    DrawingInstructions Instructions(Default = Default()) const {
-        return Instructions(PrimitiveType::Triangles);
-    }
-};
-
-ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov, float aspect, int slices, int stacks) {
-    using namespace oglplus;
-    return ShapeWrapperPtr(
-        new shapes::ShapeWrapper({ "Position", "TexCoord" }, SphereSection(fov, aspect, slices, stacks), *program)
-    );
-}
-
-namespace oglplus {
-    namespace shapes {
-
-        class Laser : public DrawingInstructionWriter, public DrawMode {
-        public:
-            using IndexArray = std::vector<GLuint>;
-            using PosArray = std::vector<float>;
-            /// The type of the index container returned by Indices()
-            // vertex positions
-            PosArray _pos_data;
-            IndexArray _idx_data;
-            unsigned int _prim_count { 0 };
-
-        public:
-            Laser() {
-                int vertices = 2;
-                _pos_data.resize(vertices * 3);
-                _pos_data[0] = 0;
-                _pos_data[1] = 0;
-                _pos_data[2] = 0;
-
-                _pos_data[3] = 0;
-                _pos_data[4] = 0;
-                _pos_data[5] = -1;
-
-                _idx_data.push_back(0);
-                _idx_data.push_back(1);
-                _prim_count = 1;
-            }
-
-            /// Returns the winding direction of faces
-            FaceOrientation FaceWinding(void) const {
-                return FaceOrientation::CCW;
-            }
-
-            /// Queries the bounding sphere coordinates and dimensions
-            template <typename T>
-            void BoundingSphere(Sphere<T>& bounding_sphere) const {
-                bounding_sphere = Sphere<T>(0, 0, -0.5, 0.5);
-            }
-
-            typedef GLuint(Laser::*VertexAttribFunc)(std::vector<GLfloat>&) const;
-
-            /// Makes the vertex positions and returns the number of values per vertex
-            template <typename T>
-            GLuint Positions(std::vector<T>& dest) const {
-                dest.clear();
-                dest.insert(dest.begin(), _pos_data.begin(), _pos_data.end());
-                return 3;
-            }
-
-            typedef VertexAttribsInfo<
-                Laser,
-                std::tuple<VertexPositionsTag>
-            > VertexAttribs;
-
-
-            /// Returns element indices that are used with the drawing instructions
-            const IndexArray & Indices(Default = Default()) const {
-                return _idx_data;
-            }
-
-            /// Returns the instructions for rendering of faces
-            DrawingInstructions Instructions(PrimitiveType primitive) const {
-                DrawingInstructions instr = MakeInstructions();
-                DrawOperation operation;
-                operation.method = DrawOperation::Method::DrawElements;
-                operation.mode = primitive;
-                operation.first = 0;
-                operation.count = _prim_count * 3;
-                operation.restart_index = DrawOperation::NoRestartIndex();
-                operation.phase = 0;
-                AddInstruction(instr, operation);
-                return instr;
-            }
-
-            /// Returns the instructions for rendering of faces
-            DrawingInstructions Instructions(Default = Default()) const {
-                return Instructions(PrimitiveType::Lines);
-            }
-        };
-    }
-}
-
-ShapeWrapperPtr loadLaser(const ProgramPtr& program) {
-    return std::make_shared<shapes::ShapeWrapper>(shapes::ShapeWrapper("Position", shapes::Laser(), *program));
-}
-
diff --git a/libraries/gl/src/gl/OglplusHelpers.h b/libraries/gl/src/gl/OglplusHelpers.h
deleted file mode 100644
index 52e63f9431..0000000000
--- a/libraries/gl/src/gl/OglplusHelpers.h
+++ /dev/null
@@ -1,190 +0,0 @@
-//
-//  Created by Bradley Austin Davis on 2015/05/26
-//  Copyright 2015 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
-//
-#pragma once
-
-// FIXME support oglplus on all platforms
-// For now it's a convenient helper for Windows
-
-#include <queue>
-#include <map>
-
-
-#include <QtGlobal>
-
-#include "GLMHelpers.h"
-
-#define OGLPLUS_USE_GLCOREARB_H 0
-#define OGLPLUS_USE_GLEW 1
-#define OGLPLUS_USE_BOOST_CONFIG 1
-#define OGLPLUS_NO_SITE_CONFIG 1
-#define OGLPLUS_LOW_PROFILE 1
-
-// NOTE: oglplus does some naked "#pragma GCC" without proper platform wrapping, so we need to disable this warning.
-#ifdef _WIN32
-#pragma warning(push)
-#pragma warning( disable : 4068 )
-#elif defined(Q_OS_MAC)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wpessimizing-move"
-#endif
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#if __GNUC__ >= 5 && __GNUC_MINOR__ >= 1
-#pragma GCC diagnostic ignored "-Wsuggest-override"
-#endif
-#endif
-
-#include <oglplus/gl.hpp>
-
-#include <oglplus/all.hpp>
-#include <oglplus/interop/glm.hpp>
-#include <oglplus/bound/texture.hpp>
-#include <oglplus/bound/framebuffer.hpp>
-#include <oglplus/bound/renderbuffer.hpp>
-#include <oglplus/shapes/wrapper.hpp>
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-#ifdef _WIN32
-#pragma warning(pop)
-#elif defined(Q_OS_MAC)
-#pragma clang diagnostic pop
-#endif
-
-#include "NumericalConstants.h"
-
-using FramebufferPtr = std::shared_ptr<oglplus::Framebuffer>;
-using RenderbufferPtr = std::shared_ptr<oglplus::Renderbuffer>;
-using TexturePtr = std::shared_ptr<oglplus::Texture>;
-using ShapeWrapperPtr = std::shared_ptr<oglplus::shapes::ShapeWrapper>;
-using BufferPtr = std::shared_ptr<oglplus::Buffer>;
-using VertexArrayPtr = std::shared_ptr<oglplus::VertexArray>;
-using ProgramPtr = std::shared_ptr<oglplus::Program>;
-using Mat4Uniform = oglplus::Uniform<mat4>;
-
-ProgramPtr loadDefaultShader();
-ProgramPtr loadCubemapShader();
-void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& fs);
-void compileProgram(ProgramPtr & result, const std::string& vs, const std::string& gs, const std::string& fs);
-
-ShapeWrapperPtr loadSkybox(ProgramPtr program);
-ShapeWrapperPtr loadPlane(ProgramPtr program, float aspect = 1.0f);
-ShapeWrapperPtr loadSphereSection(ProgramPtr program, float fov = PI / 3.0f * 2.0f, float aspect = 16.0f / 9.0f, int slices = 128, int stacks = 128);
-ShapeWrapperPtr loadLaser(const ProgramPtr& program);
-
-
-// A basic wrapper for constructing a framebuffer with a renderbuffer
-// for the depth attachment and an undefined type for the color attachement
-// This allows us to reuse the basic framebuffer code for both the Mirror
-// FBO as well as the Oculus swap textures we will use to render the scene
-// Though we don't really need depth at all for the mirror FBO, or even an
-// FBO, but using one means I can just use a glBlitFramebuffer to get it onto
-// the screen.
-template <
-    typename C,
-    typename D
->
-struct FramebufferWrapper {
-    uvec2       size;
-    oglplus::Framebuffer fbo;
-    C           color;
-    D           depth;
-
-    FramebufferWrapper() {}
-
-    virtual ~FramebufferWrapper() {
-    }
-
-    virtual void Init(const uvec2 & size) {
-        this->size = size;
-        initColor();
-        initDepth();
-        initDone();
-    }
-
-    template <typename F>
-    void Bound(F f) {
-        Bound(oglplus::Framebuffer::Target::Draw, f);
-    }
-
-    template <typename F>
-    void Bound(oglplus::Framebuffer::Target target , F f) {
-        fbo.Bind(target);
-        onBind(target);
-        f();
-        onUnbind(target);
-        oglplus::DefaultFramebuffer().Bind(target);
-    }
-
-    void Viewport() {
-        oglplus::Context::Viewport(size.x, size.y);
-    }
-
-protected:
-    virtual void onBind(oglplus::Framebuffer::Target target) {}
-    virtual void onUnbind(oglplus::Framebuffer::Target target) {}
-
-    static GLenum toEnum(oglplus::Framebuffer::Target target) {
-        switch (target) {
-        case oglplus::Framebuffer::Target::Draw:
-            return GL_DRAW_FRAMEBUFFER;
-        case oglplus::Framebuffer::Target::Read:
-            return GL_READ_FRAMEBUFFER;
-        default:
-            Q_ASSERT(false);
-            return GL_FRAMEBUFFER;
-        }
-    }
-
-    virtual void initDepth() {}
-
-    virtual void initColor() {}
-
-    virtual void initDone() = 0;
-};
-
-struct BasicFramebufferWrapper : public FramebufferWrapper <oglplus::Texture, oglplus::Renderbuffer> {
-protected:
-    virtual void initDepth() override {
-        using namespace oglplus;
-        Context::Bound(Renderbuffer::Target::Renderbuffer, depth)
-            .Storage(
-            PixelDataInternalFormat::DepthComponent,
-            size.x, size.y);
-    }
-
-    virtual void initColor() override {
-        using namespace oglplus;
-        Context::Bound(oglplus::Texture::Target::_2D, color)
-            .MinFilter(TextureMinFilter::Linear)
-            .MagFilter(TextureMagFilter::Linear)
-            .WrapS(TextureWrap::ClampToEdge)
-            .WrapT(TextureWrap::ClampToEdge)
-            .Image2D(
-                0, PixelDataInternalFormat::RGBA8,
-                size.x, size.y,
-                0, PixelDataFormat::RGB, PixelDataType::UnsignedByte, nullptr
-            );
-    }
-
-    virtual void initDone() override {
-        using namespace oglplus;
-        static const Framebuffer::Target target = Framebuffer::Target::Draw;
-        Bound(target, [&] {
-            fbo.AttachTexture(target, FramebufferAttachment::Color, color, 0);
-            fbo.AttachRenderbuffer(target, FramebufferAttachment::Depth, depth);
-            fbo.Complete(target);
-        });
-    }
-};
-
-using BasicFramebufferWrapperPtr = std::shared_ptr<BasicFramebufferWrapper>;
-
diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt
index 115f4bd83e..ecafb8f565 100644
--- a/libraries/render-utils/CMakeLists.txt
+++ b/libraries/render-utils/CMakeLists.txt
@@ -7,5 +7,4 @@ link_hifi_libraries(shared gpu model model-networking render animation fbx entit
 
 if (NOT ANDROID)
   target_nsight()
-  target_oglplus()
 endif ()
diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 98516011d5..2feb272fbe 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -23,14 +23,10 @@
 
 #include <gl/QOpenGLContextWrapper.h>
 #include <PerfStat.h>
-#include <gl/OglplusHelpers.h>
 #include <ViewFrustum.h>
 #include <gpu/gl/GLbackend.h>
 
 #include <ui-plugins/PluginContainer.h>
-#include "OculusHelpers.h"
-
-using namespace oglplus;
 
 const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
 
diff --git a/tests/render-perf/src/TextOverlay.hpp b/tests/render-perf/src/TextOverlay.hpp
index d9a9f0a320..5e0c211b8d 100644
--- a/tests/render-perf/src/TextOverlay.hpp
+++ b/tests/render-perf/src/TextOverlay.hpp
@@ -17,8 +17,6 @@
 #include <iomanip>
 
 #include <GLMHelpers.h>
-#include <gl/OglplusHelpers.h>
-
 
 #include "stb_font_consolas_24_latin1.inl"
 
@@ -37,23 +35,16 @@
 // todo : comment
 class TextOverlay {
 private:
+    uvec2 _size;
+// FIXME port from oglplus
+#if 0
     FramebufferPtr _framebuffer;
     TexturePtr _texture;
-    uvec2 _size;
     BufferPtr _vertexBuffer;
     ProgramPtr _program;
     VertexArrayPtr _vertexArray;
-
-    //vk::DescriptorPool descriptorPool;
-    //vk::DescriptorSetLayout descriptorSetLayout;
-    //vk::DescriptorSet descriptorSet;
-    //vk::PipelineLayout pipelineLayout;
-    //vk::Pipeline pipeline;
-
     // Pointer to mapped vertex buffer
     glm::vec4* _mapped { nullptr };
-    stb_fontchar stbFontData[STB_NUM_CHARS];
-    uint32_t numLetters;
 
     const char* const VERTEX_SHADER = R"SHADER(
 #version 450 core
@@ -92,6 +83,12 @@ void main(void)
 }
 )SHADER";
 
+#endif
+
+    stb_fontchar stbFontData[STB_NUM_CHARS];
+    uint32_t numLetters;
+
+
 public:
     enum TextAlign { alignLeft, alignCenter, alignRight };
 
@@ -104,11 +101,13 @@ public:
     }
 
     ~TextOverlay() {
+#if 0
         // Free up all Vulkan resources requested by the text overlay
         _program.reset();
         _texture.reset();
         _vertexBuffer.reset();
         _vertexArray.reset();
+#endif
     }
 
     void resize(const uvec2& size) {
@@ -118,6 +117,7 @@ public:
     // Prepare all vulkan resources required to render the font
     // The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers
     void prepare() {
+#if 0
         static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH];
         STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT);
 
@@ -154,14 +154,17 @@ public:
         }
 
         compileProgram(_program, VERTEX_SHADER, FRAGMENT_SHADER);
+#endif
     }
 
 
     // Map buffer 
     void beginTextUpdate() {
+#if 0
         using namespace oglplus;
         _mapped = (glm::vec4*)glMapNamedBuffer(GetName(*_vertexBuffer), GL_WRITE_ONLY);
         numLetters = 0;
+#endif
     }
 
     // Add text to the current buffer
@@ -223,17 +226,21 @@ public:
 
     // Unmap buffer and update command buffers
     void endTextUpdate() {
+#if 0
         glUnmapNamedBuffer(GetName(*_vertexBuffer));
         _mapped = nullptr;
+#endif
     }
 
     // Needs to be called by the application
     void render() {
+#if 0
         _texture->Bind(oglplus::TextureTarget::_2D);
         _program->Use();
         _vertexArray->Bind();
         for (uint32_t j = 0; j < numLetters; j++) {
             glDrawArrays(GL_TRIANGLE_STRIP, j * 4, 4);
         }
+#endif
     }
 };
diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt
index 4aa66b92db..5b38f473e8 100644
--- a/tests/shaders/CMakeLists.txt
+++ b/tests/shaders/CMakeLists.txt
@@ -5,8 +5,6 @@ set(TARGET_NAME shaders-test)
 setup_hifi_project(Quick Gui OpenGL)
 set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
 
-#include_oglplus()
-
 # link in the shared libraries
 link_hifi_libraries(shared octree gl gpu gpu-gl model render fbx networking entities 
                     script-engine physics 
diff --git a/tests/ui/src/oldmain.cpp b/tests/ui/src/oldmain.cpp
deleted file mode 100644
index 82ba8376bd..0000000000
--- a/tests/ui/src/oldmain.cpp
+++ /dev/null
@@ -1,643 +0,0 @@
-//
-//  Created by Bradley Austin Davis on 2015-04-22
-//  Copyright 2013-2015 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 <gl/Config.h>
-#include <gl/OglplusHelpers.h>
-#include <gl/GLHelpers.h>
-#include <memory>
-
-#include <QtCore/QFile>
-#include <QtCore/QDir>
-#include <QtCore/QTime>
-#include <QtCore/QTimer>
-#include <QtCore/QElapsedTimer>
-#include <QtCore/QLoggingCategory>
-#include <QtCore/QThread>
-#include <QtCore/QUuid>
-
-#include <QtGui/QWindow>
-#include <QtGui/QImage>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QResizeEvent>
-#include <QtGui/QScreen>
-
-#include <gl/QOpenGLContextWrapper.h>
-
-#include <QtScript/QScriptEngine>
-
-#include <QtQml/QQmlContext>
-#include <QtQml/QQmlApplicationEngine>
-
-#include <GLMHelpers.h>
-#include <gl/OffscreenGLCanvas.h>
-#include <OffscreenUi.h>
-#include <PathUtils.h>
-#include <PathUtils.h>
-#include <VrMenu.h>
-#include <InfoView.h>
-#include <QmlWebWindowClass.h>
-#include <RegisteredMetaTypes.h>
-
-const QString& getResourcesDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
-        qDebug() << "Resources Path: " << dir;
-    }
-    return dir;
-}
-
-const QString& getExamplesDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../../../examples/")) + "/";
-        qDebug() << "Resources Path: " << dir;
-    }
-    return dir;
-}
-
-const QString& getInterfaceQmlDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        dir = getResourcesDir() + "qml/";
-        qDebug() << "Qml Path: " << dir;
-    }
-    return dir;
-}
-
-const QString& getTestQmlDir() {
-    static QString dir;
-    if (dir.isEmpty()) {
-        QDir path(__FILE__);
-        path.cdUp();
-        dir = path.cleanPath(path.absoluteFilePath("../")) + "/";
-        qDebug() << "Qml Test Path: " << dir;
-    }
-    return dir;
-}
-
-
-class RateCounter {
-    std::vector<float> times;
-    QElapsedTimer timer;
-public:
-    RateCounter() {
-        timer.start();
-    }
-
-    void reset() {
-        times.clear();
-    }
-
-    size_t count() const {
-        return times.size() - 1;
-    }
-
-    float elapsed() const {
-        if (times.size() < 1) {
-            return 0.0f;
-        }
-        float elapsed = *times.rbegin() - *times.begin();
-        return elapsed;
-    }
-
-    void increment() {
-        times.push_back(timer.elapsed() / 1000.0f);
-    }
-
-    float rate() const {
-        if (elapsed() == 0.0f) {
-            return 0.0f;
-        }
-        return (float) count() / elapsed();
-    }
-};
-
-
-
-
-extern QOpenGLContext* qt_gl_global_share_context();
-
-
-static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
-    if (engine.hasUncaughtException()) {
-        const auto backtrace = engine.uncaughtExceptionBacktrace();
-        const auto exception = engine.uncaughtException().toString();
-        const auto line = QString::number(engine.uncaughtExceptionLineNumber());
-        engine.clearExceptions();
-
-        auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line);
-        if (!backtrace.empty()) {
-            static const auto lineSeparator = "\n    ";
-            message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator));
-        }
-        qWarning() << qPrintable(message);
-        return true;
-    }
-    return false;
-}
-
-const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0f / 60.0f) * 1000 * 1000) + 0.5f);
-
-static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
-    QString message = "";
-    for (int i = 0; i < context->argumentCount(); i++) {
-        if (i > 0) {
-            message += " ";
-        }
-        message += context->argument(i).toString();
-    }
-    qDebug().noquote() << "script:print()<<" << message;  // noquote() so that \n is treated as newline
-
-    message = message.replace("\\", "\\\\")
-        .replace("\n", "\\n")
-        .replace("\r", "\\r")
-        .replace("'", "\\'");
-    engine->evaluate("Script.print('" + message + "')");
-
-    return QScriptValue();
-}
-
-class ScriptEngine : public QScriptEngine {
-    Q_OBJECT
-
-public:
-    void loadFile(const QString& scriptPath) {
-        if (_isRunning) {
-            return;
-        }
-        qDebug() << "Loading script from " << scriptPath;
-        _fileNameString = scriptPath;
-
-        QFile file(scriptPath);
-        if (file.exists()) {
-            file.open(QIODevice::ReadOnly);
-            _scriptContents = file.readAll();
-        } else {
-            qFatal("Missing file ");
-        }
-        runInThread();
-    }
-
-    Q_INVOKABLE void stop() {
-        if (!_isFinished) {
-            if (QThread::currentThread() != thread()) {
-                QMetaObject::invokeMethod(this, "stop");
-                return;
-            }
-            _isFinished = true;
-            if (_wantSignals) {
-                emit runningStateChanged();
-            }
-        }
-    }
-
-    Q_INVOKABLE void print(const QString& message) {
-        if (_wantSignals) {
-            emit printedMessage(message);
-        }
-    }
-
-    Q_INVOKABLE QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) {
-        // create the timer, add it to the map, and start it
-        QTimer* newTimer = new QTimer(this);
-        newTimer->setSingleShot(isSingleShot);
-
-        connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
-
-        // make sure the timer stops when the script does
-        connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
-
-        _timerFunctionMap.insert(newTimer, function);
-
-        newTimer->start(intervalMS);
-        return newTimer;
-    }
-
-    Q_INVOKABLE QObject* setInterval(const QScriptValue& function, int intervalMS) {
-        return setupTimerWithInterval(function, intervalMS, false);
-    }
-
-    Q_INVOKABLE QObject* setTimeout(const QScriptValue& function, int timeoutMS) {
-        return setupTimerWithInterval(function, timeoutMS, true);
-    }
-private:
-
-    void runInThread() {
-        QThread* workerThread = new QThread();
-        connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
-        connect(workerThread, &QThread::started, this, &ScriptEngine::run);
-        connect(workerThread, &QThread::finished, this, &ScriptEngine::deleteLater);
-        connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit);
-        moveToThread(workerThread);
-        workerThread->start();
-    }
-
-    void init() {
-        _isInitialized = true;
-        registerMetaTypes(this);
-        registerGlobalObject("Script", this);
-        qScriptRegisterSequenceMetaType<QVector<QUuid>>(this);
-        qScriptRegisterSequenceMetaType<QVector<QString>>(this);
-        globalObject().setProperty("OverlayWebWindow", newFunction(QmlWebWindowClass::constructor));
-        QScriptValue printConstructorValue = newFunction(debugPrint);
-        globalObject().setProperty("print", printConstructorValue);
-    }
-
-    void timerFired() {
-        QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
-        QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
-
-        if (!callingTimer->isActive()) {
-            // this timer is done, we can kill it
-            _timerFunctionMap.remove(callingTimer);
-            delete callingTimer;
-        }
-
-        // call the associated JS function, if it exists
-        if (timerFunction.isValid()) {
-            timerFunction.call();
-        }
-    }
-
-
-    void run() {
-        if (!_isInitialized) {
-            init();
-        }
-
-        _isRunning = true;
-        if (_wantSignals) {
-            emit runningStateChanged();
-        }
-
-        QScriptValue result = evaluate(_scriptContents, _fileNameString);
-        QElapsedTimer startTime;
-        startTime.start();
-
-        int thisFrame = 0;
-
-        qint64 lastUpdate = usecTimestampNow();
-
-        while (!_isFinished) {
-            int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec
-            if (usecToSleep > 0) {
-                usleep(usecToSleep);
-            }
-
-            if (_isFinished) {
-                break;
-            }
-
-            QCoreApplication::processEvents();
-            if (_isFinished) {
-                break;
-            }
-
-            qint64 now = usecTimestampNow();
-            float deltaTime = (float)(now - lastUpdate) / (float)USECS_PER_SECOND;
-            if (!_isFinished) {
-                if (_wantSignals) {
-                    emit update(deltaTime);
-                }
-            }
-            lastUpdate = now;
-
-            // Debug and clear exceptions
-            hadUncaughtExceptions(*this, _fileNameString);
-        }
-
-        if (_wantSignals) {
-            emit scriptEnding();
-        }
-
-        if (_wantSignals) {
-            emit finished(_fileNameString, this);
-        }
-
-        _isRunning = false;
-
-        if (_wantSignals) {
-            emit runningStateChanged();
-            emit doneRunning();
-        }
-    }
-
-    void registerGlobalObject(const QString& name, QObject* object) {
-        if (QThread::currentThread() != thread()) {
-            QMetaObject::invokeMethod(this, "registerGlobalObject",
-                Q_ARG(const QString&, name),
-                Q_ARG(QObject*, object));
-            return;
-        }
-        if (!globalObject().property(name).isValid()) {
-            if (object) {
-                QScriptValue value = newQObject(object);
-                globalObject().setProperty(name, value);
-            } else {
-                globalObject().setProperty(name, QScriptValue());
-            }
-        }
-    }
-
-    void registerFunction(const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
-        if (QThread::currentThread() != thread()) {
-            QMetaObject::invokeMethod(this, "registerFunction",
-                Q_ARG(const QString&, name),
-                Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
-                Q_ARG(int, numArguments));
-            return;
-        }
-        QScriptValue scriptFun = newFunction(functionSignature, numArguments);
-        globalObject().setProperty(name, scriptFun);
-    }
-
-    void registerFunction(const QString& parent, const QString& name, QScriptEngine::FunctionSignature functionSignature, int numArguments) {
-        if (QThread::currentThread() != thread()) {
-            QMetaObject::invokeMethod(this, "registerFunction",
-                Q_ARG(const QString&, name),
-                Q_ARG(QScriptEngine::FunctionSignature, functionSignature),
-                Q_ARG(int, numArguments));
-            return;
-        }
-
-        QScriptValue object = globalObject().property(parent);
-        if (object.isValid()) {
-            QScriptValue scriptFun = newFunction(functionSignature, numArguments);
-            object.setProperty(name, scriptFun);
-        }
-    }
-
-signals:
-    void scriptLoaded(const QString& scriptFilename);
-    void errorLoadingScript(const QString& scriptFilename);
-    void update(float deltaTime);
-    void scriptEnding();
-    void finished(const QString& fileNameString, ScriptEngine* engine);
-    void cleanupMenuItem(const QString& menuItemString);
-    void printedMessage(const QString& message);
-    void errorMessage(const QString& message);
-    void runningStateChanged();
-    void evaluationFinished(QScriptValue result, bool isException);
-    void loadScript(const QString& scriptName, bool isUserLoaded);
-    void reloadScript(const QString& scriptName, bool isUserLoaded);
-    void doneRunning();
-
-
-private:
-    QString _scriptContents;
-    QString _fileNameString;
-    QString _parentURL;
-    bool _isInitialized { false };
-    std::atomic<bool> _isFinished { false };
-    std::atomic<bool> _isRunning { false };
-    bool _wantSignals { true };
-    QHash<QTimer*, QScriptValue> _timerFunctionMap;
-};
-
-
-
-ScriptEngine* loadScript(const QString& scriptFilename) {
-    ScriptEngine* scriptEngine = new ScriptEngine();
-    scriptEngine->loadFile(scriptFilename);
-    return scriptEngine;
-}
-
-OffscreenGLCanvas* _chromiumShareContext { nullptr };
-Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
-
-
-// Create a simple OpenGL window that renders text in various ways
-class QTestWindow : public QWindow {
-    Q_OBJECT
-
-    QOpenGLContextWrapper* _context{ nullptr };
-    QSize _size;
-    bool _altPressed{ false };
-    RateCounter fps;
-    QTimer _timer;
-    int testQmlTexture{ 0 };
-    ProgramPtr _program;
-    ShapeWrapperPtr _plane;
-    QScriptEngine* _scriptEngine { nullptr };
-
-public:
-    QObject* rootMenu;
-
-    QTestWindow() {
-        _scriptEngine = new ScriptEngine();
-        _timer.setInterval(1);
-        QObject::connect(&_timer, &QTimer::timeout, this, &QTestWindow::draw);
-
-        _chromiumShareContext = new OffscreenGLCanvas();
-        _chromiumShareContext->create();
-        _chromiumShareContext->makeCurrent();
-        qt_gl_set_global_share_context(_chromiumShareContext->getContext());
-
-        {
-            setSurfaceType(QSurface::OpenGLSurface);
-            QSurfaceFormat format = getDefaultOpenGLSurfaceFormat();
-            setFormat(format);
-            _context = new QOpenGLContextWrapper();
-            _context->setFormat(format);
-            _context->setShareContext(_chromiumShareContext->getContext());
-        }
-
-
-        if (!_context->create()) {
-            qFatal("Could not create OpenGL context");
-        }
-
-        show();
-
-        makeCurrent();
-
-        glewExperimental = true;
-        glewInit();
-        glGetError();
-
-        using namespace oglplus;
-        Context::Enable(Capability::Blend);
-        Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha);
-        Context::Disable(Capability::DepthTest);
-        Context::Disable(Capability::CullFace);
-        Context::ClearColor(0.2f, 0.2f, 0.2f, 1);
-
-        InfoView::registerType();
-
-        auto offscreenUi = DependencyManager::set<OffscreenUi>();
-        {
-            offscreenUi->create(_context->getContext());
-            offscreenUi->setProxyWindow(this);
-
-            connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) {
-                testQmlTexture = textureId;
-            });
-
-            makeCurrent();
-        }
-
-
-        auto primaryScreen = QGuiApplication::primaryScreen();
-        auto targetScreen = primaryScreen;
-        auto screens = QGuiApplication::screens();
-        if (screens.size() > 1) {
-            for (auto screen : screens) {
-                if (screen != targetScreen) {
-                    targetScreen = screen;
-                    break;
-                }
-            }
-        }
-        auto rect = targetScreen->availableGeometry();
-        rect.setWidth(rect.width() * 0.8f);
-        rect.setHeight(rect.height() * 0.8f);
-        rect.moveTo(QPoint(20, 20));
-        setGeometry(rect);
-
-#ifdef QML_CONTROL_GALLERY
-        offscreenUi->setBaseUrl(QUrl::fromLocalFile(getTestQmlDir()));
-        offscreenUi->load(QUrl("main.qml"));
-#else 
-        offscreenUi->setBaseUrl(QUrl::fromLocalFile(getInterfaceQmlDir()));
-        offscreenUi->load(QUrl("TestRoot.qml"));
-#endif
-        installEventFilter(offscreenUi.data());
-        offscreenUi->resume();
-        _timer.start();
-    }
-
-    virtual ~QTestWindow() {
-        DependencyManager::destroy<OffscreenUi>();
-    }
-
-private:
-    void draw() {
-        if (!isVisible()) {
-            return;
-        }
-
-        makeCurrent();
-        auto error = glGetError();
-        if (error != GL_NO_ERROR) {
-            qDebug() << "GL error in entering draw " << error;
-        }
-
-        using namespace oglplus;
-        Context::Clear().ColorBuffer().DepthBuffer();
-        ivec2 size(_size.width(), _size.height());
-        size *= devicePixelRatio();
-        size = glm::max(size, ivec2(100, 100));
-        Context::Viewport(size.x, size.y);
-        if (!_program) {
-            _program = loadDefaultShader();
-            _plane = loadPlane(_program);
-        }
-
-        if (testQmlTexture > 0) {
-            glBindTexture(GL_TEXTURE_2D, testQmlTexture);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        }
-
-        _program->Bind();
-        _plane->Use();
-        _plane->Draw();
-        _context->swapBuffers(this);
-
-        fps.increment();
-        if (fps.elapsed() >= 10.0f) {
-            qDebug() << "FPS: " << fps.rate();
-            fps.reset();
-        }
-    }
-
-    void makeCurrent() {
-        _context->makeCurrent(this);
-    }
-
-    void resizeWindow(const QSize & size) {
-        _size = size;
-        DependencyManager::get<OffscreenUi>()->resize(_size);
-    }
-
-
-protected:
-    void resizeEvent(QResizeEvent* ev) override {
-        resizeWindow(ev->size());
-    }
-
-  
-    void keyPressEvent(QKeyEvent* event) override {
-        _altPressed = Qt::Key_Alt == event->key();
-        switch (event->key()) {
-            case Qt::Key_B:
-                if (event->modifiers() & Qt::CTRL) {
-                    auto offscreenUi = DependencyManager::get<OffscreenUi>();
-                    offscreenUi->load("Browser.qml");
-                }
-                break;
-
-            case Qt::Key_J:
-                if (event->modifiers() & Qt::CTRL) {
-                     loadScript(getExamplesDir() + "tests/qmlWebTest.js");
-                }
-                break;
-
-            case Qt::Key_K:
-                if (event->modifiers() & Qt::CTRL) {
-                    OffscreenUi::question("Message title", "Message contents", [](QMessageBox::Button b){
-                        qDebug() << b;
-                    });
-                }
-                break;
-        }
-        QWindow::keyPressEvent(event);
-    }
-
-    void moveEvent(QMoveEvent* event) override {
-        static qreal oldPixelRatio = 0.0;
-        if (devicePixelRatio() != oldPixelRatio) {
-            oldPixelRatio = devicePixelRatio();
-            resizeWindow(size());
-        }
-        QWindow::moveEvent(event);
-    }
-};
-
-const char * LOG_FILTER_RULES = R"V0G0N(
-hifi.offscreen.focus.debug=false
-qt.quick.mouse.debug=false
-)V0G0N";
-
-void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
-    QString logMessage = message;
-
-#ifdef Q_OS_WIN
-    if (!logMessage.isEmpty()) {
-        OutputDebugStringA(logMessage.toLocal8Bit().constData());
-        OutputDebugStringA("\n");
-    }
-#endif
-}
-
-
-int main(int argc, char** argv) {    
-    QGuiApplication app(argc, argv);
-    qInstallMessageHandler(messageHandler);
-    QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
-    QTestWindow window;
-    app.exec();
-    return 0;
-}
-
-#include "main.moc"

From f3f55c9857ecc675431ac582256a16ec3517a55a Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 11:49:19 -0700
Subject: [PATCH 08/28] Fixing render-perf

---
 tests/render-perf/src/TextOverlay.hpp         | 246 ------
 tests/render-perf/src/main.cpp                |  14 -
 .../src/stb_font_consolas_24_latin1.inl       | 734 ------------------
 3 files changed, 994 deletions(-)
 delete mode 100644 tests/render-perf/src/TextOverlay.hpp
 delete mode 100644 tests/render-perf/src/stb_font_consolas_24_latin1.inl

diff --git a/tests/render-perf/src/TextOverlay.hpp b/tests/render-perf/src/TextOverlay.hpp
deleted file mode 100644
index 5e0c211b8d..0000000000
--- a/tests/render-perf/src/TextOverlay.hpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
-* Text overlay class for displaying debug information
-*
-* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
-*
-* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-*/
-
-#pragma once
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <vector>
-#include <sstream>
-#include <iomanip>
-
-#include <GLMHelpers.h>
-
-#include "stb_font_consolas_24_latin1.inl"
-
-// Defines for the STB font used
-// STB font files can be found at http://nothings.org/stb/font/
-#define STB_FONT_NAME stb_font_consolas_24_latin1
-#define STB_FONT_WIDTH STB_FONT_consolas_24_latin1_BITMAP_WIDTH
-#define STB_FONT_HEIGHT STB_FONT_consolas_24_latin1_BITMAP_HEIGHT 
-#define STB_FIRST_CHAR STB_FONT_consolas_24_latin1_FIRST_CHAR
-#define STB_NUM_CHARS STB_FONT_consolas_24_latin1_NUM_CHARS
-
-// Max. number of chars the text overlay buffer can hold
-#define MAX_CHAR_COUNT 1024
-
-// Mostly self-contained text overlay class
-// todo : comment
-class TextOverlay {
-private:
-    uvec2 _size;
-// FIXME port from oglplus
-#if 0
-    FramebufferPtr _framebuffer;
-    TexturePtr _texture;
-    BufferPtr _vertexBuffer;
-    ProgramPtr _program;
-    VertexArrayPtr _vertexArray;
-    // Pointer to mapped vertex buffer
-    glm::vec4* _mapped { nullptr };
-
-    const char* const VERTEX_SHADER = R"SHADER(
-#version 450 core
-layout (location = 0) in vec2 inPos;
-layout (location = 1) in vec2 inUV;
-
-layout (location = 0) out vec2 outUV;
-
-out gl_PerVertex 
-{
-    vec4 gl_Position;   
-};
-
-void main(void)
-{
-    vec2 pos = inPos;
-    pos.y *= -1.0;
-    gl_Position = vec4(pos, 0.0, 1.0);
-    outUV = inUV;
-}
-)SHADER";
-
-    const char* const FRAGMENT_SHADER = R"SHADER(
-#version 450 core
-
-layout (location = 0) in vec2 inUV;
-
-layout (binding = 0) uniform sampler2D samplerFont;
-
-layout (location = 0) out vec4 outFragColor;
-
-void main(void)
-{
-    float color = texture(samplerFont, inUV).r;
-    outFragColor = vec4(vec3(color), 1.0);
-}
-)SHADER";
-
-#endif
-
-    stb_fontchar stbFontData[STB_NUM_CHARS];
-    uint32_t numLetters;
-
-
-public:
-    enum TextAlign { alignLeft, alignCenter, alignRight };
-
-    bool visible = true;
-    bool invalidated = false;
-
-
-    TextOverlay(const glm::uvec2& size) : _size(size) {
-        prepare();
-    }
-
-    ~TextOverlay() {
-#if 0
-        // Free up all Vulkan resources requested by the text overlay
-        _program.reset();
-        _texture.reset();
-        _vertexBuffer.reset();
-        _vertexArray.reset();
-#endif
-    }
-
-    void resize(const uvec2& size) {
-        _size = size;
-    }
-
-    // Prepare all vulkan resources required to render the font
-    // The text overlay uses separate resources for descriptors (pool, sets, layouts), pipelines and command buffers
-    void prepare() {
-#if 0
-        static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH];
-        STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT);
-
-        // Vertex buffer
-        {
-            GLuint buffer;
-            GLuint bufferSize = MAX_CHAR_COUNT * sizeof(glm::vec4);
-            glCreateBuffers(1, &buffer);
-            glNamedBufferStorage(buffer, bufferSize, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
-            using BufferName = oglplus::ObjectName<oglplus::tag::Buffer>;
-            BufferName name = BufferName(buffer);
-            _vertexBuffer = std::make_shared<oglplus::Buffer>(oglplus::Buffer::FromRawName(name));
-            _vertexArray = std::make_shared<oglplus::VertexArray>();
-            _vertexArray->Bind();
-            glBindBuffer(GL_ARRAY_BUFFER, buffer);
-            glEnableVertexAttribArray(0);
-            glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), 0);
-            glEnableVertexAttribArray(1);
-            glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)sizeof(glm::vec2));
-            glBindVertexArray(0);
-        }
-
-        // Font texture
-        {
-            GLuint texture;
-            glCreateTextures(GL_TEXTURE_2D, 1, &texture);
-            glTextureStorage2D(texture, 1, GL_R8, STB_FONT_WIDTH, STB_FONT_HEIGHT);
-            glTextureSubImage2D(texture, 0, 0, 0, STB_FONT_WIDTH, STB_FONT_HEIGHT, GL_RED, GL_UNSIGNED_BYTE, &font24pixels[0][0]);
-            glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-            using TextureName = oglplus::ObjectName<oglplus::tag::Texture>;
-            TextureName name = TextureName(texture);
-            _texture = std::make_shared<oglplus::Texture>(oglplus::Texture::FromRawName(name));
-        }
-
-        compileProgram(_program, VERTEX_SHADER, FRAGMENT_SHADER);
-#endif
-    }
-
-
-    // Map buffer 
-    void beginTextUpdate() {
-#if 0
-        using namespace oglplus;
-        _mapped = (glm::vec4*)glMapNamedBuffer(GetName(*_vertexBuffer), GL_WRITE_ONLY);
-        numLetters = 0;
-#endif
-    }
-
-    // Add text to the current buffer
-    // todo : drop shadow? color attribute?
-    void addText(std::string text, vec2 pos, TextAlign align) {
-        assert(_mapped != nullptr);
-        const vec2 fbSize = _size;
-        const vec2 charSize = vec2(1.5f) / fbSize;
-        pos = (pos / fbSize * 2.0f) - 1.0f;
-
-        // Calculate text width
-        float textWidth = 0;
-        for (auto letter : text) {
-            stb_fontchar *charData = &stbFontData[(uint32_t)letter - STB_FIRST_CHAR];
-            textWidth += charData->advance * charSize.x;
-        }
-
-        switch (align) {
-        case alignRight:
-            pos.x -= textWidth;
-            break;
-        case alignCenter:
-            pos.x -= textWidth / 2.0f;
-            break;
-        case alignLeft:
-            break;
-        }
-
-        // Generate a uv mapped quad per char in the new text
-        for (auto letter : text) {
-            stb_fontchar *charData = &stbFontData[(uint32_t)letter - STB_FIRST_CHAR];
-            _mapped->x = pos.x + (float)charData->x0 * charSize.x;
-            _mapped->y = pos.y + (float)charData->y0 * charSize.y;
-            _mapped->z = charData->s0;
-            _mapped->w = charData->t0;
-            ++_mapped;
-
-            _mapped->x = pos.x + (float)charData->x1 * charSize.x;
-            _mapped->y = pos.y + (float)charData->y0 * charSize.y;
-            _mapped->z = charData->s1;
-            _mapped->w = charData->t0;
-            ++_mapped;
-
-            _mapped->x = pos.x + (float)charData->x0 * charSize.x;
-            _mapped->y = pos.y + (float)charData->y1 * charSize.y;
-            _mapped->z = charData->s0;
-            _mapped->w = charData->t1;
-            _mapped++;
-
-            _mapped->x = pos.x + (float)charData->x1 * charSize.x;
-            _mapped->y = pos.y + (float)charData->y1 * charSize.y;
-            _mapped->z = charData->s1;
-            _mapped->w = charData->t1;
-            _mapped++;
-            pos.x += charData->advance * charSize.x;
-            numLetters++;
-        }
-    }
-
-    // Unmap buffer and update command buffers
-    void endTextUpdate() {
-#if 0
-        glUnmapNamedBuffer(GetName(*_vertexBuffer));
-        _mapped = nullptr;
-#endif
-    }
-
-    // Needs to be called by the application
-    void render() {
-#if 0
-        _texture->Bind(oglplus::TextureTarget::_2D);
-        _program->Use();
-        _vertexArray->Bind();
-        for (uint32_t j = 0; j < numLetters; j++) {
-            glDrawArrays(GL_TRIANGLE_STRIP, j * 4, 4);
-        }
-#endif
-    }
-};
diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp
index 987fbe33d5..8abb9f54e5 100644
--- a/tests/render-perf/src/main.cpp
+++ b/tests/render-perf/src/main.cpp
@@ -64,7 +64,6 @@
 #include <SceneScriptingInterface.h>
 
 #include "Camera.hpp"
-#include "TextOverlay.hpp"
 
 
 static const QString LAST_SCENE_KEY = "lastSceneFile";
@@ -1052,19 +1051,6 @@ private:
         }
     } };
 
-    struct TextElement {
-        const glm::vec2 position;
-        const std::string text;
-        TextOverlay::TextAlign alignment;
-    };
-
-    enum TextBlock {
-        Help,
-        Info,
-    };
-
-    std::map<TextBlock, std::list<TextElement>> _textBlocks;
-
     render::EnginePointer _renderEngine { new render::Engine() };
     render::ScenePointer _main3DScene { new render::Scene(glm::vec3(-0.5f * (float)TREE_SCALE), (float)TREE_SCALE) };
     QSize _size;
diff --git a/tests/render-perf/src/stb_font_consolas_24_latin1.inl b/tests/render-perf/src/stb_font_consolas_24_latin1.inl
deleted file mode 100644
index 12eedd2f43..0000000000
--- a/tests/render-perf/src/stb_font_consolas_24_latin1.inl
+++ /dev/null
@@ -1,734 +0,0 @@
-// Font generated by stb_font_inl_generator.c (4/1 bpp)
-//
-// Following instructions show how to use the only included font, whatever it is, in
-// a generic way so you can replace it with any other font by changing the include.
-// To use multiple fonts, replace STB_SOMEFONT_* below with STB_FONT_consolas_24_latin1_*,
-// and separately install each font. Note that the CREATE function call has a
-// totally different name; it's just 'stb_font_consolas_24_latin1'.
-//
-/* // Example usage:
-
-static stb_fontchar fontdata[STB_SOMEFONT_NUM_CHARS];
-
-static void init(void)
-{
-    // optionally replace both STB_SOMEFONT_BITMAP_HEIGHT with STB_SOMEFONT_BITMAP_HEIGHT_POW2
-    static unsigned char fontpixels[STB_SOMEFONT_BITMAP_HEIGHT][STB_SOMEFONT_BITMAP_WIDTH];
-    STB_SOMEFONT_CREATE(fontdata, fontpixels, STB_SOMEFONT_BITMAP_HEIGHT);
-    ... create texture ...
-    // for best results rendering 1:1 pixels texels, use nearest-neighbor sampling
-    // if allowed to scale up, use bilerp
-}
-
-// This function positions characters on integer coordinates, and assumes 1:1 texels to pixels
-// Appropriate if nearest-neighbor sampling is used
-static void draw_string_integer(int x, int y, char *str) // draw with top-left point x,y
-{
-    ... use texture ...
-    ... turn on alpha blending and gamma-correct alpha blending ...
-    glBegin(GL_QUADS);
-    while (*str) {
-        int char_codepoint = *str++;
-        stb_fontchar *cd = &fontdata[char_codepoint - STB_SOMEFONT_FIRST_CHAR];
-        glTexCoord2f(cd->s0, cd->t0); glVertex2i(x + cd->x0, y + cd->y0);
-        glTexCoord2f(cd->s1, cd->t0); glVertex2i(x + cd->x1, y + cd->y0);
-        glTexCoord2f(cd->s1, cd->t1); glVertex2i(x + cd->x1, y + cd->y1);
-        glTexCoord2f(cd->s0, cd->t1); glVertex2i(x + cd->x0, y + cd->y1);
-        // if bilerping, in D3D9 you'll need a half-pixel offset here for 1:1 to behave correct
-        x += cd->advance_int;
-    }
-    glEnd();
-}
-
-// This function positions characters on float coordinates, and doesn't require 1:1 texels to pixels
-// Appropriate if bilinear filtering is used
-static void draw_string_float(float x, float y, char *str) // draw with top-left point x,y
-{
-    ... use texture ...
-    ... turn on alpha blending and gamma-correct alpha blending ...
-    glBegin(GL_QUADS);
-    while (*str) {
-        int char_codepoint = *str++;
-        stb_fontchar *cd = &fontdata[char_codepoint - STB_SOMEFONT_FIRST_CHAR];
-        glTexCoord2f(cd->s0f, cd->t0f); glVertex2f(x + cd->x0f, y + cd->y0f);
-        glTexCoord2f(cd->s1f, cd->t0f); glVertex2f(x + cd->x1f, y + cd->y0f);
-        glTexCoord2f(cd->s1f, cd->t1f); glVertex2f(x + cd->x1f, y + cd->y1f);
-        glTexCoord2f(cd->s0f, cd->t1f); glVertex2f(x + cd->x0f, y + cd->y1f);
-        // if bilerping, in D3D9 you'll need a half-pixel offset here for 1:1 to behave correct
-        x += cd->advance;
-    }
-    glEnd();
-}
-*/
-
-#pragma once
-
-#ifndef STB_FONTCHAR__TYPEDEF
-#define STB_FONTCHAR__TYPEDEF
-typedef struct
-{
-    // coordinates if using integer positioning
-    float s0,t0,s1,t1;
-    signed short x0,y0,x1,y1;
-    int   advance_int;
-    // coordinates if using floating positioning
-    float s0f,t0f,s1f,t1f;
-    float x0f,y0f,x1f,y1f;
-    float advance;
-} stb_fontchar;
-#endif
-
-#define STB_FONT_consolas_24_latin1_BITMAP_WIDTH         256
-#define STB_FONT_consolas_24_latin1_BITMAP_HEIGHT        170
-#define STB_FONT_consolas_24_latin1_BITMAP_HEIGHT_POW2   256
-
-#define STB_FONT_consolas_24_latin1_FIRST_CHAR            32
-#define STB_FONT_consolas_24_latin1_NUM_CHARS            224
-
-#define STB_FONT_consolas_24_latin1_LINE_SPACING          16
-
-static unsigned int stb__consolas_24_latin1_pixels[]={
-    0x08262131,0xff904400,0x3ffe1fff,0x3b2206ff,0x2007913f,0x0000defa,
-    0x64c00f32,0x0de5c402,0x00a614c0,0x4002ae62,0x98014c19,0x01aa881c,
-    0x00d54400,0xb880154c,0x8330020b,0x1e980029,0xaa7d5dd4,0x2001d94f,
-    0x3332a6e8,0x999ff0ff,0x37ffa207,0x2600df12,0x8000fffd,0x3fa005fd,
-    0xfdff700f,0x8ffc409f,0x3ea02ff8,0x200dffff,0x0bfe0ff8,0x7d407ee0,
-    0xfd10001f,0x9fff5007,0xcffff880,0x1ff104eb,0x320017fc,0x7d77e40f,
-    0x17ee9f54,0xfd027ec0,0x7dc01fe1,0x0037c40d,0xb0017f22,0xffe8007f,
-    0x7dc3fd80,0x741ff104,0x59ff701f,0x7401dfd7,0x2003f60e,0x3fa200fc,
-    0x0ff44001,0x7dc6fdc0,0x32236604,0x3ba00eff,0x31003f60,0xdf90dd57,
-    0xd93ea9f5,0x037e403f,0x803fc3fa,0x06f882fd,0x2006f980,0xa8800098,
-    0xf903fb81,0x88040401,0x1ff441ff,0x0fb00000,0x00000000,0x00020000,
-    0xffffa800,0xfadfb86f,0x7fc49f54,0x803ff301,0x200ff0fe,0x06f880fe,
-    0x0000ff00,0x05f88000,0x40000fe6,0x0ff504fc,0x81540153,0x100affb9,
-    0x22001573,0x31000ab9,0x26200157,0x731000ab,0xcffb8015,0x7dc4ffda,
-    0x89f54fad,0x3fe80ff9,0x0ff0fe80,0x3e203fa0,0x807ddb36,0x01dd107f,
-    0xdddb076c,0x1fb8bddd,0x1dd12fc0,0x3ff076c0,0x3f60ffc0,0xe98ff102,
-    0xa84fffff,0x00dfffff,0x37ffffea,0x3fffea00,0x3fea00df,0x2a00dfff,
-    0x80dfffff,0x3bb61ff8,0x3eb3ea3f,0x7f909f54,0xfd005fa8,0x7f401fe1,
-    0xffaef880,0x1fe05ffe,0xdf504fd8,0xfffffff8,0x9db33746,0x09fb1b6b,
-    0x80ff1bea,0x817ec2fd,0x33fe67f8,0x7dc3acfa,0x0efebacf,0xebacffb8,
-    0xcffb80ef,0xb80efeba,0xefebacff,0xbacffb80,0x27e40efe,0x20df59f1,
-    0x509f54fa,0x003fd8bf,0x401fe1fd,0x9fff107e,0x7407fe61,0x20ff500f,
-    0x6f9803fd,0x777ccfe2,0x7fa8db6f,0x37cc7fb0,0x5fb0ff60,0x3fe9fe20,
-    0x3ff105f3,0x7c43fe88,0x21ff441f,0x7f441ff8,0x220ffc43,0x0ffc43fe,
-    0x3ff0ffa2,0x267f97d4,0x9f54fadf,0x1ff8ff10,0x1fe1fd00,0x7c417e20,
-    0x704fb84f,0x217f405f,0xf9800ff8,0x47f47ea6,0xfd0f95f8,0x260ff885,
-    0x21fe406f,0x2ff102fd,0x207ea6f9,0x8ff504fc,0x8ff504fc,0x8ff504fc,
-    0x8ff504fc,0x8ff504fc,0x3fd3e47f,0x553eafea,0x261ff04f,0x1fd000ff,
-    0xefcc81fe,0x260ff101,0x9bfb105f,0x7d45fb81,0x64df3005,0x9f34f98f,
-    0x517ee1f2,0x407f98bf,0x817ec2fd,0x5cbf57f8,0x201ff80f,0x807fe1ff,
-    0x807fe1ff,0x807fe1ff,0x807fe1ff,0xf8df31ff,0x47e4bf65,0x203514fa,
-    0x00df52fd,0x107f87f4,0x7c403fff,0x440df306,0x7fc41ffe,0x4c00bf60,
-    0x97ddf66f,0xf10db2fa,0x2217ec1f,0x20ff407f,0x2ff102fd,0x7c1f64fb,
-    0xff17ec07,0x1fe2fd80,0x03fc5fb0,0x407f8bf6,0x4cdf32fd,0x9d4ff22f,
-    0x9f7004fa,0xfe8013ee,0x6cc40ff0,0x20df103f,0x3bf506f9,0x7c4ff601,
-    0xd9be6007,0x47f23f96,0x227fb06d,0x203ff07f,0x17ec0ff8,0x4df57f88,
-    0x406f986e,0x80df33fd,0x80df33fd,0x80df33fd,0x80df33fd,0x64ff13fd,
-    0x2a0bf60f,0x29f9004f,0x3fa005fa,0x1be00ff0,0x5fa837c4,0xfa801f90,
-    0x4c009f76,0x87edba6f,0x2a09f0fd,0x3209f76f,0xb0bf704f,0x4dfe205f,
-    0xf30bf0ff,0xf33fc80d,0xf33fc80d,0xf33fc80d,0xf33fc80d,0x3e3fc80d,
-    0x03fd1ba7,0x3f6009f5,0x7400ff13,0x3a00ff0f,0x906f880f,0x401fa07f,
-    0x001fe9ff,0xf96e9be6,0x017cdfe3,0x203fd3ff,0x7fd43ff9,0xf102fd81,
-    0x27d7fecf,0xfb01fe63,0xfb01fe65,0xfb01fe65,0xfb01fe65,0xfb01fe65,
-    0x1fc4ff45,0x9f501ff1,0xfe8bfe00,0x3e1fd001,0x101fd007,0x40df50df,
-    0xfbf9007e,0x26f9800d,0xfdb9f56d,0x7e401fb7,0x7fdc06fd,0xb02ffede,
-    0x89fe205f,0x4feefffc,0x1fe80ff1,0x1fe80ff1,0x1fe80ff1,0x1fe80ff1,
-    0x1fe80ff1,0xb87ef7f2,0x2a9f505f,0x647f984f,0x21fd002f,0x01fd007f,
-    0xfb99dff1,0x803f403f,0x4003fff8,0x6c5f26f9,0x01ffe8ef,0x401fffc4,
-    0x01dfffda,0x2fd40ff2,0x0e77ff4c,0x3fe203ff,0x7c407fe0,0x4407fe0f,
-    0x407fe0ff,0x07fe0ff8,0xff107fc4,0x807fd4fd,0x509f54fa,0x004fa8bf,
-    0x401fe1fd,0xfff880fe,0x7400deff,0x01ff6007,0x0fb9be60,0x7ec00302,
-    0x027dc007,0x4fc827dc,0x3f203f70,0xfc8bf704,0xfc8bf704,0xfc8bf704,
-    0xfc8bf704,0xf30bf704,0x07ffd9df,0x84faa7d4,0x07fc41fe,0x07f87f40,
-    0xdf101fd0,0x07f80022,0x2000ff60,0x00fe65fa,0x001fec00,0x98103fe6,
-    0x0ffcc1ff,0xff100fc8,0x440ffa87,0x07fd43ff,0xff50ffe2,0x543ff881,
-    0x1ffc40ff,0x7dc03fea,0x5401dfff,0xfc89f54f,0xd00df705,0x6c01fe1f,
-    0x006f883f,0xf5006f98,0x9fb0001f,0xa80006e8,0xfd8000ff,0xfc86fcdf,
-    0x04ffecdf,0xdff701f6,0x2e07ffd9,0x3ffeceff,0xfd9dff70,0x3bfee07f,
-    0xf703ffec,0x07ffd9df,0x5000cfec,0xfa93ea9f,0x013f600f,0x401fe1fd,
-    0x37c41efb,0x013f6600,0x33007fea,0x2e07fdc4,0xf500505f,0x7e40003f,
-    0xfd703fff,0x6e805dff,0xdfffea80,0x7fff5401,0x7ff5401d,0x7f5401df,
-    0x75401dff,0x7c01dfff,0x54fa8005,0x00bfe29f,0x775c3fd1,0xddff0ffe,
-    0x7fff409d,0x2600df12,0xf300effe,0xf7007fff,0x207fffdf,0x7fdcdffb,
-    0x07ffff30,0x80022000,0x0017e001,0x00060003,0x0018000c,0x07220030,
-    0x7d53ea00,0x26007fb4,0x3bbbae6f,0x9ddddb0e,0xd12ecb80,0x0f3a600b,
-    0x0019bd30,0x073bbb22,0x17bdb730,0x00337a60,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x4d3ea9f5,0x00154004,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x009f54fa,
-    0x77777400,0xeeeeeeee,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x4c000000,0x0007d33e,0x77777740,0x0eeeeeee,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x54400000,0x2a20001a,0x0154c01a,0x54400b20,
-    0xaaa98000,0x99953100,0x032e0059,0x10053066,0x22004177,0x04c801aa,
-    0x01aa8800,0x500d5440,0x51017997,0x51000035,0x0bb88035,0x00d54402,
-    0x0007fea0,0xf500ffa2,0x3e6009ff,0x3fef9803,0xfffff700,0xffffb89f,
-    0xf8804fff,0x3e0ff886,0x3ffe202f,0x5404ebcf,0x0fec01ff,0x07fd1000,
-    0x103fe880,0x05fffffd,0x80007fea,0x7c403fe8,0x04ebcfff,0x88003ff5,
-    0x3a2001fe,0x46fdc01f,0x7dc404fb,0x6baec00b,0xabcffd80,0x3fff24ec,
-    0x804fb9df,0x41dd03fb,0x236600fd,0x800effc8,0x3e601fe8,0x3fd10005,
-    0x01fe8800,0x008833f6,0x20007fa2,0xd9801fe8,0x00effc88,0x00007fa2,
-    0x00000000,0x9fffffd5,0x036cf640,0x98407bee,0xf54fffff,0x001fd009,
-    0x00020000,0x0007f400,0x44000000,0x0000007f,0x00200000,0x40153000,
-    0xa802a62a,0x2a802a62,0x33fb7ff2,0x3bfa204d,0x007fe201,0x53fffff2,
-    0x27d404fa,0x40015540,0x553002aa,0x50555555,0x01aa807f,0x554c1544,
-    0xf82aaaaa,0x2aa8002f,0x802aa800,0x50aa02a9,0x55555555,0xf102fd81,
-    0xf8817ecf,0x7c40bf67,0x1f61ff37,0x5c02aa80,0xfff9005f,0x013ea9ff,
-    0xff8803fb,0x3fe2002f,0xfffc802f,0xdf07ffff,0x6406fb80,0xffffc85f,
-    0xffb87fff,0x3ffe2003,0x3ffe2002,0x41ffe402,0x7fffc6f8,0x6c0fffff,
-    0x6cff102f,0x6cff102f,0x2eff102f,0x4401ba5f,0x3f202fff,0xffff7003,
-    0x8813ea9f,0xfffa805f,0x3ffea004,0xaacfc804,0x5f902aaa,0xf103ff80,
-    0x559f901f,0xff985555,0xfa802eff,0x3ea004ff,0x7fe404ff,0x5546f886,
-    0x0aaadfda,0x7f8817ec,0x3fc40bf6,0x5fe205fb,0x4017e7fa,0x3604fffa,
-    0xfff3002f,0x813ea9ff,0xafd802fc,0x2bf6007f,0x03fc807f,0x2a02fc40,
-    0x04fd80ff,0x3fa007f9,0x404ffd89,0x2007fafd,0x6407fafd,0x37c42fef,
-    0xfd809f70,0x7ecff102,0x7ecff102,0x3e2ff102,0xb004faef,0x7f40ff5f,
-    0x3fff2002,0x7c09f54f,0xfd7f8807,0x3aff1003,0x01fe401f,0x3a00fec0,
-    0x807fcc4f,0x5f9803fc,0xf8827fd4,0xf1003fd7,0xfc807faf,0x037c46fb,
-    0x2fd809f7,0x17ecff10,0x0bf67f88,0xffd33fc4,0x7f88019f,0x0bfa03fd,
-    0x29ffd500,0x07f504fa,0x13ee9f50,0x27dd3ea0,0x2000ff20,0x7fcc04fa,
-    0xfc80ff60,0x886f9803,0x74fa81ff,0x29f5009f,0x2bf204fb,0x81be22fd,
-    0x17ec04fb,0x0bf67f88,0x05fb3fc4,0x3fae1fe2,0x53ea03ff,0x07fb04fb,
-    0x4fa84c00,0xfb001fd0,0x3601fe65,0xc80ff32f,0x1fd0003f,0xdf34fd80,
-    0xf003fc80,0xb07f905f,0x201fe65f,0x40ff32fd,0x226faafc,0x013ee06f,
-    0x9fe205fb,0x4ff102fd,0x0ff102fd,0x417ff7ee,0x20ff32fd,0x500006fb,
-    0x00bf309f,0x01fe8ff1,0x03fd1fe2,0x777777e4,0x01fdc04e,0x0bf63fe2,
-    0xdddddf90,0x43ffa89d,0x23fc43fb,0x1fe201fe,0x4bf203fd,0x40df11fe,
-    0x17ec04fb,0x0bf67f88,0x05fb3fc4,0x9be41fe2,0x23fc43ff,0x2ff881fe,
-    0x84fa8000,0x5fa801fc,0xbf5027e4,0x3f204fc8,0x06ffffff,0x7e4037c4,
-    0xffc806fe,0xa86fffff,0x0ff89eff,0x13f22fd4,0x27e45fa8,0x2bf52fc8,
-    0x13ee06f8,0x3e205fb0,0x7c40bf67,0x7c40bf67,0x2fdcdb07,0x09f917ea,
-    0x0620bff2,0x3e227d40,0x985fb006,0x30bf607f,0x01fe40ff,0x8803f900,
-    0xfc801fff,0x7fec4003,0x42fd82ff,0x0bf607f9,0x8bf20ff3,0x206f89ff,
-    0x17ec04fb,0x0bf67f88,0x05fb3fc4,0xb2f41fe2,0x4c2fd89f,0x3fff607f,
-    0x5004fedd,0x802fb89f,0x99999ff8,0x9ff881ff,0x01ff9999,0x4c0007f9,
-    0x05fb805f,0x20007f90,0xff886fe9,0x1ff99999,0x9999ff88,0x2fc81ff9,
-    0x81be33ee,0x1fe404fb,0x0ff25fa8,0x07f92fd4,0x9f04d7ea,0x7c43ff71,
-    0xff99999f,0x3fffaa01,0x7f9002ce,0xff5007e8,0x9fffffff,0xffffff50,
-    0x3f209fff,0x07f40003,0x64013ee0,0x3a20003f,0x7fffd42f,0xa84fffff,
-    0xffffffff,0x222fc84f,0x2e06f9ff,0x827dc04f,0x413ee4fc,0x413ee4fc,
-    0xfdffb4fc,0xfa87ffff,0xffffffff,0x0077c404,0x9f517f40,0x3337f600,
-    0xd86fdccc,0xdcccccdf,0x007f906f,0x5c04fa80,0x07f9004f,0x6c2fe800,
-    0xdcccccdf,0xccdfd86f,0xc86fdccc,0x37e7e42f,0xf9809f70,0x30ffcc1f,
-    0x1ff983ff,0xff307fe6,0x3fffb6a3,0xcdfd80ce,0x06fdcccc,0x37601fd4,
-    0x6c6fd989,0x0ff8800f,0xff887fe0,0x3207fe00,0x7f80003f,0xc8027dc0,
-    0x4c15003f,0x3fe20ffb,0xf887fe00,0x907fe00f,0x6fff885f,0x32013ee0,
-    0x4ffecdff,0xfecdffc8,0xcdffc84f,0x3f704ffe,0xf007fc40,0x00fe403f,
-    0xdfffffb1,0xa802fcc3,0x527ec05f,0x84fd80bf,0xeeeeeefc,0x80bee006,
-    0xdf9004fb,0xf8dddddd,0x41ffffff,0x27ec05fa,0x4fd80bf5,0x7fe417e4,
-    0x7ff776c6,0xfd700eee,0x75c05dff,0x2e02efff,0x202efffe,0x17ea00fc,
-    0x14c09fb0,0x82cdba80,0x7fb001ca,0x3f66fa80,0x6437d403,0x7fffffff,
-    0xb80f2200,0xfff9004f,0xcb8fffff,0x7fb02cdd,0x3f66fa80,0x3237d403,
-    0x46ff882f,0xffffffff,0x8001800f,0x90018001,0x403fd80b,0x000006fa,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x0d544000,0x2600aa60,0x54c014c1,0x14c19802,0x400154c0,
-    0xcb9802c9,0x0332e02c,0x30a60f22,0x00332a05,0x4000b260,0x0cca83cc,
-    0x01e64000,0x2e200b26,0x6644020b,0x00cca801,0xe8803ca8,0x7ffd403f,
-    0xf83fe204,0x3ffea02f,0xf83fe204,0x3ffea02f,0x3f7ee004,0x3ffff604,
-    0x7f7ec0ef,0x220fe40f,0x05ff11ff,0xa8003bee,0x6c003fff,0x03bee05f,
-    0x202fec00,0x2203fffa,0x4eacffff,0x9d95ff70,0x9003bee0,0x1fe880bf,
-    0x7dc6fdc0,0xfd83ba04,0xf71bf700,0xfb077409,0x2e37ee01,0x2a7d004f,
-    0x261bf907,0x54fea4fd,0x2213ea3f,0x807fa0ff,0xfa800ef9,0xb003fc8d,
-    0x1df3007f,0x403fd800,0x03fc8dfa,0xdffb31d3,0xfffdb881,0x3be603ef,
-    0x0017f200,0x00000000,0x00000000,0x7b8dd800,0x6f981ff0,0x8a7c47ee,
-    0x020200ee,0x22002620,0x4c400cc1,0x00262000,0x18800988,0x011000cc,
-    0x0ffb7fe2,0xf9004c40,0x5555550b,0xaa981555,0x982aaaaa,0x2aaaaaaa,
-    0xaaaaaaa8,0x555540aa,0x200aaaaa,0x7cc002aa,0x86f882ff,0x44bee5fa,
-    0x0005f94f,0x00000000,0x00000000,0x00000000,0x001ff982,0xff0bf900,
-    0x1fffffff,0xffffffc8,0xffffc87f,0xfff87fff,0x40ffffff,0xffffffff,
-    0x5fff100f,0x26013000,0x30ffd45f,0xf33fb3bf,0x9dfb7009,0xcefdb801,
-    0x677edc00,0x677edc00,0xdfdb7100,0x3b6e203b,0xb7101def,0x2203bdfd,
-    0x01defedb,0x01bffb2a,0x7039dfb7,0xfb5550bf,0xfc81555b,0x82aaaaac,
-    0xaaaaacfc,0xdfdaaa82,0x55540aaa,0x00aaadfd,0x1009fff5,0x83bdfdb7,
-    0x07bee5f9,0x7f4fffee,0x76f7ec00,0xbdfb02ff,0x3f605ffd,0xb02ffede,
-    0x05ffdbdf,0xfffddff7,0xfddff705,0xdff705ff,0xf705fffd,0x05fffddf,
-    0x5ffddffb,0xffdffd30,0x404fb87f,0x1fe404fb,0x0007f900,0xfb8013ee,
-    0xff5fb004,0xfddff700,0x8afcc5ff,0x426200ff,0x27e402fc,0x9f903fea,
-    0x7e40ffa8,0x3207fd44,0x207fd44f,0x43fdc419,0x43fdc419,0x43fdc419,
-    0x23fdc419,0x1bea0dfc,0x3ff513fa,0x3ee027dc,0x001fe404,0x2e0007f9,
-    0x13ee004f,0x0ff5fe20,0xff710660,0x07f8afcc,0xf1017e60,0xf88ff20d,
-    0x7c47f906,0x7c47f906,0x4007f906,0x3fe000ff,0x003fe000,0x0df30ff8,
-    0x05fa87fa,0x027dcbf9,0x7f9013ee,0x001fe400,0x2e004fb8,0x74fa804f,
-    0x7fc0009f,0x27fcbf30,0x5400fe80,0x549f504f,0x549f504f,0x549f504f,
-    0x009f504f,0xfb000fec,0x00fec003,0x0fee3fb0,0x05f927e4,0x04fb9be2,
-    0x3f2027dc,0x00ff2003,0x70027dc0,0x25fb009f,0x360007f9,0x7ccbf31f,
-    0x4bee00df,0x77dc1dec,0x5feeeeee,0x3bbbbbee,0x3bee5fee,0x5feeeeee,
-    0x3bbbbbee,0xec985fee,0x981ffffe,0x1ffffeec,0xfffeec98,0xfeec981f,
-    0x05fb1fff,0x01fe97ea,0x403fa9fe,0x77e404fb,0xc84eeeee,0x4eeeeeef,
-    0x70027dc0,0x47f8809f,0x764c01fe,0xf31ffffe,0x80efe98b,0xffbfd5f8,
-    0x77777e43,0x3f24eeee,0xeeeeeeee,0x3bbbbf24,0x3f24eeee,0xeeeeeeee,
-    0x6677fdc4,0x7fdc1ffc,0x41ffccce,0xfccceffb,0x677fdc1f,0x3fb1ffcc,
-    0x1fe97ea0,0x03fa9fe0,0x3f2027dc,0x86ffffff,0xfffffffc,0x0027dc06,
-    0x5fa809f7,0xff7027e4,0x23ff999d,0x4fe885f9,0x33f98fe8,0x002fdc9f,
-    0x7dc00bf7,0x017ee005,0xfd81ff88,0x3607fe21,0x207fe21f,0x07fe21fd,
-    0x817e47f6,0x40bf64fb,0x007266f8,0x3fc809f7,0x000ff200,0xf70027dc,
-    0x4c2fd809,0x03ff107f,0x417e63fb,0xb9fdc6f9,0xffa97e1f,0x01ff5000,
-    0x4003fea0,0xf5000ffa,0xfa87fa0b,0x7d43fd05,0x7d43fd05,0x3ee3fd05,
-    0x7e45fb05,0x000bf704,0x3fc809f7,0x000ff200,0xf70027dc,0x4cffc409,
-    0xa81ff999,0x263fd05f,0x44df305f,0x7c4bea6f,0x80067f44,0xfd000cfe,
-    0x33fa0019,0x446fa800,0x1bea1ffd,0x7d43ffb1,0x50ffec46,0x1ffd88df,
-    0x7fa85ff1,0x3e60ffc4,0x700faa1f,0x03fc809f,0x4000ff20,0x3ee004fb,
-    0x3fffea04,0xa84fffff,0x8ffec46f,0xfb9935f9,0xf10fec5f,0xf983fb7d,
-    0x0eccbdff,0x65efffcc,0x7ffcc0ec,0x4c0eccbd,0xeccbdfff,0x373bfe20,
-    0x3e21feff,0xfeffdcef,0x373bfe21,0x3e21feff,0xfeffdcef,0x3737fee1,
-    0xdffb82ff,0x7fc3ffdc,0x2027dc07,0x3f2003fc,0x09f70003,0xfb027dc0,
-    0xfb99999b,0xb9dff10d,0x3e63fdff,0x45dfff35,0xfffa83fa,0xffffb102,
-    0xffb101df,0xb101dfff,0x01dfffff,0xdfffffb1,0xdfffe981,0x7f4c1fc8,
-    0x41fc8dff,0xc8dfffe9,0x7fff4c1f,0x7541fc8d,0x2a01efff,0xc81efffe,
-    0x027dc05f,0xfc800ff2,0x09f70003,0xf8827dc0,0x207fe00f,0xc8dfffe9,
-    0x0002201f,0x02620008,0x20009880,0x26200098,0x40008800,0x00440008,
-    0x06000220,0x40600600,0xeeffeeed,0x7777e40e,0xefc86eee,0xd86eeeee,
-    0xeeeffeee,0x7ff776c0,0x0bf50eee,0x02204fd8,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0xffffff80,0x7fe40fff,0xc87fffff,
-    0x7fffffff,0xfffffff8,0x7fffc0ff,0xfb0fffff,0x006fa807,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x40f32000,0xca814c29,0x055cc00c,0x203cc800,0x98014c29,0x0bb8802c,
-    0x40044002,0x298003c8,0x0310014c,0x8000b260,0x157300cb,0x76c17a20,
-    0x00f32000,0x32a0aa62,0x027d400c,0xf882fec0,0x205ff11f,0x3ee00efb,
-    0x36001eff,0x47fe205f,0x7d402ff8,0x3fe203ff,0x204eacff,0x203ffffa,
-    0x7c4006f8,0x005ff11f,0x3fea01f6,0x3fb0003f,0x4fffff98,0x1fd06f88,
-    0x8817f600,0x706ffffb,0x7ff401df,0x80ff6000,0x07fa0ff8,0x5100ef98,
-    0xb005ffd7,0x0ff8807f,0xdfa807fa,0x1d303fc8,0x201dffb3,0x2ffdcffa,
-    0x8800df10,0x007fa0ff,0x37ea02fc,0xd8003fc8,0x26ffea1f,0x37c44feb,
-    0xfd800fe8,0x37ffe603,0x3be602ac,0x400bf700,0x10100098,0x20013100,
-    0x26200ffb,0x00202000,0x20019831,0x717ec008,0x01be20bf,0xb7004040,
-    0x18807fff,0x7ec000cc,0xff10bfa1,0xfe837c41,0x1004c400,0x310007ff,
-    0x00000001,0x20000000,0x000004fd,0x00000000,0x6f983fe0,0x0000df10,
-    0xfeffe980,0x000001ff,0x17ea3fb0,0x0df127dc,0x200003fa,0x000003fc,
-    0x05e88026,0x82f443d9,0x417a21ec,0x17ee01ec,0x00e77edc,0x80e77edc,
-    0x03d905e8,0x8073bf6e,0x413ee2fe,0x7ddb36f8,0x3bfb6e20,0xf13fe81d,
-    0x6dc03ffd,0x65401cef,0xf91ffdee,0x44dfd305,0x701fd06f,0x7c0bdddd,
-    0x7775c007,0x407f305e,0x45fb06f8,0x45fb06f8,0x05fb06f8,0x3fa61fdc,
-    0x303fffef,0x7fffdffd,0x3f60df10,0x7f7ff4c2,0x2df903ff,0xdf100ffa,
-    0x0bffdff5,0xfffddff7,0x5f52fdc5,0xffd309f7,0xb107fffd,0x3fffdfff,
-    0xfff707f6,0xfe837c4f,0x7ffffc80,0x2aa2bf30,0xffff9009,0x8813ea0f,
-    0x445fb06f,0x445fb06f,0x205fb06f,0x27f40ff9,0x3fa07fea,0x220ffd44,
-    0xe85fb06f,0x40ffd44f,0x01efeff8,0x4c33ffe2,0x220cc1ff,0xd8bf27fb,
-    0x9fd0bf17,0x7e41ffa8,0xfe8ff42d,0xff3dfb10,0x0fe837c4,0xfa83fc40,
-    0x2fffffee,0xfa83fc40,0x6c1be204,0x6c1be22f,0x6c1be22f,0x3fffe62f,
-    0xfc82fd44,0xfc82fd45,0xfd837c45,0x7e417ea2,0x00bffb05,0x9f709ff1,
-    0xfe87fc00,0x547f93e0,0x44bf905f,0x3e3fb07f,0xf0dff98f,0x303fe21f,
-    0x7f8803ff,0x537bff70,0x7c403ff9,0x4409f507,0x445fb06f,0x445fb06f,
-    0x4c5fb06f,0x05f902ef,0x05f91be2,0x0df11be2,0x02fc8bf6,0xefe88df1,
-    0x88ff11ff,0x00bf307f,0x50fe8fec,0x3f23fc5f,0x7dcdf102,0x3fa3fb04,
-    0x13fc3ffc,0x7ff445ff,0xb83fc401,0x40bf904f,0x09f507f8,0x2fd837c4,
-    0x17ec1be2,0x8bf60df1,0x07fa04f9,0x00ff47f8,0xb06f88ff,0xf00ff45f,
-    0xdfb4fd8f,0x6f88df31,0xd930df30,0x323ffffd,0x37c4fb2f,0x27f807fa,
-    0x23fb03fc,0x7c41effd,0x337ffe27,0x202efbef,0x09f707f8,0x7f881be6,
-    0x7c40bf50,0x7c45fb06,0x7c45fb06,0x7cc5fb06,0xf807fa04,0xff00ff47,
-    0x5fb06f88,0x4ff00ff4,0x56ff47f8,0x9837c45f,0x677fdc6f,0x9f51ffcc,
-    0x745fa97e,0xfd9fe01f,0x3f23fb02,0x225fa80d,0xb0dffeef,0x83fc409f,
-    0x0ff105fa,0x5fb83fc4,0x7ec1be20,0x7ec1be22,0x7ec1be22,0xfd80b222,
-    0xfd8df102,0xf88df102,0x7ec5fb06,0x7ccdf102,0x17fffc46,0x2fd41be2,
-    0x3fb03ff1,0x44bf3fe2,0x817ec1fe,0x413f26f8,0x20df31fe,0x45be22fd,
-    0x07f88000,0x17ea0ff1,0xbf707f88,0x7c40ff80,0x2207fc2f,0x207fc2ff,
-    0x64002ff8,0xc8bf704f,0xf0bf704f,0x22ff881f,0x4bf704fc,0xfffa87f9,
-    0xfc837c40,0x7f417ea3,0x373ffea1,0x04fc84ff,0x42fdcbf7,0x0ffa1ffb,
-    0x06f88ff5,0xb03fc400,0x02fe889f,0x2fdc1fe2,0xfe88bfe0,0xd117fc2f,
-    0x22ff85ff,0x3a62ffe8,0x307fe204,0x1ff883ff,0x7fc0ffcc,0x88bffa22,
-    0x0ffcc1ff,0xffd50ffe,0xfa86f883,0x36237d46,0x7ffd41ff,0x3ff102ef,
-    0x3e21ff98,0x87ffea1f,0xffdcdff9,0x00037c41,0xff981fe2,0x404fecbd,
-    0x0bf707f8,0xefcdffb8,0x6ffdc2fd,0x5c2fdefc,0xfdefcdff,0xb803ff62,
-    0x3ffdcdff,0xfb9bff70,0x37fee07f,0x5c2fdefc,0x3ffdcdff,0xffceffa8,
-    0x3e20efef,0x1ffdccef,0x7ee77fc4,0x5fd41fef,0x9bff7001,0xffb07ffb,
-    0x83f99fdb,0x81dfffd8,0xcc8006f8,0x1cccffcc,0x177ffec4,0xcffcccc8,
-    0x00df71cc,0xf71bffd5,0x1bffd505,0xffd505f7,0x7dc5f71b,0xfffea806,
-    0x7ff5401e,0x7f5401ef,0xa82fb8df,0x201efffe,0xd1dfffea,0xfffdb8bf,
-    0xffd300de,0xd83f91bf,0xffea8007,0x3ff201ef,0x0c03f93e,0x20017a20,
-    0xffffffff,0x3e00603f,0xffffffff,0x4400bd73,0x00044000,0x00020022,
-    0x000c0006,0x00c00044,0x01000040,0x3c800440,0x2000c000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x55530000,0x53035555,0x54c00557,
-    0xba9800aa,0x2aaaa60a,0x2a600aaa,0x0032e009,0x32205950,0x020bb883,
-    0x3c881654,0x6440736e,0x09999953,0x80357510,0x209aca98,0x20aa00a9,
-    0x2e014c29,0x0164c03f,0x1dd127dc,0x64c076c0,0xfffffc82,0x7ffe44ff,
-    0x3ee03fff,0x904fffff,0x2bffffff,0xfffffffc,0xfffffb81,0x000fe80d,
-    0x320bffd3,0x7fffc41f,0x3fa64eac,0x6c3f905f,0x1fc80ffd,0x40fffff9,
-    0xefffffc8,0xfffffc81,0x440bf65f,0x88ffc47f,0x1ffe02ff,0x203fffa8,
-    0x3f62fff8,0x3a0df504,0x567e40ff,0x5dc1aaaa,0x81ffdb9a,0xecabcffd,
-    0x5e7ff444,0x55535dca,0xfd83fd55,0x0efc989c,0xea8007f4,0x84fa85fa,
-    0xeffd98e9,0x217ebaa0,0x83fb04fa,0x266624fa,0x2fbf607f,0x360ffda9,
-    0x3baabcef,0x3fc40bf6,0x1fe83fe2,0x7d413f60,0x3e03fc8d,0x41fea1ff,
-    0x1ffd03fd,0x40001fc8,0x0f7dc4fe,0x8077ec08,0xf70ff400,0xfd17ea07,
-    0x45f88001,0x11000ee8,0x3a22fc40,0x22ffe40e,0xff100ee8,0x3e03fe20,
-    0x003ff32f,0x1fe205fb,0x20000404,0x9300cc18,0xf885fd05,0x9035100f,
-    0xfb80003f,0x4007fe25,0x20000ffa,0x4cdf11fe,0x743f91bb,0x2fc4000f,
-    0x80000bf2,0x417e45f8,0x3f23fda9,0x441fe202,0x2e5fb06f,0x05fb005f,
-    0x80001fe2,0x00000098,0x5fa8bf70,0x003f9000,0x3ee2fc80,0x00ff6005,
-    0x3ee3fd00,0x22ffff52,0x3603fa4f,0x265f884e,0x2a9d104f,0xbf101cfd,
-    0xc99827cc,0x8809f34f,0x10bfa07f,0x007fd4ff,0x7f8817ec,0x02f7775c,
-    0xeeb82fb8,0x440005ee,0x70bf60ff,0xf90bdddd,0xf3000335,0x001fe41d,
-    0xe80003fd,0xdf11f91f,0x3fa5f823,0x44077ec0,0x4403fa5f,0xffeefcdf,
-    0x3fa5f884,0x21dfff00,0x3fc400fe,0xf519ff50,0x177f447f,0x7c40bf60,
-    0x3ffffe47,0xfc82fb80,0x80007fff,0x90ff13fd,0xf90fffff,0x205bffff,
-    0xd85feee8,0x83fe002f,0x403cccc9,0x3eafb1fe,0x07f4fb03,0x90980bfb,
-    0x7ffc405f,0x2603fea3,0x4cc05f90,0x2200bf20,0x7ffcc07f,0xffe981ff,
-    0x02fd80be,0x3fc40ff1,0x2017e440,0xa80007f8,0x8809f76f,0xdccca87f,
-    0xff982fff,0x3fa0cfff,0xa8ff1002,0x7406ffff,0x0beadd1f,0x361fd3ec,
-    0x17e6005f,0xff07ff10,0x002fcc03,0x7c4017e6,0x7ffec407,0x3ffae03f,
-    0x8817ec3f,0x81fe207f,0x403fffd9,0x2da807f8,0x07fa7fe0,0x6400ff10,
-    0x6fd9807f,0x7c400bf6,0x37d4cc47,0x8bec7fa0,0x7f4dd04f,0x74005fd8,
-    0x83fc400f,0x03fa02fd,0x2001fd00,0x3fa607f8,0x405ffc8c,0x3f65ffda,
-    0x440ff102,0x273fa07f,0x03fc4009,0xfc80fffc,0x7f8806fd,0x007fe200,
-    0x03fc97f4,0x7cc03fe0,0xfc8ff406,0x7c737fd0,0x01bf7fa5,0x33265f70,
-    0xfd837c42,0xd915f702,0x997dc05b,0x0ff102cc,0x3fe617fc,0xb2ffa802,
-    0x81fe205f,0x0bf307f8,0xe807f880,0xfff103ff,0x00ff1007,0xf9002fe8,
-    0xe801bee7,0x80df303f,0x267f51fe,0x47f37ffd,0x002ffafe,0x27ff4bf1,
-    0x17ec1be2,0xecfaafc4,0x3a5f881f,0x0ff104ff,0x2fe417e6,0x7f94fc80,
-    0xf8817ea0,0x8009f707,0xff9807f8,0x401ff603,0x3e2007f8,0x23fd000f,
-    0xf5002ff8,0x40df301f,0x11fa0ff9,0x1fd07ec1,0xfd005ff3,0x113eff21,
-    0x20bf60df,0x17dc20fe,0xfbfc87f4,0x2e0ff104,0x00bf704f,0x827dcff2,
-    0x1fe204fc,0x220037dc,0x03ff007f,0xf8801fec,0x09fb1007,0xff91bee0,
-    0xefe83105,0x20bb7cc0,0x77d46fc8,0x7f43fc80,0x5c03ff50,0x9f39f33f,
-    0x5fb06f88,0xfe883fb8,0xcf99fdc0,0x0ff104f9,0x3fa03fea,0x8ffcc013,
-    0x7fcc1ff9,0x441fe201,0x3e2003ff,0x206fb807,0xf1000ffa,0xfb999b0f,
-    0xb999b0bf,0xfd881fff,0x44feddff,0xecdeffe8,0xffbdfd6f,0x59df703f,
-    0x1fd09fd7,0x7c40ffdc,0x3bfbbf66,0x7ec1be23,0x3e61be22,0xfb37c41e,
-    0xf107dfdd,0x667ff40f,0x3bf66ffc,0x44ffedcd,0xffecdffc,0x703fc404,
-    0x88013bff,0x3bfb207f,0x003ff500,0x7ff43fc4,0xfff02dff,0xea807dff,
-    0x702cefff,0x25bffffd,0x00dfffeb,0x0b7fff66,0x3ff207f4,0xdd90fec0,
-    0x37c47dfd,0x07f62fd8,0x6c357ff5,0x3fbbb21f,0xff99993e,0x7dc43999,
-    0x2e0bffff,0x2dffffff,0x5dfffd70,0x3ff33320,0x7fd41ccc,0x666644ff,
-    0x3e1cccff,0xffff983d,0xfcccc803,0x1331cccf,0x00026600,0x00cc0004,
-    0x00100011,0x1dfb01fd,0x4f980fea,0x2fd837c4,0xfff707f5,0x980fea9f,
-    0x3ffffe4f,0x3103ffff,0x00133001,0xffff8018,0x503fffff,0xffff87b9,
-    0x003fffff,0x20019bd3,0xffffffff,0x0000003f,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x02ae6200,
-    0xdddfd910,0xdd9501dd,0x0f223b9b,0x00014400,0x22179995,0x07ddb34e,
-    0x23deedb8,0x0d4c02a8,0x55440055,0x4c40009a,0x551001ab,0x2aa35555,
-    0xaaaaaaaa,0x5555530a,0x5554c555,0xaaaa8009,0x57510009,0x00aaa001,
-    0xff5013ee,0xf101bfff,0xddffd9bf,0xfeeffd81,0x00df11ff,0x22001fe0,
-    0x12fffffe,0xffdff5bf,0xddffd30b,0x103fe8ff,0x01fe21ff,0xffffffa8,
-    0x7ffd401d,0x7e401eff,0xdf4fffff,0xdddddddd,0x3ffff21f,0x3ff67fff,
-    0xf00dffff,0x07ffffff,0x1fffffe4,0x80bffe20,0xf702fff8,0x1dfd759f,
-    0x27e43fd8,0x3fa06fe4,0x2000df11,0xdfd8007f,0x3fe21312,0x83ff30cf,
-    0x26140dfe,0x23fd80ff,0x3ea007f8,0x3ffecbae,0x9339ff30,0xefef805f,
-    0x021f1aaa,0x559f90f8,0x67ec5555,0x82ffecba,0xffecabff,0xa9adfd83,
-    0x3fea03ff,0x0fffc04f,0x3a20ffc4,0x7c43fc3f,0x6c07fc47,0x000df11f,
-    0x3fe001fe,0x213fe201,0x017f24fb,0x37cc4fd8,0x3bffffe2,0xb85fa81d,
-    0x83fd80ff,0x2fdfd400,0x85dfd0f8,0xb007f90f,0x81ff705f,0x547fc87f,
-    0x206f986f,0x4c07fafd,0x209f902c,0x21fe27fa,0x837dc7f8,0x00df11fd,
-    0x3bffbba6,0xf301eeee,0x307f880d,0x000ff4bf,0x17f43ff1,0x3b733fe2,
-    0x82fd43ff,0x00fe85fc,0x05f9fe80,0xf27dc41f,0x3600ff21,0xf8bfb02f,
-    0x320ff887,0x105fb03f,0x0007faff,0x3fe01ff8,0xbf70bfa1,0x3fb04fc8,
-    0x67ed5be2,0x7ffffcc1,0x302fffff,0x06f880bf,0x007fcdf3,0x2fd57ee0,
-    0x7fd43fc4,0x7cc17ea1,0x98007f87,0x1f05f8cf,0x643e1f50,0x02fd803f,
-    0x887f8ff3,0xb817ec7f,0xf74fa83f,0x03fc0009,0xcffa8bf6,0x7ec0ffda,
-    0x3e23fb02,0x4ffeefce,0xf3001fe0,0x306f880b,0x001fe2df,0x407f57f4,
-    0x49f907f8,0x03fe05fa,0x3f9000ff,0x203e0bf1,0x3f21f1f9,0x202fd803,
-    0x321fe0ff,0xb81fec5f,0xf32fd84f,0x1be6000f,0x6ff47fb0,0xfc80dfff,
-    0x3e23fd03,0x03fea4ff,0x7ffc03fc,0x7fffffff,0x27d41be2,0xf50001fd,
-    0x1fe207ff,0xffeeb7d4,0xa8ffc1ee,0x2aaaaffa,0xeff8b7c0,0x4cc1f1ee,
-    0x3f21f0fd,0x24eeeeee,0x87fe02fd,0xefecbbff,0x64077d40,0x3a3fc45f,
-    0x6f98001f,0x4f99fe40,0x709f7002,0x0ffe23ff,0x03fc07fe,0x67fee664,
-    0x1be24ccc,0x07f71fe4,0x881bf600,0x3ebf707f,0x742fffff,0xffffff1f,
-    0x3ee01fff,0x3dddff13,0x06f7c43e,0x3ffff21f,0x0bf66fff,0x3ffe1fe8,
-    0xfd00bfff,0x9fffb99f,0x27e45fa8,0x0ff30150,0x3df52fd8,0xa83fe200,
-    0x0ff11fff,0x03fc0bf6,0xf1017e60,0x4c6fb88d,0x74040bff,0xeeeffeee,
-    0x7f41fe21,0xff817ea3,0x333ff331,0x887f4033,0x3e21f05f,0x07f90f80,
-    0x7fc05fb0,0x3f267fe1,0x3ffb200e,0x7ec3fccf,0xfe83fcc2,0x203fc40f,
-    0xfffd11fe,0xfb05bfff,0x3fb9fd9f,0x17ec1be2,0x7cc007f8,0x677fc405,
-    0xfc81fffc,0xe87ecdff,0xeeeffeee,0xf931fe21,0x882fd41f,0x003fc0ff,
-    0x82fc4bf3,0x43e03a0f,0x2fd803fc,0x3fc1ff10,0x320013f2,0x267fe22f,
-    0x441ff999,0x1ff82fff,0x7e41ff10,0x4fffeeed,0xfb3effc8,0x7ec1be23,
-    0x9800ff02,0x7ffc405f,0x2e00dfff,0x405ffffe,0x3fe204fb,0x41efffee,
-    0x0df705fa,0x7fe400ff,0x1f05ffff,0x7f90f804,0x2e05fb00,0x3e23fc6f,
-    0x07f4000f,0xfffffff5,0x1dfb09ff,0x3ee09f90,0x7dc17ee5,0x23fb0207,
-    0x05fb06f8,0xf98007fa,0x08b7c405,0x803be200,0x99dfc999,0x77fffc41,
-    0x10bf503d,0x00ff07ff,0x3bbbbfe2,0x3ea1f05f,0x07f90f82,0xff105fb0,
-    0x4fc87f85,0xfb0ff200,0xfb99999b,0xff88060d,0xfb07fd43,0x003fe205,
-    0x06f88fec,0x13f605fb,0x4405f980,0x7f50006f,0xffffff80,0x1fe21fff,
-    0x7545fa80,0x200ff06f,0x82fc43fb,0x1f03d30f,0x3f600ff2,0x7c2ffd42,
-    0x400ff987,0x7fc46fd9,0x0007fe00,0x3fb3bfee,0xc837ec3f,0x47f6005f,
-    0x05fb06f8,0x3733ffe6,0x880bf301,0x3f90006f,0xdfdaaa80,0x1fe20aaa,
-    0xfeeffa80,0x7f6c0dff,0x3eeeeeef,0x9ff103fa,0x2003e599,0xddddf90f,
-    0x777ecddd,0xff05fffe,0xddb13f60,0xfa819fff,0x0027ec05,0x1dfffea8,
-    0xeeefff98,0x36000eff,0x360df11f,0x3ffaa02f,0x0bf301ff,0x30006f88,
-    0x04fb8005,0xfa801fe2,0xf01cefff,0xffffffff,0x2217e69f,0xff5fffff,
-    0xffffffff,0x3ffff21f,0x3ff67fff,0x3e01ceef,0x741ff307,0xfb01cdef,
-    0x006fa807,0xeb880180,0x8002ceee,0x20df11ec,0x013002fd,0x74405f98,
-    0x00000005,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-    0x00000000,0xaaaa8000,0xaaa98099,0x31aaaaaa,0x55555555,0x260aaa00,
-    0x2055100a,0x2aa0d42a,0x0aaaaaaa,0x0aa60551,0x40335555,0x455302a9,
-    0xaaaaaaa9,0x803551aa,0x02aa22a8,0x03530aa8,0x01551a88,0x0154c550,
-    0x2aaaaa55,0x00aaaaaa,0x751002aa,0x80551015,0xfffffff8,0x3ffff20c,
-    0xf95fffff,0x0fffffff,0xfb0fff70,0x7c1be205,0xfff0fe65,0x21ffffff,
-    0x2ff886f8,0x3fffffe2,0x07fec0bf,0xfff737fc,0x2bffffff,0x2fe406fb,
-    0x7fd413fa,0xf9807f50,0xfa809fb4,0x220fff26,0xffffff6f,0x501fffff,
-    0x36203ffd,0x4c3fffff,0x57fc406f,0x2a5ffcba,0xdccccccc,0x555bf95f,
-    0xff880555,0x102fd87f,0xfa93e0df,0x6fed5542,0x0df10aaa,0xaff887fd,
-    0x6c5ffeba,0x3ffd43ff,0x99999993,0x81ffc9ff,0x7fcc0ff8,0xf517f441,
-    0xf53f9809,0x323fc80f,0x56f886ff,0x55bfb555,0x7ff4c155,0x7bfd01ff,
-    0x7cc3ff95,0x443fc406,0x3fd000ff,0x6c000ff2,0x2fd87fbf,0x9f10df10,
-    0x9f700fdc,0x9fb1be20,0xff10ff10,0x3637f747,0xdf7007ee,0xfd80ffa8,
-    0xfc8bf904,0x2a027cc5,0xf807fe3f,0x0bfbf21f,0x13ee0df1,0xff9dff98,
-    0xbf905501,0x3e2037cc,0x3003fd07,0x001fe4df,0x43fc67d4,0x4df102fd,
-    0xdaadfbaa,0x4fb81abf,0x2fdcdf10,0xbf907f88,0xf887e774,0xff8807dc,
-    0x7cc4fe81,0x25ff100f,0x2fcc0ff9,0x4fd8bea0,0xbfc8df30,0xb837c46f,
-    0xff0e404f,0x26f98003,0x3fc406f9,0x5fb007f8,0x22001fe4,0xd87f88ff,
-    0x74df102f,0xffffffff,0x04fb85ff,0x03be6df1,0x6fa83fc4,0x7dcfe7ba,
-    0x7ec00fd9,0x6c1ff304,0x47fd403f,0x45f883fe,0xfa8bee09,0xfc87f906,
-    0x1be22fda,0x3e0027dc,0x37cc001f,0x7f880df3,0xf9804fc8,0x2001fe46,
-    0xb0ff12fd,0x21be205f,0x701f61fb,0x23be209f,0x1fe201ff,0x3adf2fec,
-    0x803f6dd6,0xa7ec06fa,0xdfb006f9,0xa9be20df,0xff07ee3f,0xfc81fd03,
-    0x1be26faa,0x3e0027dc,0x2fdc001f,0xff880df3,0x002ffeee,0xcefc85fb,
-    0xfa82cccc,0x3f61fe25,0xfeeeeeee,0x1ba0fc86,0x3e209f70,0x7c402fef,
-    0x3e2ff887,0x367f5f95,0x03ff100f,0x2fd8ff88,0x03fff100,0x64df937c,
-    0x2627ec1f,0xfd2fc86f,0x7dc1be23,0x00ffc004,0x7cc5fd10,0x7fffc406,
-    0x4c02efff,0xffffc86f,0x0fe85fff,0x3ff61fe2,0x6fffffff,0x202fc7c8,
-    0xfff104fb,0x9ff8805f,0x7c5ffdb9,0x321fff35,0x009fb01f,0x001bfbf2,
-    0x37c01ffd,0x03f23fff,0x83fc8df5,0x22bf52fc,0x009f706f,0x36001ff8,
-    0x2037cc5f,0x7fe447f8,0x320bf601,0x099999cf,0x1fe217e4,0x37c40bf6,
-    0x7013e3ec,0x2bbe209f,0x3fe200ff,0x443fffff,0xfc97fa5f,0x2006fa81,
-    0x2001fff8,0x3a05fffb,0x329f9f57,0x3a1ff80f,0x3e2fc80f,0xf706f89f,
-    0x01ff8009,0xf981df90,0xc83fc406,0x20df305f,0xef9803fc,0x9ff99999,
-    0x2205fb09,0xdffdd56f,0x20ddffdd,0x2df104fb,0xff100efb,0xf1013599,
-    0x3f917dcb,0x4001ff88,0x3e6005fb,0xfd02ff9f,0x3edbe3f2,0x0df33fd8,
-    0x8cfb8bf2,0x009f706f,0xfc801ff8,0x406f980e,0x0df507f8,0x1fe40ff6,
-    0x7ffffdc0,0xb4ffffff,0x4dbe205f,0xfdccefcc,0x09f704cd,0x05fd9be2,
-    0x3e600ff1,0x3617e405,0x4fb8004f,0x7dcffa00,0x5f8fd80f,0x2a0fb3f9,
-    0x3207f76f,0x3e7fe22f,0x8009f706,0x77e401ff,0x880df300,0x309fb07f,
-    0x01fe40ff,0x6666664c,0xfb2ccffc,0xf11be205,0x2e017d49,0x44df104f,
-    0x07f883ff,0xfb809f30,0x0003bea2,0x7dc013ee,0x7e427f46,0xdd9f32fb,
-    0x07f47fc0,0x67e42fc8,0x009f706f,0x3f201ff8,0x01be600e,0xffa88ff1,
-    0x3203fd82,0x7c40003f,0xf102fd87,0x3ee4f88d,0x8827dc01,0x20ffcc6f,
-    0x9f3007f8,0xff13fb80,0x13ee0003,0xf30bfe20,0x47efc83f,0x3f606eff,
-    0x0bf206fc,0x2e0dfff1,0x0ffc004f,0x4c00efc8,0x77fc406f,0x983fffee,
-    0x0ff200ff,0xb0ff1000,0x31be205f,0x6c07e47f,0xeeeffeee,0xff70df10,
-    0xa803fc41,0xc9fdc04f,0xffffffff,0x013ee06f,0x37e417f6,0xff917fee,
-    0x1fffd40b,0xff905f90,0xb013ee0d,0xdddffddd,0x3ffffe67,0xff36ffff,
-    0x15dddddd,0x19dfffff,0xf900ff60,0x7f880007,0xdf102fd8,0x03f22fa8,
-    0x3ffffffe,0x20df10ff,0x01fe26fd,0x3ee027d4,0xffffffb3,0x7dc0dfff,
-    0x807fdc04,0x3fee4ff8,0x202ffcc2,0x3f200fff,0x706ff882,0xffff809f,
-    0xf34fffff,0xffffffff,0x3ffffe6d,0x00003fff,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x80322000,
-    0x8026200b,0x6c40001c,0xdb880000,0x2e01defe,0xe881cefd,0x6d43d905,
-    0xdfd98cef,0x00054400,0x207bddb7,0x700cefdb,0xc83ddfdb,0x21bd505e,
-    0xd52ed8bd,0xeeeed81b,0xaa986eee,0x2017540a,0x2e1d74e9,0x77441dfd,
-    0x6c03b600,0x40df504f,0x7ff304fa,0x0ffe6000,0x7dc04fa8,0x42fffeef,
-    0xfffeffe9,0xfd837c43,0x3bff7be2,0x7406fdef,0xffe9807f,0xefd87fee,
-    0x7f42ffed,0x442feeef,0x17fc43ff,0xf3ffdb9f,0xfffe8bfd,0x7dc7ffff,
-    0x3ea1ffff,0xfca7d404,0x1fffefc9,0x6fa81fec,0x32ebfe20,0x2a01ff9b,
-    0x13fe604f,0x805ff700,0x20cc04fa,0x27f47fb8,0x6f887fea,0x36145fb0,
-    0x405f90ff,0xdfe807fe,0x513f2140,0x417ee1ff,0x361ff980,0x5c77fc4f,
-    0x200fd4ef,0xf70cc3fe,0x2e02fccb,0x45fdf93f,0x837d45fc,0x7fd403fd,
-    0x403fffff,0x7f4404fa,0x1efc800d,0x0004fa80,0x82fd43fe,0x41be25fc,
-    0x97ee02fd,0x072204fa,0xf100bf90,0x7e4ff20d,0xab7e4003,0xf52ff86f,
-    0x32007ecf,0x37cc405f,0x9174cdf1,0x307ff23f,0x883ff0df,0x7fc400ff,
-    0x402ffc9c,0xdfb004fa,0x03bf6201,0x00027d40,0x40bf23fb,0x41be26f8,
-    0x8fea02fd,0xe80004f9,0x04fa801f,0x0bfee9f5,0x1ff9fd00,0xb27d4ff0,
-    0x077d401f,0x37fff644,0x365fc9fe,0xd107f90f,0xfb89f90b,0x645fb804,
-    0x7777645f,0x205eeeff,0x7f441ffb,0x5ccccc04,0x981999df,0x1ffffeec,
-    0x13fc03fd,0x88bf60df,0xeeefeedb,0x266665fe,0x41999999,0xefb800ff,
-    0x5feeeeee,0x0077fff6,0x7c0bffe2,0x0fd8fea7,0x3203ff30,0x746f99af,
-    0x3f43ffa7,0xf88005f9,0x6c00ff47,0x363fcc2f,0xffffffff,0x8ffdc07f,
-    0xff805ff8,0xffffffff,0x33bfee1f,0x3fd1ffcc,0x0df13fc0,0xcffe8bf6,
-    0x2ccccefd,0x3ffffffe,0xff11ffff,0x3bbbf200,0x4c4eeeee,0x200efffd,
-    0xff00ffe8,0x01fb1fd4,0x37c05fd1,0x98fd8df5,0x64df3fcf,0x2fd8002f,
-    0x3f600df3,0x2a03fc42,0x3fe6004f,0x201ffd43,0xcefdcccc,0x3ff10ccc,
-    0x0bf63fb0,0x0df137c4,0x52fd4bf6,0xcccc809f,0x0ccccccc,0x3ee003fe,
-    0xfd510005,0x77f7ec0d,0x8fea7f80,0x04fd80fd,0x37ff6fec,0x3e3f27ee,
-    0x017e4bf6,0x3fcafd40,0xf989fb00,0x8027d406,0xfd302ffb,0x027d4009,
-    0x47fa0bf5,0x8bf704fc,0x97fc40ff,0x01bea2fc,0x01ff4000,0x00007fd4,
-    0xdf701ff1,0xa9fe17f6,0xf703f63f,0x17b7100d,0x5ebfa877,0x7e49f5f9,
-    0xd1ff0002,0x3bea001f,0xf500ff60,0x03df9009,0x800dfe88,0x1bea04fa,
-    0x3e23ffb1,0x20ffcc1f,0x3ffa22ff,0x3fa27f72,0x0054001f,0x8102ffea,
-    0x30000cfe,0x23ff30ff,0x53fc3ff8,0xf307ec7f,0x4c00001f,0xfbf32fdf,
-    0x80017e47,0x2005fdfc,0xfffdfff8,0x1027d401,0x6c001dfb,0x27d400ef,
-    0xfb9dff10,0x7fdc3fdf,0xb83ffdcd,0xfdefcdff,0x7dd9df12,0x403b99ff,
-    0xffd806fd,0x7cc7ecdf,0x0eccbdff,0xffb999dd,0x4c3ff889,0xfa9fe1ff,
-    0xfff83f63,0x32eeeeee,0x7ddddddd,0xff07ffc4,0x0017e45f,0x002fff98,
-    0x37ffbbf6,0x8164c06f,0x70005fe8,0x27d403ff,0x37fffa60,0x7f541fc8,
-    0x3aa01eff,0x22fb8dff,0xff90efeb,0x3ff403ff,0xffffea80,0xffffd885,
-    0xffffb0ef,0x0bfb05df,0x53fc3ff2,0xff07ec7f,0x5fffffff,0x3bbbbba6,
-    0x322ffc3e,0x00bf20ff,0x2006fe80,0x09fb06fb,0x001f4400,0x98807ea0,
-    0x00011000,0x00088003,0x26002601,0x0088002c,0x4cc01310,0x00000009,
-    0x00000000,0x00000000,0x4407ee00,0x3333264f,0x002ccccc,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x40000000,
-    0x3fee0400,0x4fffffff,0x74400000,0x4039fb54,0x64400aa9,0xb9800001,
-    0x000001bc,0x03372a00,0x4017bb93,0x16dc04c9,0x200e65c4,0x333100a8,
-    0x81333333,0x4cc40bb9,0x09999999,0x26057700,0x257714c2,0x00000bb9,
-    0x40000000,0xfeefcdf8,0x7fff444f,0x80be202f,0xc81d705c,0x40dfdcdf,
-    0x3203645c,0xfd83320d,0x3f21ffff,0x6cc0ffff,0x3fe207ff,0x3fffea0f,
-    0x41bf604f,0xfffffffa,0x0efb84ff,0x3ffffff2,0xfd802fff,0x11ff880d,
-    0x54ffa3ff,0x000000ff,0x44000000,0x3fea3fff,0x3ee6ff60,0x8fc46a0f,
-    0x717fa238,0x557641df,0x7ec5d88a,0x7d40ff23,0x1731be65,0x32049fb1,
-    0x3f7fe23f,0x897ffc07,0x05fd10ff,0x5107fbf5,0x55555555,0x543be603,
-    0xebbbbbbb,0x01fec02f,0xd1fe83fa,0x001fe67f,0x00000000,0x3e0ffe20,
-    0xfc8bf31f,0x5cfd3fa3,0x57fa20ff,0x27e60efb,0x3f8afcfa,0x0fe83fa2,
-    0x07fa0fe8,0x7ec0bf70,0x03fc45c2,0x1fd4bfea,0x75ba13ea,0x8800000f,
-    0x05f90009,0x808004c4,0x3fccbf60,0x00000000,0x83fc4000,0xa87f52fd,
-    0x77f7544f,0xefe880bf,0x6ab5c0ef,0xbf317299,0x8ff22fcc,0x7f4403fc,
-    0x027ff542,0xff880ff1,0x4f987f70,0x44f98fdc,0x99999998,0x20000099,
-    0x000002fc,0x37c4bf60,0x00000000,0x837c4000,0xb8bf32fd,0x1ffe883f,
-    0x407ff440,0x21ddf54d,0x362fc86b,0x7ccdf12f,0x42ff4406,0x103ffdc9,
-    0x25fc80ff,0x117e45f9,0x2a1fd8bf,0xffffffff,0x3200004f,0x0000002f,
-    0x037c47f2,0x00000000,0xd837c400,0x223ff12f,0x37f220fe,0xf701dfdf,
-    0x2ab90bff,0x88b90fae,0xd8df10ff,0x5407f62f,0x7f9804ff,0xd910ff10,
-    0xbdfe81df,0x207e46fd,0x2eee66f8,0x02bbbbbb,0x00000000,0x00000000,
-    0x00000000,0x17ec1be2,0x87ffdff7,0xfd33f2fe,0xfe8efb81,0xdb547d45,
-    0x22fd89d4,0x137c42fd,0xbffb81df,0xff700999,0x3a61fe20,0xfffb102d,
-    0xb827cc19,0x6d40003f,0x2ca8103d,0xffb80dcc,0x55534fff,0x00000555,
-    0x00000000,0x7ec1be20,0x40e6e4c2,0x20c3f109,0xbfd10efb,0x99339dd8,
-    0xf527dc1f,0xfb93ee0b,0x3ffffe25,0xffddb2ff,0xffffe85f,0x010001ff,
-    0x00130062,0x2ffffdc0,0x7ffccbee,0x503fff11,0x3a799999,0x007fffff,
-    0x00000000,0x0df10000,0x10000bf6,0x2077405f,0x3ba20fe8,0x741fda9b,
-    0xfd007f46,0x999076c1,0x3ae39999,0xccb80bde,0x0000cccc,0x80000000,
-    0x8dfd89fe,0xfff50fd8,0x00fffe65,0x333332e0,0x00000004,0x10000000,
-    0x4cbf60df,0x3eeeeeee,0x04401510,0xdfb70088,0x00202019,0x00000101,
-    0x00000000,0x7c400000,0x2ffffec5,0x1ffd1bfa,0x00000000,0x00000000,
-    0x20df1000,0xdddd32fd,0x00007ddd,0x00000000,0x00000000,0x00000000,
-    0x06a00000,0x80413bae,0x00000009,0x00000000,0x00000000,0x00000000,
-    0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
-};
-
-static signed short stb__consolas_24_latin1_x[224]={ 0,5,3,0,1,0,0,5,3,3,1,0,2,3,
-4,1,1,1,1,1,0,2,1,1,1,1,4,2,1,1,2,3,0,0,1,1,1,2,2,0,1,2,2,1,
-2,0,1,0,1,0,1,1,1,1,0,0,0,0,1,4,1,3,1,0,0,1,1,1,1,1,0,1,1,2,
-1,2,2,1,1,1,1,1,2,2,0,1,0,0,0,0,1,1,5,2,0,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,5,1,1,1,0,
-5,1,0,0,2,1,1,3,1,0,2,1,2,3,0,1,1,4,5,2,2,1,0,0,0,2,0,0,0,0,
-0,0,-1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,
-0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
- };
-static signed short stb__consolas_24_latin1_y[224]={ 17,0,0,1,-1,0,0,0,-1,-1,0,4,13,9,
-13,0,1,1,1,1,1,1,1,1,1,1,5,5,4,7,4,0,0,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,20,0,5,0,5,0,5,0,5,0,0,
-0,0,0,5,5,5,5,5,5,5,1,5,5,5,5,5,5,0,-3,0,8,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,17,5,-1,1,2,1,
--3,0,0,1,1,5,9,9,0,1,0,2,0,0,0,5,0,8,17,0,1,5,0,0,0,5,-3,-3,-3,-3,
--3,-4,1,1,-3,-3,-3,-3,-3,-3,-3,-3,1,-3,-3,-3,-3,-3,-3,5,-1,-3,-3,-3,-3,-3,1,0,0,0,
-0,0,0,-1,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,2,0,0,0,0,0,0,0,
- };
-static unsigned short stb__consolas_24_latin1_w[224]={ 0,4,8,13,11,13,14,3,8,7,11,13,7,8,
-5,11,12,11,11,11,13,10,11,11,11,11,5,7,10,11,10,8,14,14,11,11,12,10,10,12,11,10,9,12,
-10,13,11,13,11,14,12,11,12,11,14,13,13,14,11,6,11,7,11,14,8,11,11,11,11,11,13,12,11,10,
-10,11,10,12,11,12,11,11,11,10,12,11,13,13,13,13,11,10,3,10,13,12,12,12,12,12,12,12,12,12,
-12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,4,10,11,12,13,
-3,11,11,14,9,11,11,8,11,10,9,11,9,8,12,12,11,5,3,9,9,11,13,13,13,8,14,14,14,14,
-14,14,14,11,12,12,12,12,12,12,12,12,13,12,13,13,13,13,13,11,13,12,12,12,12,14,11,11,12,12,
-12,12,12,12,13,11,12,12,12,12,12,12,12,12,11,12,13,13,13,13,13,13,12,12,12,12,12,13,11,13,
- };
-static unsigned short stb__consolas_24_latin1_h[224]={ 0,18,6,16,21,18,18,6,23,23,11,13,9,3,
-5,20,17,16,16,17,16,17,17,16,17,16,13,17,14,7,14,18,22,16,16,17,16,16,16,17,16,16,17,16,
-16,16,16,17,16,21,16,17,16,17,16,16,16,16,16,22,20,22,9,2,6,13,18,13,18,13,17,17,17,17,
-22,17,17,12,12,13,17,17,12,13,17,13,12,12,12,17,12,22,25,22,5,16,16,16,16,16,16,16,16,16,
-16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,17,21,16,15,16,
-25,20,6,17,12,11,6,3,11,5,9,15,10,10,6,17,20,5,4,10,12,11,17,17,17,17,20,20,20,20,
-20,21,16,20,20,20,20,20,20,20,20,20,16,20,21,21,21,21,21,11,21,21,21,21,21,20,16,18,18,18,
-18,18,18,19,13,16,18,18,18,18,17,17,17,17,18,17,18,18,18,18,18,13,18,18,18,18,18,22,22,22,
- };
-static unsigned short stb__consolas_24_latin1_s[224]={ 252,250,247,62,40,106,104,252,17,9,70,
-48,159,238,215,91,183,221,233,12,36,1,222,13,152,220,247,223,37,189,26,
-40,100,232,1,24,194,183,25,36,50,76,49,87,245,112,196,1,100,129,207,
-164,208,176,181,167,153,138,126,34,146,26,177,26,201,62,119,127,171,139,65,
-15,40,245,89,74,141,176,48,74,79,28,225,151,52,87,237,211,162,231,189,
-41,1,64,201,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
-170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,252,247,157,
-143,1,103,5,186,235,59,201,118,210,238,94,227,167,14,130,140,222,196,79,
-221,252,149,60,106,86,113,127,201,198,213,66,118,103,52,155,67,133,173,14,
-27,241,1,40,53,129,228,168,182,196,210,224,82,238,1,14,27,144,158,117,
-94,172,185,198,211,131,81,99,91,133,159,146,120,234,209,210,188,224,100,236,
-49,157,90,63,113,144,27,1,77,14,75,52,115, };
-static unsigned short stb__consolas_24_latin1_t[224]={ 13,49,156,125,27,49,70,1,1,1,156,
-142,156,163,163,27,70,125,125,89,125,89,70,125,89,107,107,89,142,156,142,
-70,1,107,125,89,107,107,125,89,125,125,89,125,125,125,125,107,125,1,107,
-89,125,89,125,125,125,125,125,1,27,1,156,24,156,142,70,142,70,142,107,
-107,107,89,1,89,89,142,156,142,107,107,142,142,107,142,142,142,142,89,142,
-1,1,1,163,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
-107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,13,70,1,
-107,142,107,1,27,156,89,142,156,156,163,156,163,156,142,156,156,156,70,27,
-163,8,156,156,156,89,89,89,89,27,27,49,27,27,27,107,27,27,27,49,
-49,27,49,49,49,107,27,1,1,1,1,1,156,1,27,27,27,1,27,107,
-49,49,49,49,49,70,49,142,107,49,49,49,49,70,70,89,89,49,89,49,
-70,70,70,70,142,70,70,70,70,70,1,1,1, };
-static unsigned short stb__consolas_24_latin1_a[224]={ 211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
-211,211,211,211,211,211,211,211, };
-
-// Call this function with
-//    font: NULL or array length
-//    data: NULL or specified size
-//    height: STB_FONT_consolas_24_latin1_BITMAP_HEIGHT or STB_FONT_consolas_24_latin1_BITMAP_HEIGHT_POW2
-//    return value: spacing between lines
-static void stb_font_consolas_24_latin1(stb_fontchar font[STB_FONT_consolas_24_latin1_NUM_CHARS],
-                unsigned char data[STB_FONT_consolas_24_latin1_BITMAP_HEIGHT][STB_FONT_consolas_24_latin1_BITMAP_WIDTH],
-                int height)
-{
-    int i,j;
-    if (data != 0) {
-        unsigned int *bits = stb__consolas_24_latin1_pixels;
-        unsigned int bitpack = *bits++, numbits = 32;
-        for (i=0; i < STB_FONT_consolas_24_latin1_BITMAP_WIDTH*height; ++i)
-            data[0][i] = 0;  // zero entire bitmap
-        for (j=1; j < STB_FONT_consolas_24_latin1_BITMAP_HEIGHT-1; ++j) {
-            for (i=1; i < STB_FONT_consolas_24_latin1_BITMAP_WIDTH-1; ++i) {
-                unsigned int value;
-                if (numbits==0) bitpack = *bits++, numbits=32;
-                value = bitpack & 1;
-                bitpack >>= 1, --numbits;
-                if (value) {
-                    if (numbits < 3) bitpack = *bits++, numbits = 32;
-                    data[j][i] = (bitpack & 7) * 0x20 + 0x1f;
-                    bitpack >>= 3, numbits -= 3;
-                } else {
-                    data[j][i] = 0;
-                }
-            }
-        }
-    }
-
-    // build font description
-    if (font != 0) {
-        float recip_width = 1.0f / STB_FONT_consolas_24_latin1_BITMAP_WIDTH;
-        float recip_height = 1.0f / height;
-        for (i=0; i < STB_FONT_consolas_24_latin1_NUM_CHARS; ++i) {
-            // pad characters so they bilerp from empty space around each character
-            font[i].s0 = (stb__consolas_24_latin1_s[i]) * recip_width;
-            font[i].t0 = (stb__consolas_24_latin1_t[i]) * recip_height;
-            font[i].s1 = (stb__consolas_24_latin1_s[i] + stb__consolas_24_latin1_w[i]) * recip_width;
-            font[i].t1 = (stb__consolas_24_latin1_t[i] + stb__consolas_24_latin1_h[i]) * recip_height;
-            font[i].x0 = stb__consolas_24_latin1_x[i];
-            font[i].y0 = stb__consolas_24_latin1_y[i];
-            font[i].x1 = stb__consolas_24_latin1_x[i] + stb__consolas_24_latin1_w[i];
-            font[i].y1 = stb__consolas_24_latin1_y[i] + stb__consolas_24_latin1_h[i];
-            font[i].advance_int = (stb__consolas_24_latin1_a[i]+8)>>4;
-            font[i].s0f = (stb__consolas_24_latin1_s[i] - 0.5f) * recip_width;
-            font[i].t0f = (stb__consolas_24_latin1_t[i] - 0.5f) * recip_height;
-            font[i].s1f = (stb__consolas_24_latin1_s[i] + stb__consolas_24_latin1_w[i] + 0.5f) * recip_width;
-            font[i].t1f = (stb__consolas_24_latin1_t[i] + stb__consolas_24_latin1_h[i] + 0.5f) * recip_height;
-            font[i].x0f = stb__consolas_24_latin1_x[i] - 0.5f;
-            font[i].y0f = stb__consolas_24_latin1_y[i] - 0.5f;
-            font[i].x1f = stb__consolas_24_latin1_x[i] + stb__consolas_24_latin1_w[i] + 0.5f;
-            font[i].y1f = stb__consolas_24_latin1_y[i] + stb__consolas_24_latin1_h[i] + 0.5f;
-            font[i].advance = stb__consolas_24_latin1_a[i]/16.0f;
-        }
-    }
-}
-
-#ifndef STB_SOMEFONT_CREATE
-#define STB_SOMEFONT_CREATE              stb_font_consolas_24_latin1
-#define STB_SOMEFONT_BITMAP_WIDTH        STB_FONT_consolas_24_latin1_BITMAP_WIDTH
-#define STB_SOMEFONT_BITMAP_HEIGHT       STB_FONT_consolas_24_latin1_BITMAP_HEIGHT
-#define STB_SOMEFONT_BITMAP_HEIGHT_POW2  STB_FONT_consolas_24_latin1_BITMAP_HEIGHT_POW2
-#define STB_SOMEFONT_FIRST_CHAR          STB_FONT_consolas_24_latin1_FIRST_CHAR
-#define STB_SOMEFONT_NUM_CHARS           STB_FONT_consolas_24_latin1_NUM_CHARS
-#define STB_SOMEFONT_LINE_SPACING        STB_FONT_consolas_24_latin1_LINE_SPACING
-#endif
-

From 53f358d77a746d651791a131ca78a8b7813894bc Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Thu, 29 Sep 2016 13:27:04 -0700
Subject: [PATCH 09/28] Fix warnings

---
 libraries/gl/src/gl/GLShaders.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp
index b8e1bf7391..3487ae5d25 100644
--- a/libraries/gl/src/gl/GLShaders.cpp
+++ b/libraries/gl/src/gl/GLShaders.cpp
@@ -75,8 +75,8 @@ namespace gl {
         return false;
     }
 
-    GLuint glprogram = 0;
 #ifdef SEPARATE_PROGRAM
+    GLuint glprogram = 0;
     // so far so good, program is almost done, need to link:
     GLuint glprogram = glCreateProgram();
     if (!glprogram) {

From 9bc0f2477702da1d2ba5dbee6dcfac58bf5f9fd6 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Sun, 2 Oct 2016 12:22:00 -0700
Subject: [PATCH 10/28] Fix GLEW linker warnings

---
 cmake/macros/TargetOpenGL.cmake | 1 +
 1 file changed, 1 insertion(+)

diff --git a/cmake/macros/TargetOpenGL.cmake b/cmake/macros/TargetOpenGL.cmake
index 7b3178d579..73c92e651a 100644
--- a/cmake/macros/TargetOpenGL.cmake
+++ b/cmake/macros/TargetOpenGL.cmake
@@ -6,6 +6,7 @@
 #  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 # 
 macro(TARGET_OPENGL)
+    add_definitions(-DGLEW_STATIC) 
     if (APPLE)
       # link in required OS X frameworks and include the right GL headers
       find_library(OpenGL OpenGL)

From ce8fcfed36aa0e6237d9a3ba6f4b31d3d75d1116 Mon Sep 17 00:00:00 2001
From: Bradley Austin Davis <bdavis@saintandreas.org>
Date: Sun, 2 Oct 2016 17:42:10 -0700
Subject: [PATCH 11/28] Fix mac build (again?)

---
 plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 2feb272fbe..b7b6ae5768 100644
--- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -28,6 +28,8 @@
 
 #include <ui-plugins/PluginContainer.h>
 
+#include "OculusHelpers.h"
+
 const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
 
 OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() {

From c683c82817b402bfb8c0836538b075c6f9102085 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 8 Sep 2016 14:55:51 -0700
Subject: [PATCH 12/28] Fix setting textures in model overlays

---
 interface/src/ui/overlays/ModelOverlay.cpp | 24 ++++++++++++----------
 libraries/render-utils/src/Model.h         |  2 +-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 0a89268f6b..74719aeeb6 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -123,17 +123,19 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
     auto texturesValue = properties["textures"];
     if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) {
         QVariantMap textureMap = texturesValue.toMap();
-        foreach(const QString& key, textureMap.keys()) {
-
-            QUrl newTextureURL = textureMap[key].toUrl();
-            qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL;
-
-            QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection,
-                                      Q_ARG(const QString&, key),
-                                      Q_ARG(const QUrl&, newTextureURL));
-
-            _modelTextures[key] = newTextureURL;  // Keep local track of textures for getProperty()
-        }
+        QMetaObject::invokeMethod(_model.get(), "setTextures", Qt::AutoConnection,
+                                    Q_ARG(const QVariantMap&, textureMap));
+//        foreach(const QString& key, textureMap.keys()) {
+//
+//            QUrl newTextureURL = textureMap[key].toUrl();
+//            qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL;
+//
+//            QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection,
+//                                      Q_ARG(const QString&, key),
+//                                      Q_ARG(const QUrl&, newTextureURL));
+//
+//            _modelTextures[key] = newTextureURL;  // Keep local track of textures for getProperty()
+//        }
     }
 }
 
diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h
index bd94fb706b..0ab028f8eb 100644
--- a/libraries/render-utils/src/Model.h
+++ b/libraries/render-utils/src/Model.h
@@ -131,7 +131,7 @@ public:
     const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
 
     const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
-    void setTextures(const QVariantMap& textures);
+    Q_INVOKABLE void setTextures(const QVariantMap& textures);
 
     /// Provided as a convenience, will crash if !isLoaded()
     // And so that getGeometry() isn't chained everywhere

From 93d995a5ae5bff53b087b32cfcb5d293329eed24 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Thu, 8 Sep 2016 15:59:17 -0700
Subject: [PATCH 13/28] Fix model overlay visible not working

---
 interface/src/ui/overlays/ModelOverlay.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 74719aeeb6..e299070dca 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -79,11 +79,10 @@ void ModelOverlay::render(RenderArgs* args) {
         _model->removeFromScene(scene, pendingChanges);
         _model->addToScene(scene, pendingChanges);
     }
-    scene->enqueuePendingChanges(pendingChanges);
 
-    if (!_visible) {
-        return;
-    }
+    _model->setVisibleInScene(_visible, scene);
+
+    scene->enqueuePendingChanges(pendingChanges);
 }
 
 void ModelOverlay::setProperties(const QVariantMap& properties) {

From 847a5cc7a1a494708dffcab640e992ed19a7b44f Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 20 Sep 2016 12:55:15 -0700
Subject: [PATCH 14/28] Remove old texture setting code in ModelOverlay

---
 interface/src/ui/overlays/ModelOverlay.cpp | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index e299070dca..694a1e1ddc 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -123,18 +123,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
     if (texturesValue.isValid() && texturesValue.canConvert(QVariant::Map)) {
         QVariantMap textureMap = texturesValue.toMap();
         QMetaObject::invokeMethod(_model.get(), "setTextures", Qt::AutoConnection,
-                                    Q_ARG(const QVariantMap&, textureMap));
-//        foreach(const QString& key, textureMap.keys()) {
-//
-//            QUrl newTextureURL = textureMap[key].toUrl();
-//            qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL;
-//
-//            QMetaObject::invokeMethod(_model.get(), "setTextureWithNameToURL", Qt::AutoConnection,
-//                                      Q_ARG(const QString&, key),
-//                                      Q_ARG(const QUrl&, newTextureURL));
-//
-//            _modelTextures[key] = newTextureURL;  // Keep local track of textures for getProperty()
-//        }
+                                  Q_ARG(const QVariantMap&, textureMap));
     }
 }
 

From 392ecb0dae3e0f2c7a7bead747e85297af364cc6 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Fri, 23 Sep 2016 16:41:44 -0700
Subject: [PATCH 15/28] Update interface to launch server

---
 interface/src/main.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 527b7f2331..3fc09636ed 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -29,6 +29,7 @@
 #include "InterfaceLogging.h"
 #include "UserActivityLogger.h"
 #include "MainWindow.h"
+#include <QtCore/QProcess>
 
 #ifdef HAS_BUGSPLAT
 #include <BuildInfo.h>
@@ -121,6 +122,27 @@ int main(int argc, const char* argv[]) {
         }
     }
 
+    QCommandLineParser parser;
+    QCommandLineOption runServer("runServer", "Whether to run the server");
+    QCommandLineOption serverContentPath("serverContentPath", "Where to find server content", "serverContentPath");
+    parser.addOption(runServer);
+    parser.addOption(serverContentPath);
+    parser.parse(arguments);
+    if (parser.isSet(runServer)) {
+        QString serverPath = QFileInfo(arguments[0]).path();
+        serverPath += "/server-console/server-console.exe";
+        //serverPath = "./server-console/server-console.exe";
+        QStringList args;
+        if (parser.isSet(serverContentPath)) {
+            args << "--" << "--contentPath" << parser.value(serverContentPath);
+        }
+        qDebug() << "server path: " << serverPath << args;
+        qDebug() << QFileInfo(arguments[0]).path();
+        qDebug() << QProcess::startDetached(serverPath, args);
+
+        usleep(2000000);
+    }
+
     QElapsedTimer startupTime;
     startupTime.start();
 

From fe6382d1b66ce3cb72c27e11c4790d9c0903264c Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Fri, 23 Sep 2016 17:41:26 -0700
Subject: [PATCH 16/28] Update server content path to be relative

---
 interface/src/main.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 3fc09636ed..7980d3de0f 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -134,7 +134,8 @@ int main(int argc, const char* argv[]) {
         //serverPath = "./server-console/server-console.exe";
         QStringList args;
         if (parser.isSet(serverContentPath)) {
-            args << "--" << "--contentPath" << parser.value(serverContentPath);
+            QString serverContentPath = QFileInfo(arguments[0]).path() + "/" + parser.value(serverContentPath);
+            args << "--" << "--contentPath" << serverContentPath;
         }
         qDebug() << "server path: " << serverPath << args;
         qDebug() << QFileInfo(arguments[0]).path();

From 0aba1d3e54da35192a94eb51bf18ea1b7054726d Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 26 Sep 2016 09:07:45 -0700
Subject: [PATCH 17/28] Fix server arguments causing crash on startup

---
 interface/src/main.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 7980d3de0f..8dd4414c6b 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -123,18 +123,18 @@ int main(int argc, const char* argv[]) {
     }
 
     QCommandLineParser parser;
-    QCommandLineOption runServer("runServer", "Whether to run the server");
-    QCommandLineOption serverContentPath("serverContentPath", "Where to find server content", "serverContentPath");
-    parser.addOption(runServer);
-    parser.addOption(serverContentPath);
+    QCommandLineOption runServerOption("runServer", "Whether to run the server");
+    QCommandLineOption serverContentPathOption("serverContentPath", "Where to find server content", "serverContentPath");
+    parser.addOption(runServerOption);
+    parser.addOption(serverContentPathOption);
     parser.parse(arguments);
-    if (parser.isSet(runServer)) {
+    if (parser.isSet(runServerOption)) {
         QString serverPath = QFileInfo(arguments[0]).path();
         serverPath += "/server-console/server-console.exe";
         //serverPath = "./server-console/server-console.exe";
         QStringList args;
-        if (parser.isSet(serverContentPath)) {
-            QString serverContentPath = QFileInfo(arguments[0]).path() + "/" + parser.value(serverContentPath);
+        if (parser.isSet(serverContentPathOption)) {
+            QString serverContentPath = QFileInfo(arguments[0]).path() + "/" + parser.value(serverContentPathOption);
             args << "--" << "--contentPath" << serverContentPath;
         }
         qDebug() << "server path: " << serverPath << args;

From 224c35d568caa23ffc1844c7fb66ee74ca2f0f6c Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 3 Oct 2016 09:30:25 -0700
Subject: [PATCH 18/28] Clean up launch server in main.cpp

---
 interface/src/main.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 8dd4414c6b..c2bc10eefc 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -129,18 +129,20 @@ int main(int argc, const char* argv[]) {
     parser.addOption(serverContentPathOption);
     parser.parse(arguments);
     if (parser.isSet(runServerOption)) {
-        QString serverPath = QFileInfo(arguments[0]).path();
-        serverPath += "/server-console/server-console.exe";
-        //serverPath = "./server-console/server-console.exe";
+        //QString serverPath = QFileInfo(arguments[0]).path();
+        QString applicationDirPath = QCoreApplication::applicationDirPath();
+        QString serverPath = "/server-console/server-console.exe";
+        qDebug() << "Application dir path is: " << applicationDirPath;
+        qDebug() << "Server path is: " << serverPath;
         QStringList args;
         if (parser.isSet(serverContentPathOption)) {
             QString serverContentPath = QFileInfo(arguments[0]).path() + "/" + parser.value(serverContentPathOption);
             args << "--" << "--contentPath" << serverContentPath;
         }
-        qDebug() << "server path: " << serverPath << args;
         qDebug() << QFileInfo(arguments[0]).path();
         qDebug() << QProcess::startDetached(serverPath, args);
 
+        // Sleep a short amount of time to give the server a chance to start
         usleep(2000000);
     }
 

From ff8f45d36c3fa7a96fe77ee67865d6ece6be648d Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Mon, 3 Oct 2016 15:45:19 -0700
Subject: [PATCH 19/28] Fix application directory path

---
 interface/src/main.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index c2bc10eefc..3c4a3fd77a 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -129,9 +129,8 @@ int main(int argc, const char* argv[]) {
     parser.addOption(serverContentPathOption);
     parser.parse(arguments);
     if (parser.isSet(runServerOption)) {
-        //QString serverPath = QFileInfo(arguments[0]).path();
-        QString applicationDirPath = QCoreApplication::applicationDirPath();
-        QString serverPath = "/server-console/server-console.exe";
+        QString applicationDirPath = QFileInfo(arguments[0]).path();
+        QString serverPath = applicationDirPath + "/server-console/server-console.exe";
         qDebug() << "Application dir path is: " << applicationDirPath;
         qDebug() << "Server path is: " << serverPath;
         QStringList args;

From a52e2d8bc56bce0327a9968885a136a07b3dfe01 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Sun, 2 Oct 2016 21:19:53 -0700
Subject: [PATCH 20/28] Add category to log lines

---
 libraries/shared/src/LogHandler.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp
index b67c86ecef..a0efdee2a8 100644
--- a/libraries/shared/src/LogHandler.cpp
+++ b/libraries/shared/src/LogHandler.cpp
@@ -137,9 +137,10 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
         dateFormatPtr = &DATE_STRING_FORMAT_WITH_MILLISECONDS;
     }
 
-    QString prefixString = QString("[%1]").arg(QDateTime::currentDateTime().toString(*dateFormatPtr));
+    QString prefixString = QString("[%1] [%2] [%3]").arg(QDateTime::currentDateTime().toString(*dateFormatPtr),
+        stringForLogType(type), context.category);
 
-    prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
+    //prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
 
     if (_shouldOutputProcessID) {
         prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));

From 2bb2aca2beac896dec09ca7255b141c2a947c287 Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Tue, 4 Oct 2016 16:54:37 -0700
Subject: [PATCH 21/28] Remove commented line in LogHandler

---
 libraries/shared/src/LogHandler.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp
index a0efdee2a8..f003506aa7 100644
--- a/libraries/shared/src/LogHandler.cpp
+++ b/libraries/shared/src/LogHandler.cpp
@@ -140,8 +140,6 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
     QString prefixString = QString("[%1] [%2] [%3]").arg(QDateTime::currentDateTime().toString(*dateFormatPtr),
         stringForLogType(type), context.category);
 
-    //prefixString.append(QString(" [%1]").arg(stringForLogType(type)));
-
     if (_shouldOutputProcessID) {
         prefixString.append(QString(" [%1]").arg(QCoreApplication::instance()->applicationPid()));
     }

From 972a611d0302a042e9c8b9b5d4bc172296722dee Mon Sep 17 00:00:00 2001
From: Zach Pomerantz <zach@highfidelity.io>
Date: Tue, 4 Oct 2016 17:50:34 -0700
Subject: [PATCH 22/28] retain stereo on dead audio resampling

---
 libraries/audio-client/src/AudioClient.cpp    |  6 +--
 .../audio/src/MixedProcessedAudioStream.cpp   | 40 +++++++++----------
 .../audio/src/MixedProcessedAudioStream.h     |  9 +++--
 3 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 16f4c35d21..d70730380f 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -1152,9 +1152,9 @@ bool AudioClient::outputLocalInjector(bool isStereo, AudioInjector* injector) {
 }
 
 void AudioClient::outputFormatChanged() {
-    int outputFormatChannelCountTimesSampleRate = _outputFormat.channelCount() * _outputFormat.sampleRate();
-    _outputFrameSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * outputFormatChannelCountTimesSampleRate / _desiredOutputFormat.sampleRate();
-    _receivedAudioStream.outputFormatChanged(outputFormatChannelCountTimesSampleRate);
+    _outputFrameSize = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * _outputFormat.channelCount() * _outputFormat.sampleRate()) /
+        _desiredOutputFormat.sampleRate();
+    _receivedAudioStream.outputFormatChanged(_outputFormat.sampleRate(), _outputFormat.channelCount());
 }
 
 bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp
index 88a1e071ec..6820a17a47 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.cpp
+++ b/libraries/audio/src/MixedProcessedAudioStream.cpp
@@ -17,27 +17,27 @@ static const int STEREO_FACTOR = 2;
 MixedProcessedAudioStream::MixedProcessedAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames)
     : InboundAudioStream(numFrameSamples, numFramesCapacity, numStaticJitterFrames) {}
 
-void MixedProcessedAudioStream::outputFormatChanged(int outputFormatChannelCountTimesSampleRate) {
-    _outputFormatChannelsTimesSampleRate = outputFormatChannelCountTimesSampleRate;
-    int deviceOutputFrameSize = networkToDeviceSamples(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
-    _ringBuffer.resizeForFrameSize(deviceOutputFrameSize);
+void MixedProcessedAudioStream::outputFormatChanged(int sampleRate, int channelCount) {
+    _outputSampleRate = sampleRate;
+    _outputChannelCount = channelCount;
+    int deviceOutputFrameFrames = networkToDeviceFrames(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / STEREO_FACTOR);
+    int deviceOutputFrameSamples = deviceOutputFrameFrames * STEREO_FACTOR;
+    _ringBuffer.resizeForFrameSize(deviceOutputFrameSamples);
 }
 
 int MixedProcessedAudioStream::writeDroppableSilentSamples(int silentSamples) {
-    
-    int deviceSilentSamplesWritten = InboundAudioStream::writeDroppableSilentSamples(networkToDeviceSamples(silentSamples));
-    
-    emit addedSilence(deviceToNetworkSamples(deviceSilentSamplesWritten) / STEREO_FACTOR);
-
+    int deviceSilentFrames = networkToDeviceFrames(silentSamples / STEREO_FACTOR);
+    int deviceSilentSamples = deviceSilentFrames * STEREO_FACTOR;
+    int deviceSilentSamplesWritten = InboundAudioStream::writeDroppableSilentSamples(deviceSilentSamples);
+    emit addedSilence(deviceToNetworkFrames(deviceSilentSamplesWritten / STEREO_FACTOR));
     return deviceSilentSamplesWritten;
 }
 
 int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int samples) {
-
-    int deviceSamplesWritten = InboundAudioStream::writeLastFrameRepeatedWithFade(networkToDeviceSamples(samples));
-
-    emit addedLastFrameRepeatedWithFade(deviceToNetworkSamples(deviceSamplesWritten) / STEREO_FACTOR);
-    
+    int deviceFrames = networkToDeviceFrames(samples / STEREO_FACTOR);
+    int deviceSamples = deviceFrames * STEREO_FACTOR;
+    int deviceSamplesWritten = InboundAudioStream::writeLastFrameRepeatedWithFade(deviceSamples);
+    emit addedLastFrameRepeatedWithFade(deviceToNetworkFrames(deviceSamplesWritten / STEREO_FACTOR));
     return deviceSamplesWritten;
 }
 
@@ -60,12 +60,12 @@ int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray&
     return packetAfterStreamProperties.size();
 }
 
-int MixedProcessedAudioStream::networkToDeviceSamples(int networkSamples) {
-    return (quint64)networkSamples * (quint64)_outputFormatChannelsTimesSampleRate / (quint64)(STEREO_FACTOR
-                                                                                               * AudioConstants::SAMPLE_RATE);
+int MixedProcessedAudioStream::networkToDeviceFrames(int networkFrames) {
+    return ((quint64)networkFrames * _outputChannelCount * _outputSampleRate) /
+        (quint64)(STEREO_FACTOR * AudioConstants::SAMPLE_RATE);
 }
 
-int MixedProcessedAudioStream::deviceToNetworkSamples(int deviceSamples) {
-    return (quint64)deviceSamples * (quint64)(STEREO_FACTOR * AudioConstants::SAMPLE_RATE)
-        / (quint64)_outputFormatChannelsTimesSampleRate;
+int MixedProcessedAudioStream::deviceToNetworkFrames(int deviceFrames) {
+    return (quint64)deviceFrames * (quint64)(STEREO_FACTOR * AudioConstants::SAMPLE_RATE) /
+        (_outputSampleRate * _outputChannelCount);
 }
diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h
index f28586f484..d89ce9f7e3 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.h
+++ b/libraries/audio/src/MixedProcessedAudioStream.h
@@ -30,7 +30,7 @@ signals:
     void processSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer);
 
 public:
-    void outputFormatChanged(int outputFormatChannelCountTimesSampleRate);
+    void outputFormatChanged(int sampleRate, int channelCount);
 
 protected:
     int writeDroppableSilentSamples(int silentSamples) override;
@@ -38,11 +38,12 @@ protected:
     int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) override;
 
 private:
-    int networkToDeviceSamples(int networkSamples);
-    int deviceToNetworkSamples(int deviceSamples);
+    int networkToDeviceFrames(int networkFrames);
+    int deviceToNetworkFrames(int deviceFrames);
 
 private:
-    int _outputFormatChannelsTimesSampleRate;
+    quint64 _outputSampleRate;
+    quint64 _outputChannelCount;
 };
 
 #endif // hifi_MixedProcessedAudioStream_h

From 00fabb77b42383a31355d33938b96a0a6e114e21 Mon Sep 17 00:00:00 2001
From: Zach Pomerantz <zach@highfidelity.io>
Date: Tue, 4 Oct 2016 18:20:01 -0700
Subject: [PATCH 23/28] use proper audio frame naming

---
 libraries/audio/src/InboundAudioStream.cpp    | 26 +++++++++----------
 libraries/audio/src/InboundAudioStream.h      |  8 +++---
 .../audio/src/MixedProcessedAudioStream.cpp   | 22 +++++++---------
 .../audio/src/MixedProcessedAudioStream.h     |  4 +--
 4 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp
index a3fabad70f..71e8cb12ab 100644
--- a/libraries/audio/src/InboundAudioStream.cpp
+++ b/libraries/audio/src/InboundAudioStream.cpp
@@ -121,11 +121,11 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
 
     packetReceivedUpdateTimingStats();
 
-    int networkSamples;
-    
+    int networkFrames;
+
     // parse the info after the seq number and before the audio data (the stream properties)
     int prePropertyPosition = message.getPosition();
-    int propertyBytes = parseStreamProperties(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkSamples);
+    int propertyBytes = parseStreamProperties(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkFrames);
     message.seek(prePropertyPosition + propertyBytes);
 
     // handle this packet based on its arrival status.
@@ -135,7 +135,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
             // NOTE: we assume that each dropped packet contains the same number of samples
             // as the packet we just received.
             int packetsDropped = arrivalInfo._seqDiffFromExpected;
-            writeSamplesForDroppedPackets(packetsDropped * networkSamples);
+            writeFramesForDroppedPackets(packetsDropped * networkFrames);
 
             // fall through to OnTime case
         }
@@ -143,7 +143,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
             // Packet is on time; parse its data to the ringbuffer
             if (message.getType() == PacketType::SilentAudioFrame) {
                 // FIXME - Some codecs need to know about these silent frames... and can produce better output
-                writeDroppableSilentSamples(networkSamples);
+                writeDroppableSilentFrames(networkFrames);
             } else {
                 // note: PCM and no codec are identical
                 bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == "";
@@ -153,7 +153,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
                     parseAudioData(message.getType(), afterProperties);
                 } else {
                     qDebug() << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence";
-                    writeDroppableSilentSamples(networkSamples);
+                    writeDroppableSilentFrames(networkFrames);
                     // inform others of the mismatch
                     auto sendingNode = DependencyManager::get<NodeList>()->nodeWithUUID(message.getSourceID());
                     emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket);
@@ -218,9 +218,9 @@ int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packet
     return _ringBuffer.writeData(decodedBuffer.data(), actualSize);
 }
 
-int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) {
+int InboundAudioStream::writeDroppableSilentFrames(int silentFrames) {
     if (_decoder) {
-        _decoder->trackLostFrames(silentSamples);
+        _decoder->trackLostFrames(silentFrames);
     }
 
     // calculate how many silent frames we should drop.
@@ -228,12 +228,12 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) {
     int desiredJitterBufferFramesPlusPadding = _desiredJitterBufferFrames + DESIRED_JITTER_BUFFER_FRAMES_PADDING;
     int numSilentFramesToDrop = 0;
 
-    if (silentSamples >= samplesPerFrame && _currentJitterBufferFrames > desiredJitterBufferFramesPlusPadding) {
+    if (silentFrames >= samplesPerFrame && _currentJitterBufferFrames > desiredJitterBufferFramesPlusPadding) {
 
         // our avg jitter buffer size exceeds its desired value, so ignore some silent
         // frames to get that size as close to desired as possible
         int numSilentFramesToDropDesired = _currentJitterBufferFrames - desiredJitterBufferFramesPlusPadding;
-        int numSilentFramesReceived = silentSamples / samplesPerFrame;
+        int numSilentFramesReceived = silentFrames / samplesPerFrame;
         numSilentFramesToDrop = std::min(numSilentFramesToDropDesired, numSilentFramesReceived);
 
         // dont reset _currentJitterBufferFrames here; we want to be able to drop further silent frames
@@ -247,7 +247,7 @@ int InboundAudioStream::writeDroppableSilentSamples(int silentSamples) {
         _framesAvailableStat.reset();
     }
 
-    int ret = _ringBuffer.addSilentSamples(silentSamples - numSilentFramesToDrop * samplesPerFrame);
+    int ret = _ringBuffer.addSilentSamples(silentFrames - numSilentFramesToDrop * samplesPerFrame);
     
     return ret;
 }
@@ -414,8 +414,8 @@ void InboundAudioStream::packetReceivedUpdateTimingStats() {
     _lastPacketReceivedTime = now;
 }
 
-int InboundAudioStream::writeSamplesForDroppedPackets(int networkSamples) {
-    return writeLastFrameRepeatedWithFade(networkSamples);
+int InboundAudioStream::writeFramesForDroppedPackets(int networkFrames) {
+    return writeLastFrameRepeatedWithFade(networkFrames);
 }
 
 int InboundAudioStream::writeLastFrameRepeatedWithFade(int samples) {
diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h
index 4c10c8c789..e72a45a01b 100644
--- a/libraries/audio/src/InboundAudioStream.h
+++ b/libraries/audio/src/InboundAudioStream.h
@@ -115,7 +115,7 @@ public slots:
 private:
     void packetReceivedUpdateTimingStats();
 
-    int writeSamplesForDroppedPackets(int networkSamples);
+    int writeFramesForDroppedPackets(int networkFrames);
 
     void popSamplesNoCheck(int samples);
     void framesAvailableChanged();
@@ -134,12 +134,12 @@ protected:
     /// default implementation assumes packet contains raw audio samples after stream properties
     virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties);
 
-    /// writes silent samples to the buffer that may be dropped to reduce latency caused by the buffer
-    virtual int writeDroppableSilentSamples(int silentSamples);
+    /// writes silent frames to the buffer that may be dropped to reduce latency caused by the buffer
+    virtual int writeDroppableSilentFrames(int silentFrames);
 
     /// writes the last written frame repeatedly, gradually fading to silence.
     /// used for writing samples for dropped packets.
-    virtual int writeLastFrameRepeatedWithFade(int samples);
+    virtual int writeLastFrameRepeatedWithFade(int frames);
     
 protected:
 
diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp
index 6820a17a47..ccaf35f1c4 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.cpp
+++ b/libraries/audio/src/MixedProcessedAudioStream.cpp
@@ -25,20 +25,18 @@ void MixedProcessedAudioStream::outputFormatChanged(int sampleRate, int channelC
     _ringBuffer.resizeForFrameSize(deviceOutputFrameSamples);
 }
 
-int MixedProcessedAudioStream::writeDroppableSilentSamples(int silentSamples) {
-    int deviceSilentFrames = networkToDeviceFrames(silentSamples / STEREO_FACTOR);
-    int deviceSilentSamples = deviceSilentFrames * STEREO_FACTOR;
-    int deviceSilentSamplesWritten = InboundAudioStream::writeDroppableSilentSamples(deviceSilentSamples);
-    emit addedSilence(deviceToNetworkFrames(deviceSilentSamplesWritten / STEREO_FACTOR));
-    return deviceSilentSamplesWritten;
+int MixedProcessedAudioStream::writeDroppableSilentFrames(int silentFrames) {
+    int deviceSilentFrames = networkToDeviceFrames(silentFrames);
+    int deviceSilentFramesWritten = InboundAudioStream::writeDroppableSilentFrames(deviceSilentFrames);
+    emit addedSilence(deviceToNetworkFrames(deviceSilentFramesWritten));
+    return deviceSilentFramesWritten;
 }
 
-int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int samples) {
-    int deviceFrames = networkToDeviceFrames(samples / STEREO_FACTOR);
-    int deviceSamples = deviceFrames * STEREO_FACTOR;
-    int deviceSamplesWritten = InboundAudioStream::writeLastFrameRepeatedWithFade(deviceSamples);
-    emit addedLastFrameRepeatedWithFade(deviceToNetworkFrames(deviceSamplesWritten / STEREO_FACTOR));
-    return deviceSamplesWritten;
+int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int frames) {
+    int deviceFrames = networkToDeviceFrames(frames);
+    int deviceFramesWritten = InboundAudioStream::writeLastFrameRepeatedWithFade(deviceFrames);
+    emit addedLastFrameRepeatedWithFade(deviceToNetworkFrames(deviceFramesWritten));
+    return deviceFramesWritten;
 }
 
 int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) {
diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h
index d89ce9f7e3..7071cf0e5a 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.h
+++ b/libraries/audio/src/MixedProcessedAudioStream.h
@@ -33,8 +33,8 @@ public:
     void outputFormatChanged(int sampleRate, int channelCount);
 
 protected:
-    int writeDroppableSilentSamples(int silentSamples) override;
-    int writeLastFrameRepeatedWithFade(int samples) override;
+    int writeDroppableSilentFrames(int silentFrames) override;
+    int writeLastFrameRepeatedWithFade(int frames) override;
     int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) override;
 
 private:

From 05aded5c9d7d645c8ada7425d313dd0a2a48235c Mon Sep 17 00:00:00 2001
From: Zach Pomerantz <zach@highfidelity.io>
Date: Tue, 4 Oct 2016 18:45:03 -0700
Subject: [PATCH 24/28] differentiate smaples/frames from dropped audio

---
 libraries/audio/src/InboundAudioStream.cpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp
index 71e8cb12ab..35c90e51bd 100644
--- a/libraries/audio/src/InboundAudioStream.cpp
+++ b/libraries/audio/src/InboundAudioStream.cpp
@@ -224,16 +224,17 @@ int InboundAudioStream::writeDroppableSilentFrames(int silentFrames) {
     }
 
     // calculate how many silent frames we should drop.
+    int silentSamples = silentFrames * 2;
     int samplesPerFrame = _ringBuffer.getNumFrameSamples();
     int desiredJitterBufferFramesPlusPadding = _desiredJitterBufferFrames + DESIRED_JITTER_BUFFER_FRAMES_PADDING;
     int numSilentFramesToDrop = 0;
 
-    if (silentFrames >= samplesPerFrame && _currentJitterBufferFrames > desiredJitterBufferFramesPlusPadding) {
+    if (silentSamples >= samplesPerFrame && _currentJitterBufferFrames > desiredJitterBufferFramesPlusPadding) {
 
         // our avg jitter buffer size exceeds its desired value, so ignore some silent
         // frames to get that size as close to desired as possible
         int numSilentFramesToDropDesired = _currentJitterBufferFrames - desiredJitterBufferFramesPlusPadding;
-        int numSilentFramesReceived = silentFrames / samplesPerFrame;
+        int numSilentFramesReceived = silentSamples / samplesPerFrame;
         numSilentFramesToDrop = std::min(numSilentFramesToDropDesired, numSilentFramesReceived);
 
         // dont reset _currentJitterBufferFrames here; we want to be able to drop further silent frames
@@ -247,7 +248,7 @@ int InboundAudioStream::writeDroppableSilentFrames(int silentFrames) {
         _framesAvailableStat.reset();
     }
 
-    int ret = _ringBuffer.addSilentSamples(silentFrames - numSilentFramesToDrop * samplesPerFrame);
+    int ret = _ringBuffer.addSilentSamples(silentSamples - numSilentFramesToDrop * samplesPerFrame);
     
     return ret;
 }
@@ -418,10 +419,10 @@ int InboundAudioStream::writeFramesForDroppedPackets(int networkFrames) {
     return writeLastFrameRepeatedWithFade(networkFrames);
 }
 
-int InboundAudioStream::writeLastFrameRepeatedWithFade(int samples) {
+int InboundAudioStream::writeLastFrameRepeatedWithFade(int frames) {
     AudioRingBuffer::ConstIterator frameToRepeat = _ringBuffer.lastFrameWritten();
     int frameSize = _ringBuffer.getNumFrameSamples();
-    int samplesToWrite = samples;
+    int samplesToWrite = frames * 2;
     int indexOfRepeat = 0;
     do {
         int samplesToWriteThisIteration = std::min(samplesToWrite, frameSize);
@@ -434,7 +435,7 @@ int InboundAudioStream::writeLastFrameRepeatedWithFade(int samples) {
         indexOfRepeat++;
     } while (samplesToWrite > 0);
 
-    return samples;
+    return frames;
 }
 
 AudioStreamStats InboundAudioStream::getAudioStreamStats() const {

From 5af95c6062bc80abd6ed7f5ad223c4be0fd61970 Mon Sep 17 00:00:00 2001
From: Zach Pomerantz <zach@highfidelity.io>
Date: Wed, 5 Oct 2016 11:33:12 -0700
Subject: [PATCH 25/28] store channels on audio stream

---
 assignment-client/src/Agent.cpp                   |  3 +--
 libraries/audio-client/src/AudioClient.cpp        |  2 +-
 libraries/audio/src/InboundAudioStream.cpp        | 13 +++++++------
 libraries/audio/src/InboundAudioStream.h          |  3 ++-
 libraries/audio/src/MixedAudioStream.cpp          |  9 +++++++--
 libraries/audio/src/MixedAudioStream.h            |  2 +-
 libraries/audio/src/MixedProcessedAudioStream.cpp |  5 +++--
 libraries/audio/src/MixedProcessedAudioStream.h   |  2 +-
 libraries/audio/src/PositionalAudioStream.cpp     | 11 +++++++----
 9 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp
index c6a2a3d5e8..65443b0574 100644
--- a/assignment-client/src/Agent.cpp
+++ b/assignment-client/src/Agent.cpp
@@ -48,8 +48,7 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
 Agent::Agent(ReceivedMessage& message) :
     ThreadedAssignment(message),
     _entityEditSender(),
-    _receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO,
-        RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
+    _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
     DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
 
     ResourceManager::init();
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index d70730380f..6fbd93e386 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -115,7 +115,7 @@ AudioClient::AudioClient() :
     _loopbackAudioOutput(NULL),
     _loopbackOutputDevice(NULL),
     _inputRingBuffer(0),
-    _receivedAudioStream(0, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES),
+    _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES),
     _isStereoInput(false),
     _outputStarveDetectionStartTimeMsec(0),
     _outputStarveDetectionCount(0),
diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp
index 35c90e51bd..177a5ddcef 100644
--- a/libraries/audio/src/InboundAudioStream.cpp
+++ b/libraries/audio/src/InboundAudioStream.cpp
@@ -46,10 +46,11 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30;
 // _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset.
 static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND;
 
-InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames) :
-    _ringBuffer(numFrameSamples, numFramesCapacity),
-    _dynamicJitterBufferEnabled(numStaticJitterFrames == -1),
-    _staticJitterBufferFrames(std::max(numStaticJitterFrames, DEFAULT_STATIC_JITTER_FRAMES)),
+InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) :
+    _ringBuffer(numChannels * numFrames, numBlocks),
+    _numChannels(numChannels),
+    _dynamicJitterBufferEnabled(numStaticJitterBlocks == -1),
+    _staticJitterBufferFrames(std::max(numStaticJitterBlocks, DEFAULT_STATIC_JITTER_FRAMES)),
     _desiredJitterBufferFrames(_dynamicJitterBufferEnabled ? 1 : _staticJitterBufferFrames),
     _incomingSequenceNumberStats(STATS_FOR_STATS_PACKET_WINDOW_SECONDS),
     _starveHistory(STARVE_HISTORY_CAPACITY),
@@ -224,7 +225,7 @@ int InboundAudioStream::writeDroppableSilentFrames(int silentFrames) {
     }
 
     // calculate how many silent frames we should drop.
-    int silentSamples = silentFrames * 2;
+    int silentSamples = silentFrames * _numChannels;
     int samplesPerFrame = _ringBuffer.getNumFrameSamples();
     int desiredJitterBufferFramesPlusPadding = _desiredJitterBufferFrames + DESIRED_JITTER_BUFFER_FRAMES_PADDING;
     int numSilentFramesToDrop = 0;
@@ -422,7 +423,7 @@ int InboundAudioStream::writeFramesForDroppedPackets(int networkFrames) {
 int InboundAudioStream::writeLastFrameRepeatedWithFade(int frames) {
     AudioRingBuffer::ConstIterator frameToRepeat = _ringBuffer.lastFrameWritten();
     int frameSize = _ringBuffer.getNumFrameSamples();
-    int samplesToWrite = frames * 2;
+    int samplesToWrite = frames * _numChannels;
     int indexOfRepeat = 0;
     do {
         int samplesToWriteThisIteration = std::min(samplesToWrite, frameSize);
diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h
index e72a45a01b..f7b79ab136 100644
--- a/libraries/audio/src/InboundAudioStream.h
+++ b/libraries/audio/src/InboundAudioStream.h
@@ -47,7 +47,7 @@ public:
     static const bool REPETITION_WITH_FADE;
 
     InboundAudioStream() = delete;
-    InboundAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames = -1);
+    InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks);
     ~InboundAudioStream();
 
     void reset();
@@ -144,6 +144,7 @@ protected:
 protected:
 
     AudioRingBuffer _ringBuffer;
+    int _numChannels;
 
     bool _lastPopSucceeded { false };
     AudioRingBuffer::ConstIterator _lastPopOutput;
diff --git a/libraries/audio/src/MixedAudioStream.cpp b/libraries/audio/src/MixedAudioStream.cpp
index 8a3091f596..0f28b23b24 100644
--- a/libraries/audio/src/MixedAudioStream.cpp
+++ b/libraries/audio/src/MixedAudioStream.cpp
@@ -11,5 +11,10 @@
 
 #include "MixedAudioStream.h"
 
-MixedAudioStream::MixedAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames) :
-    InboundAudioStream(numFrameSamples, numFramesCapacity, numStaticJitterFrames) {}
+#include "AudioConstants.h"
+
+static const int STEREO_FACTOR = 2;
+
+MixedAudioStream::MixedAudioStream(int numFramesCapacity, int numStaticJitterFrames) :
+    InboundAudioStream(STEREO_FACTOR, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
+        numFramesCapacity, numStaticJitterFrames) {}
diff --git a/libraries/audio/src/MixedAudioStream.h b/libraries/audio/src/MixedAudioStream.h
index f86ebaef56..6f2716203e 100644
--- a/libraries/audio/src/MixedAudioStream.h
+++ b/libraries/audio/src/MixedAudioStream.h
@@ -16,7 +16,7 @@
 
 class MixedAudioStream : public InboundAudioStream {
 public:
-    MixedAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames = -1);
+    MixedAudioStream(int numFramesCapacity, int numStaticJitterFrames = -1);
 
     float getNextOutputFrameLoudness() const { return _ringBuffer.getNextOutputFrameLoudness(); }
 };
diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp
index ccaf35f1c4..26ae6f7928 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.cpp
+++ b/libraries/audio/src/MixedProcessedAudioStream.cpp
@@ -14,8 +14,9 @@
 
 static const int STEREO_FACTOR = 2;
 
-MixedProcessedAudioStream::MixedProcessedAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames)
-    : InboundAudioStream(numFrameSamples, numFramesCapacity, numStaticJitterFrames) {}
+MixedProcessedAudioStream::MixedProcessedAudioStream(int numFramesCapacity, int numStaticJitterFrames)
+    : InboundAudioStream(STEREO_FACTOR, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
+        numFramesCapacity, numStaticJitterFrames) {}
 
 void MixedProcessedAudioStream::outputFormatChanged(int sampleRate, int channelCount) {
     _outputSampleRate = sampleRate;
diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h
index 7071cf0e5a..d536163d2d 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.h
+++ b/libraries/audio/src/MixedProcessedAudioStream.h
@@ -19,7 +19,7 @@ class AudioClient;
 class MixedProcessedAudioStream  : public InboundAudioStream {
     Q_OBJECT
 public:
-    MixedProcessedAudioStream(int numFrameSamples, int numFramesCapacity, int numStaticJitterFrames = -1);
+    MixedProcessedAudioStream(int numFramesCapacity, int numStaticJitterFrames = -1);
 
 signals:
 
diff --git a/libraries/audio/src/PositionalAudioStream.cpp b/libraries/audio/src/PositionalAudioStream.cpp
index bb14044312..92573ced6f 100644
--- a/libraries/audio/src/PositionalAudioStream.cpp
+++ b/libraries/audio/src/PositionalAudioStream.cpp
@@ -21,11 +21,14 @@
 #include <udt/PacketHeaders.h>
 #include <UUID.h>
 
+static const int MONO_FACTOR = 1;
+static const int STEREO_FACTOR = 2;
+
 PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, int numStaticJitterFrames) :
-    InboundAudioStream(isStereo
-                       ? AudioConstants::NETWORK_FRAME_SAMPLES_STEREO
-                       : AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
-    AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY, numStaticJitterFrames),
+    InboundAudioStream(isStereo ? STEREO_FACTOR : MONO_FACTOR,
+                       AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
+                       AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY,
+                       numStaticJitterFrames),
     _type(type),
     _position(0.0f, 0.0f, 0.0f),
     _orientation(0.0f, 0.0f, 0.0f, 0.0f),

From afce8c4a458afbc17c606c7dacaba6625ae6c760 Mon Sep 17 00:00:00 2001
From: Zach Pomerantz <zach@highfidelity.io>
Date: Wed, 5 Oct 2016 13:02:28 -0700
Subject: [PATCH 26/28] STEREO_FACTOR -> AudioConstants::STEREO

---
 interface/src/audio/AudioScope.cpp                | 12 +++++-------
 libraries/audio/src/MixedAudioStream.cpp          |  4 +---
 libraries/audio/src/MixedProcessedAudioStream.cpp | 14 ++++++--------
 libraries/audio/src/PositionalAudioStream.cpp     |  5 +----
 4 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp
index 1946d216ff..346fbd11f4 100644
--- a/interface/src/audio/AudioScope.cpp
+++ b/interface/src/audio/AudioScope.cpp
@@ -250,8 +250,6 @@ int AudioScope::addSilenceToScope(QByteArray* byteArray, int frameOffset, int si
 }
 
 
-const int STEREO_FACTOR = 2;
-
 void AudioScope::addStereoSilenceToScope(int silentSamplesPerChannel) {
     if (!_isEnabled || _isPaused) {
         return;
@@ -265,10 +263,10 @@ void AudioScope::addStereoSamplesToScope(const QByteArray& samples) {
         return;
     }
     const int16_t* samplesData = reinterpret_cast<const int16_t*>(samples.data());
-    int samplesPerChannel = samples.size() / sizeof(int16_t) / STEREO_FACTOR;
+    int samplesPerChannel = samples.size() / sizeof(int16_t) / AudioConstants::STEREO;
     
-    addBufferToScope(_scopeOutputLeft, _scopeOutputOffset, samplesData, samplesPerChannel, 0, STEREO_FACTOR);
-    _scopeOutputOffset = addBufferToScope(_scopeOutputRight, _scopeOutputOffset, samplesData, samplesPerChannel, 1, STEREO_FACTOR);
+    addBufferToScope(_scopeOutputLeft, _scopeOutputOffset, samplesData, samplesPerChannel, 0, AudioConstants::STEREO);
+    _scopeOutputOffset = addBufferToScope(_scopeOutputRight, _scopeOutputOffset, samplesData, samplesPerChannel, 1, AudioConstants::STEREO);
     
     _scopeLastFrame = samples.right(AudioConstants::NETWORK_FRAME_BYTES_STEREO);
 }
@@ -282,9 +280,9 @@ void AudioScope::addLastFrameRepeatedWithFadeToScope(int samplesPerChannel) {
         int samplesToWriteThisIteration = std::min(samplesRemaining, (int) AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
         float fade = calculateRepeatedFrameFadeFactor(indexOfRepeat);
         addBufferToScope(_scopeOutputLeft, _scopeOutputOffset, lastFrameData,
-                         samplesToWriteThisIteration, 0, STEREO_FACTOR, fade);
+                         samplesToWriteThisIteration, 0, AudioConstants::STEREO, fade);
         _scopeOutputOffset = addBufferToScope(_scopeOutputRight, _scopeOutputOffset,
-                                              lastFrameData, samplesToWriteThisIteration, 1, STEREO_FACTOR, fade);
+                                              lastFrameData, samplesToWriteThisIteration, 1, AudioConstants::STEREO, fade);
         
         samplesRemaining -= samplesToWriteThisIteration;
         indexOfRepeat++;
diff --git a/libraries/audio/src/MixedAudioStream.cpp b/libraries/audio/src/MixedAudioStream.cpp
index 0f28b23b24..e9af6933b6 100644
--- a/libraries/audio/src/MixedAudioStream.cpp
+++ b/libraries/audio/src/MixedAudioStream.cpp
@@ -13,8 +13,6 @@
 
 #include "AudioConstants.h"
 
-static const int STEREO_FACTOR = 2;
-
 MixedAudioStream::MixedAudioStream(int numFramesCapacity, int numStaticJitterFrames) :
-    InboundAudioStream(STEREO_FACTOR, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
+    InboundAudioStream(AudioConstants::STEREO, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
         numFramesCapacity, numStaticJitterFrames) {}
diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp
index 26ae6f7928..671d3a9d60 100644
--- a/libraries/audio/src/MixedProcessedAudioStream.cpp
+++ b/libraries/audio/src/MixedProcessedAudioStream.cpp
@@ -12,17 +12,15 @@
 #include "MixedProcessedAudioStream.h"
 #include "AudioLogging.h"
 
-static const int STEREO_FACTOR = 2;
-
 MixedProcessedAudioStream::MixedProcessedAudioStream(int numFramesCapacity, int numStaticJitterFrames)
-    : InboundAudioStream(STEREO_FACTOR, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
+    : InboundAudioStream(AudioConstants::STEREO, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
         numFramesCapacity, numStaticJitterFrames) {}
 
 void MixedProcessedAudioStream::outputFormatChanged(int sampleRate, int channelCount) {
     _outputSampleRate = sampleRate;
     _outputChannelCount = channelCount;
-    int deviceOutputFrameFrames = networkToDeviceFrames(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / STEREO_FACTOR);
-    int deviceOutputFrameSamples = deviceOutputFrameFrames * STEREO_FACTOR;
+    int deviceOutputFrameFrames = networkToDeviceFrames(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / AudioConstants::STEREO);
+    int deviceOutputFrameSamples = deviceOutputFrameFrames * AudioConstants::STEREO;
     _ringBuffer.resizeForFrameSize(deviceOutputFrameSamples);
 }
 
@@ -55,16 +53,16 @@ int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray&
 
     _ringBuffer.writeData(outputBuffer.data(), outputBuffer.size());
     qCDebug(audiostream, "Wrote %d samples to buffer (%d available)", outputBuffer.size() / (int)sizeof(int16_t), getSamplesAvailable());
-    
+
     return packetAfterStreamProperties.size();
 }
 
 int MixedProcessedAudioStream::networkToDeviceFrames(int networkFrames) {
     return ((quint64)networkFrames * _outputChannelCount * _outputSampleRate) /
-        (quint64)(STEREO_FACTOR * AudioConstants::SAMPLE_RATE);
+        (quint64)(AudioConstants::STEREO * AudioConstants::SAMPLE_RATE);
 }
 
 int MixedProcessedAudioStream::deviceToNetworkFrames(int deviceFrames) {
-    return (quint64)deviceFrames * (quint64)(STEREO_FACTOR * AudioConstants::SAMPLE_RATE) /
+    return (quint64)deviceFrames * (quint64)(AudioConstants::STEREO * AudioConstants::SAMPLE_RATE) /
         (_outputSampleRate * _outputChannelCount);
 }
diff --git a/libraries/audio/src/PositionalAudioStream.cpp b/libraries/audio/src/PositionalAudioStream.cpp
index 92573ced6f..e7bf72c955 100644
--- a/libraries/audio/src/PositionalAudioStream.cpp
+++ b/libraries/audio/src/PositionalAudioStream.cpp
@@ -21,11 +21,8 @@
 #include <udt/PacketHeaders.h>
 #include <UUID.h>
 
-static const int MONO_FACTOR = 1;
-static const int STEREO_FACTOR = 2;
-
 PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, int numStaticJitterFrames) :
-    InboundAudioStream(isStereo ? STEREO_FACTOR : MONO_FACTOR,
+    InboundAudioStream(isStereo ? AudioConstants::STEREO : AudioConstants::MONO,
                        AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL,
                        AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY,
                        numStaticJitterFrames),

From 7642e9fd1e29726f0062407b0c4b8876ee237c65 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Wed, 5 Oct 2016 13:06:36 -0700
Subject: [PATCH 27/28] remove cmake warning about untestable CPP file

also: fix some broken unit tests
---
 .../src/CollisionRenderMeshCacheTests.cpp     |  2 +-
 tests/physics/src/MeshUtil.cpp                | 45 -------------------
 tests/physics/src/MeshUtil.h                  | 34 +++++++++++++-
 tests/physics/src/ShapeInfoTests.cpp          | 16 +++----
 tests/physics/src/ShapeManagerTests.cpp       | 32 ++++++-------
 5 files changed, 57 insertions(+), 72 deletions(-)
 delete mode 100644 tests/physics/src/MeshUtil.cpp

diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp
index 085c9a2fe3..ad5d5db0ab 100644
--- a/tests/physics/src/CollisionRenderMeshCacheTests.cpp
+++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp
@@ -20,7 +20,7 @@
 #include <CollisionRenderMeshCache.h>
 #include <ShapeInfo.h> // for MAX_HULL_POINTS
 
-#include "MeshUtil.cpp"
+#include "MeshUtil.h"
 
 
 QTEST_MAIN(CollisionRenderMeshCacheTests)
diff --git a/tests/physics/src/MeshUtil.cpp b/tests/physics/src/MeshUtil.cpp
deleted file mode 100644
index d3eb815948..0000000000
--- a/tests/physics/src/MeshUtil.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-//  MeshUtil.cpp
-//  tests/physics/src
-//
-//  Created by Andrew Meadows 2016.07.14
-//  Copyright 2016 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 "MeshUtil.h"
-
-#include<unordered_map>
-
-// returns false if any edge has only one adjacent triangle
-bool MeshUtil::isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices) {
-    using EdgeList = std::unordered_map<MeshUtil::TriangleEdge, uint32_t>;
-    EdgeList edges;
-
-    // count the triangles for each edge
-    const uint32_t TRIANGLE_STRIDE = 3;
-    for (uint32_t i = 0; i < numIndices; i += TRIANGLE_STRIDE) {
-        MeshUtil::TriangleEdge edge;
-        // the triangles indices are stored in sequential order
-        for (uint32_t j = 0; j < 3; ++j) {
-            edge.setIndices(meshIndices[i + j], meshIndices[i + ((j + 1) % 3)]);
-
-            EdgeList::iterator edgeEntry = edges.find(edge);
-            if (edgeEntry == edges.end()) {
-                edges.insert(std::pair<MeshUtil::TriangleEdge, uint32_t>(edge, 1));
-            } else {
-                edgeEntry->second += 1;
-            }
-        }
-    }
-    // scan for outside edge
-    for (auto& edgeEntry : edges) {
-        if (edgeEntry.second == 1) {
-             return false;
-        }
-    }
-    return true;
-}
-
diff --git a/tests/physics/src/MeshUtil.h b/tests/physics/src/MeshUtil.h
index 82d33d631b..6603ee4fae 100644
--- a/tests/physics/src/MeshUtil.h
+++ b/tests/physics/src/MeshUtil.h
@@ -42,8 +42,6 @@ private:
     uint32_t _indexB { (uint32_t)(-1) };
 };
 
-bool isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices);
-
 } // MeshUtil namespace
 
 namespace std {
@@ -55,7 +53,39 @@ namespace std {
             return hash<uint32_t>()((ab * (ab + 1)) / 2 + edge.getIndexB());
         }
     };
+} // std namesspace
+
+namespace MeshUtil {
+bool isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices) {
+    using EdgeList = std::unordered_map<TriangleEdge, uint32_t>;
+    EdgeList edges;
+
+    // count the triangles for each edge
+    const uint32_t TRIANGLE_STRIDE = 3;
+    for (uint32_t i = 0; i < numIndices; i += TRIANGLE_STRIDE) {
+        TriangleEdge edge;
+        // the triangles indices are stored in sequential order
+        for (uint32_t j = 0; j < 3; ++j) {
+            edge.setIndices(meshIndices[i + j], meshIndices[i + ((j + 1) % 3)]);
+
+            EdgeList::iterator edgeEntry = edges.find(edge);
+            if (edgeEntry == edges.end()) {
+                edges.insert(std::pair<TriangleEdge, uint32_t>(edge, 1));
+            } else {
+                edgeEntry->second += 1;
+            }
+        }
+    }
+    // scan for outside edge
+    for (auto& edgeEntry : edges) {
+        if (edgeEntry.second == 1) {
+             return false;
+        }
+    }
+    return true;
 }
 
+} // MeshUtil namespace
+
 
 #endif // hifi_MeshUtil_h
diff --git a/tests/physics/src/ShapeInfoTests.cpp b/tests/physics/src/ShapeInfoTests.cpp
index 01f5c4e511..c6a19084a2 100644
--- a/tests/physics/src/ShapeInfoTests.cpp
+++ b/tests/physics/src/ShapeInfoTests.cpp
@@ -42,7 +42,7 @@ void ShapeInfoTests::testHashFunctions() {
 
     int testCount = 0;
     int numCollisions = 0;
-    
+
     btClock timer;
     for (int x = 1; x < numSteps && testCount < maxTests; ++x) {
         float radiusX = (float)x * deltaLength;
@@ -52,7 +52,7 @@ void ShapeInfoTests::testHashFunctions() {
         DoubleHashKey key = info.getHash();
         uint32_t* hashPtr = hashes.find(key.getHash());
         if (hashPtr && *hashPtr == key.getHash2()) {
-            std::cout << testCount << "  hash collision radiusX = " << radiusX 
+            std::cout << testCount << "  hash collision radiusX = " << radiusX
                 << "  h1 = 0x" << std::hex << key.getHash()
                 << "  h2 = 0x" << std::hex << key.getHash2()
                 << std::endl;
@@ -88,7 +88,7 @@ void ShapeInfoTests::testHashFunctions() {
                 key = info.getHash();
                 hashPtr = hashes.find(key.getHash());
                 if (hashPtr && *hashPtr == key.getHash2()) {
-                    std::cout << testCount << "  hash collision radiusX = " << radiusX << "  radiusY = " << radiusY 
+                    std::cout << testCount << "  hash collision radiusX = " << radiusX << "  radiusY = " << radiusY
                         << "  h1 = 0x" << std::hex << key.getHash()
                         << "  h2 = 0x" << std::hex << key.getHash2()
                         << std::endl;
@@ -113,8 +113,8 @@ void ShapeInfoTests::testHashFunctions() {
                 DoubleHashKey key = info.getHash();
                 hashPtr = hashes.find(key.getHash());
                 if (hashPtr && *hashPtr == key.getHash2()) {
-                    std::cout << testCount << "  hash collision radiusX = " << radiusX 
-                        << "  radiusY = " << radiusY << "  radiusZ = " << radiusZ 
+                    std::cout << testCount << "  hash collision radiusX = " << radiusX
+                        << "  radiusY = " << radiusY << "  radiusZ = " << radiusZ
                         << "  h1 = 0x" << std::hex << key.getHash()
                         << "  h2 = 0x" << std::hex << key.getHash2()
                         << std::endl;
@@ -148,9 +148,9 @@ void ShapeInfoTests::testBoxShape() {
     info.setBox(halfExtents);
     DoubleHashKey key = info.getHash();
 
-    btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
+    const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
     QCOMPARE(shape != nullptr, true);
-    
+
     ShapeInfo otherInfo = info;
     DoubleHashKey otherKey = otherInfo.getHash();
     QCOMPARE(key.getHash(), otherKey.getHash());
@@ -165,7 +165,7 @@ void ShapeInfoTests::testSphereShape() {
     info.setSphere(radius);
     DoubleHashKey key = info.getHash();
 
-    btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
+    const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info);
     QCOMPARE(shape != nullptr, true);
 
     ShapeInfo otherInfo = info;
diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp
index 24d4a5ab35..f214601a42 100644
--- a/tests/physics/src/ShapeManagerTests.cpp
+++ b/tests/physics/src/ShapeManagerTests.cpp
@@ -27,14 +27,14 @@ void ShapeManagerTests::testShapeAccounting() {
     QCOMPARE(numReferences, 0);
 
     // create one shape and verify we get a valid pointer
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
     QCOMPARE(shape != nullptr, true);
 
     // verify number of shapes
     QCOMPARE(shapeManager.getNumShapes(), 1);
 
     // reference the shape again and verify that we get the same pointer
-    btCollisionShape* otherShape = shapeManager.getShape(info);
+    const btCollisionShape* otherShape = shapeManager.getShape(info);
     QCOMPARE(otherShape, shape);
 
     // verify number of references
@@ -84,7 +84,7 @@ void ShapeManagerTests::testShapeAccounting() {
 void ShapeManagerTests::addManyShapes() {
     ShapeManager shapeManager;
 
-    QVector<btCollisionShape*> shapes;
+    QVector<const btCollisionShape*> shapes;
 
     int numSizes = 100;
     float startSize = 1.0f;
@@ -96,7 +96,7 @@ void ShapeManagerTests::addManyShapes() {
         float s = startSize + (float)i * deltaSize;
         glm::vec3 scale(s, 1.23f + s, s - 0.573f);
         info.setBox(0.5f * scale);
-        btCollisionShape* shape = shapeManager.getShape(info);
+        const btCollisionShape* shape = shapeManager.getShape(info);
         shapes.push_back(shape);
         QCOMPARE(shape != nullptr, true);
 
@@ -114,14 +114,14 @@ void ShapeManagerTests::addManyShapes() {
 
     // release each shape by pointer
     for (int i = 0; i < numShapes; ++i) {
-        btCollisionShape* shape = shapes[i];
+        const btCollisionShape* shape = shapes[i];
         bool success = shapeManager.releaseShape(shape);
         QCOMPARE(success, true);
     }
 
     // verify zero references
     for (int i = 0; i < numShapes; ++i) {
-        btCollisionShape* shape = shapes[i];
+        const btCollisionShape* shape = shapes[i];
         int numReferences = shapeManager.getNumReferences(shape);
         QCOMPARE(numReferences, 0);
     }
@@ -133,10 +133,10 @@ void ShapeManagerTests::addBoxShape() {
     info.setBox(halfExtents);
 
     ShapeManager shapeManager;
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
 
     ShapeInfo otherInfo = info;
-    btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
+    const btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
     QCOMPARE(shape, otherShape);
 }
 
@@ -146,10 +146,10 @@ void ShapeManagerTests::addSphereShape() {
     info.setSphere(radius);
 
     ShapeManager shapeManager;
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
 
     ShapeInfo otherInfo = info;
-    btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
+    const btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
     QCOMPARE(shape, otherShape);
 }
 
@@ -161,10 +161,10 @@ void ShapeManagerTests::addCylinderShape() {
     info.setCylinder(radius, height);
 
     ShapeManager shapeManager;
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
 
     ShapeInfo otherInfo = info;
-    btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
+    const btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
     QCOMPARE(shape, otherShape);
     */
 }
@@ -177,10 +177,10 @@ void ShapeManagerTests::addCapsuleShape() {
     info.setCapsule(radius, height);
 
     ShapeManager shapeManager;
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
 
     ShapeInfo otherInfo = info;
-    btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
+    const btCollisionShape* otherShape = shapeManager.getShape(otherInfo);
     QCOMPARE(shape, otherShape);
     */
 }
@@ -219,14 +219,14 @@ void ShapeManagerTests::addCompoundShape() {
 
     // create the shape
     ShapeManager shapeManager;
-    btCollisionShape* shape = shapeManager.getShape(info);
+    const btCollisionShape* shape = shapeManager.getShape(info);
     QVERIFY(shape != nullptr);
 
     // verify the shape is correct type
     QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE);
 
     // verify the shape has correct number of children
-    btCompoundShape* compoundShape = static_cast<btCompoundShape*>(shape);
+    const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
     QCOMPARE(compoundShape->getNumChildShapes(), numHulls);
 
     // verify manager has only one shape

From e46c15401aec77c88d746923787bd709394ef85e Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@highfidelity.io>
Date: Wed, 5 Oct 2016 15:00:22 -0700
Subject: [PATCH 28/28] take care for division by zero when normalizing

---
 libraries/physics/src/CollisionRenderMeshCache.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp
index 517e25e1c4..3a1c4d0ea4 100644
--- a/libraries/physics/src/CollisionRenderMeshCache.cpp
+++ b/libraries/physics/src/CollisionRenderMeshCache.cpp
@@ -90,7 +90,11 @@ bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape,
         avgVertex = transform * (avgVertex * (1.0f / (float)numHullVertices));
 
         for (int i = 0; i < numHullVertices; ++i) {
-            btVector3 norm = (transform * hullVertices[i] - avgVertex).normalize();
+            btVector3 norm = transform * hullVertices[i] - avgVertex;
+            btScalar normLength = norm.length();
+            if (normLength > FLT_EPSILON) {
+                norm /= normLength;
+            }
             memcpy(tempVertices + 3 * i, norm.m_floats, SIZE_OF_VEC3);
         }
         gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices);