From cfb2fd1523c8c7ce027a720c4c5abe157fa788ef Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Tue, 27 Oct 2015 11:52:47 -0700
Subject: [PATCH] Support for runtime plugins (DLLs)

---
 CMakeLists.txt                                |   1 +
 cmake/externals/glew/CMakeLists.txt           |   5 +-
 cmake/macros/SetupHifiPlugin.cmake            |  33 +++++
 interface/src/Application.cpp                 |   1 -
 interface/src/PluginContainerProxy.cpp        |   1 -
 libraries/display-plugins/CMakeLists.txt      |   7 +-
 .../AbstractHMDScriptingInterface.cpp         |   5 +-
 .../Basic2DWindowOpenGLDisplayPlugin.cpp      |  22 +--
 .../src/display-plugins/DisplayPlugin.cpp     |  12 --
 .../src/display-plugins/DisplayPlugin.h       | 131 +---------------
 .../src/display-plugins/NullDisplayPlugin.cpp |   2 +-
 .../src/display-plugins/NullDisplayPlugin.h   |   2 +-
 .../display-plugins/OpenGLDisplayPlugin.cpp   |   1 +
 .../WindowOpenGLDisplayPlugin.cpp             |   2 +-
 .../openvr/OpenVrDisplayPlugin.cpp            |   4 +-
 .../stereo/StereoDisplayPlugin.cpp            |  10 +-
 .../src/input-plugins/InputPlugin.h           |  12 +-
 .../src/input-plugins/SixenseManager.cpp      |  10 +-
 .../input-plugins/ViveControllerManager.cpp   |   8 +-
 libraries/plugins/src/plugins/DisplayPlugin.h | 140 ++++++++++++++++++
 libraries/plugins/src/plugins/Forward.h       |   1 +
 libraries/plugins/src/plugins/InputPlugin.h   |  23 +++
 libraries/plugins/src/plugins/Plugin.cpp      |   4 +-
 libraries/plugins/src/plugins/Plugin.h        |   6 +-
 .../plugins/src/plugins/PluginManager.cpp     |  73 ++++++++-
 libraries/plugins/src/plugins/PluginManager.h |   1 +
 libraries/plugins/src/plugins/RuntimePlugin.h |  36 +++++
 plugins/CMakeLists.txt                        |  18 +++
 plugins/oculus/CMakeLists.txt                 |  22 +++
 .../oculus/src}/OculusBaseDisplayPlugin.cpp   |   8 +
 .../oculus/src}/OculusBaseDisplayPlugin.h     |   3 +-
 .../oculus/src}/OculusDebugDisplayPlugin.cpp  |   0
 .../oculus/src}/OculusDebugDisplayPlugin.h    |   0
 .../oculus/src}/OculusDisplayPlugin.cpp       |  13 +-
 .../oculus/src}/OculusDisplayPlugin.h         |   0
 .../oculus/src}/OculusHelpers.cpp             |   0
 .../oculus/src}/OculusHelpers.h               |   0
 plugins/oculus/src/OculusProvider.cpp         |  54 +++++++
 plugins/oculus/src/oculus.json                |   1 +
 plugins/oculusLegacy/CMakeLists.txt           |  22 +++
 plugins/oculusLegacy/src/OculusHelpers.cpp    |   9 ++
 plugins/oculusLegacy/src/OculusHelpers.h      |  85 +++++++++++
 .../src}/OculusLegacyDisplayPlugin.cpp        |  34 +----
 .../src}/OculusLegacyDisplayPlugin.h          |   2 +-
 plugins/oculusLegacy/src/OculusProvider.cpp   |  45 ++++++
 plugins/oculusLegacy/src/oculus.json          |   1 +
 tests/controllers/src/main.cpp                |   3 -
 47 files changed, 631 insertions(+), 242 deletions(-)
 create mode 100644 cmake/macros/SetupHifiPlugin.cmake
 create mode 100644 libraries/plugins/src/plugins/DisplayPlugin.h
 create mode 100644 libraries/plugins/src/plugins/InputPlugin.h
 create mode 100644 libraries/plugins/src/plugins/RuntimePlugin.h
 create mode 100644 plugins/CMakeLists.txt
 create mode 100644 plugins/oculus/CMakeLists.txt
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusBaseDisplayPlugin.cpp (95%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusBaseDisplayPlugin.h (96%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDebugDisplayPlugin.cpp (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDebugDisplayPlugin.h (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDisplayPlugin.cpp (97%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusDisplayPlugin.h (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusHelpers.cpp (100%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculus/src}/OculusHelpers.h (100%)
 create mode 100644 plugins/oculus/src/OculusProvider.cpp
 create mode 100644 plugins/oculus/src/oculus.json
 create mode 100644 plugins/oculusLegacy/CMakeLists.txt
 create mode 100644 plugins/oculusLegacy/src/OculusHelpers.cpp
 create mode 100644 plugins/oculusLegacy/src/OculusHelpers.h
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculusLegacy/src}/OculusLegacyDisplayPlugin.cpp (90%)
 rename {libraries/display-plugins/src/display-plugins/oculus => plugins/oculusLegacy/src}/OculusLegacyDisplayPlugin.h (97%)
 create mode 100644 plugins/oculusLegacy/src/OculusProvider.cpp
 create mode 100644 plugins/oculusLegacy/src/oculus.json

diff --git a/CMakeLists.txt b/CMakeLists.txt
index efe99b550b..d1c69e4f6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -203,6 +203,7 @@ if (NOT ANDROID)
   add_subdirectory(interface)
   set_target_properties(interface PROPERTIES FOLDER "Apps")
   add_subdirectory(tests)
+  add_subdirectory(plugins)
   add_subdirectory(tools)
 endif ()
 
diff --git a/cmake/externals/glew/CMakeLists.txt b/cmake/externals/glew/CMakeLists.txt
index 5f59cc2377..0a4a0abe71 100644
--- a/cmake/externals/glew/CMakeLists.txt
+++ b/cmake/externals/glew/CMakeLists.txt
@@ -7,14 +7,15 @@ endif ()
 include(ExternalProject)
 ExternalProject_Add(
   ${EXTERNAL_NAME}
-  URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple.zip
-  URL_MD5 0507dc08337a82a5e7ecbc5417f92cc1
+  URL http://hifi-public.s3.amazonaws.com/dependencies/glew_simple2.zip
+  URL_MD5 f05d858e8203c32b689da208ad8b39db
   CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
   LOG_DOWNLOAD 1
   LOG_CONFIGURE 1
   LOG_BUILD 1
 )
 
+
 # Hide this external target (for ide users)
 set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
 
diff --git a/cmake/macros/SetupHifiPlugin.cmake b/cmake/macros/SetupHifiPlugin.cmake
new file mode 100644
index 0000000000..0ee94c7816
--- /dev/null
+++ b/cmake/macros/SetupHifiPlugin.cmake
@@ -0,0 +1,33 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  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
+#
+macro(SETUP_HIFI_PLUGIN)
+    set(${TARGET_NAME}_SHARED 1)
+    setup_hifi_library(${ARGV})
+    add_dependencies(interface ${TARGET_NAME})
+    set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Plugins")
+    
+    if (APPLE) 
+        set(PLUGIN_PATH "interface.app/Contents/MacOS/plugins")
+    else()
+        set(PLUGIN_PATH "plugins")
+    endif()
+    
+    # create the destination for the plugin binaries
+    add_custom_command(
+        TARGET ${TARGET_NAME} POST_BUILD
+        COMMAND "${CMAKE_COMMAND}" -E make_directory
+        "${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
+    )
+    
+    add_custom_command(TARGET ${DIR} POST_BUILD
+        COMMAND "${CMAKE_COMMAND}" -E copy
+        "$<TARGET_FILE:${TARGET_NAME}>"
+        "${CMAKE_BINARY_DIR}/interface/$<CONFIGURATION>/${PLUGIN_PATH}/"
+    )
+
+endmacro()
\ No newline at end of file
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index dc2eee000d..653f9cf906 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -392,7 +392,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
     _entityClipboard->createRootElement();
 
     _pluginContainer = new PluginContainerProxy();
-    Plugin::setContainer(_pluginContainer);
 #ifdef Q_OS_WIN
     installNativeEventFilter(&MyNativeEventFilter::getInstance());
 #endif
diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp
index 079d6d0bea..2e5c883897 100644
--- a/interface/src/PluginContainerProxy.cpp
+++ b/interface/src/PluginContainerProxy.cpp
@@ -13,7 +13,6 @@
 #include "ui/DialogsManager.h"
 
 PluginContainerProxy::PluginContainerProxy() {
-    Plugin::setContainer(this);
 }
 
 PluginContainerProxy::~PluginContainerProxy() {
diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt
index 14aa03de44..fad244fa5f 100644
--- a/libraries/display-plugins/CMakeLists.txt
+++ b/libraries/display-plugins/CMakeLists.txt
@@ -1,6 +1,6 @@
 set(TARGET_NAME display-plugins)
 setup_hifi_library(OpenGL)
-link_hifi_libraries(shared plugins gpu gl)
+link_hifi_libraries(shared plugins gl)
 
 target_opengl()
 
@@ -8,11 +8,6 @@ GroupSources("src/display-plugins")
 
 target_oglplus()
 
-add_dependency_external_projects(LibOVR)
-find_package(LibOVR REQUIRED)
-target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
-target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
-
 if (WIN32)
   add_dependency_external_projects(OpenVR)
   find_package(OpenVR REQUIRED)
diff --git a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
index 9987ae345c..4b8d957e5f 100644
--- a/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
+++ b/libraries/display-plugins/src/display-plugins/AbstractHMDScriptingInterface.cpp
@@ -12,7 +12,6 @@
 
 #include "DisplayPlugin.h"
 #include <plugins/PluginContainer.h>
-#include <OVR_CAPI_Keys.h>
 
 static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
 
@@ -26,12 +25,12 @@ float AbstractHMDScriptingInterface::getIPD() const {
 
 float AbstractHMDScriptingInterface::getEyeHeight() const {
     // FIXME update the display plugin interface to expose per-plugin settings
-    return OVR_DEFAULT_EYE_HEIGHT;
+    return getPlayerHeight() - 0.10f;
 }
 
 float AbstractHMDScriptingInterface::getPlayerHeight() const {
     // FIXME update the display plugin interface to expose per-plugin settings
-    return OVR_DEFAULT_PLAYER_HEIGHT;
+    return 1.755f;
 }
 
 float AbstractHMDScriptingInterface::getIPDScale() const {
diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
index 914d30d58a..9366ec4403 100644
--- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp
@@ -35,36 +35,36 @@ QAction* _vsyncAction{ nullptr };
 
 void Basic2DWindowOpenGLDisplayPlugin::activate() {
     _framerateActions.clear();
-    CONTAINER->addMenuItem(MENU_PATH(), FULLSCREEN,
+    _container->addMenuItem(MENU_PATH(), FULLSCREEN,
         [this](bool clicked) {
             if (clicked) {
-                CONTAINER->setFullscreen(getFullscreenTarget());
+                _container->setFullscreen(getFullscreenTarget());
             } else {
-                CONTAINER->unsetFullscreen();
+                _container->unsetFullscreen();
             }
         }, true, false);
-    CONTAINER->addMenu(FRAMERATE);
+    _container->addMenu(FRAMERATE);
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED,
             [this](bool) { updateFramerate(); }, true, true, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_60,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_60,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_50,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_50,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_40,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_40,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
     _framerateActions.push_back(
-        CONTAINER->addMenuItem(FRAMERATE, FRAMERATE_30,
+        _container->addMenuItem(FRAMERATE, FRAMERATE_30,
             [this](bool) { updateFramerate(); }, true, false, FRAMERATE));
 
     WindowOpenGLDisplayPlugin::activate();
 
     // Vsync detection happens in the parent class activate, so we need to check after that
     if (_vsyncSupported) {
-        _vsyncAction = CONTAINER->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
+        _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true);
     } else {
         _vsyncAction = nullptr;
     }
@@ -107,7 +107,7 @@ int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
 bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
     static const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Menu.h
 
-    bool shouldThrottle = (!CONTAINER->isForeground() && CONTAINER->isOptionChecked(ThrottleFPSIfNotFocus));
+    bool shouldThrottle = (!_container->isForeground() && _container->isOptionChecked(ThrottleFPSIfNotFocus));
     
     if (_isThrottled != shouldThrottle) {
         _isThrottled = shouldThrottle;
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
index 4af45d299b..8155d69826 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp
@@ -15,9 +15,6 @@
 #include "Basic2DWindowOpenGLDisplayPlugin.h"
 
 #include "openvr/OpenVrDisplayPlugin.h"
-#include "oculus/OculusDisplayPlugin.h"
-#include "oculus/OculusDebugDisplayPlugin.h"
-#include "oculus/OculusLegacyDisplayPlugin.h"
 
 const QString& DisplayPlugin::MENU_PATH() {
     static const QString value = "Display";
@@ -40,15 +37,6 @@ DisplayPluginList getDisplayPlugins() {
         new InterleavedStereoDisplayPlugin(),
 
         // HMDs
-
-        // Windows Oculus SDK
-        new OculusDisplayPlugin(),
-        // Windows Oculus Simulator... uses head tracking and the same rendering 
-        // as the connected hardware, but without using the SDK to display to the 
-        // Rift.  Useful for debugging Rift performance with nSight.
-        new OculusDebugDisplayPlugin(),
-        // Mac/Linux Oculus SDK (0.5)
-        new OculusLegacyDisplayPlugin(),
 #ifdef Q_OS_WIN
         // SteamVR SDK
         new OpenVrDisplayPlugin(),
diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
index b2176e0bd1..84c6592c53 100644
--- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.h
@@ -5,135 +5,6 @@
 //  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
 
-#include "plugins/Plugin.h"
-#include <QSize>
-#include <QPoint>
-#include <functional>
-
-#include <gl/Config.h>
-#include <GLMHelpers.h>
-
-#include <glm/glm.hpp>
-#include <glm/gtc/quaternion.hpp>
-#include <RegisteredMetaTypes.h>
-
-enum Eye {
-    Left,
-    Right,
-    Mono
-};
-
-/*
- * Helper method to iterate over each eye
- */
-template <typename F>
-void for_each_eye(F f) {
-    f(Left);
-    f(Right);
-}
-
-/*
- * Helper method to iterate over each eye, with an additional lambda to take action between the eyes
- */
-template <typename F, typename FF>
-void for_each_eye(F f, FF ff) {
-    f(Eye::Left);
-    ff();
-    f(Eye::Right);
-}
-
-class QWindow;
-
-#define AVERAGE_HUMAN_IPD 0.064f
-
-class DisplayPlugin : public Plugin {
-    Q_OBJECT
-public:
-    virtual bool isHmd() const { return false; }
-    virtual int getHmdScreen() const { return -1; }
-    /// By default, all HMDs are stereo
-    virtual bool isStereo() const { return isHmd(); }
-    virtual bool isThrottled() const { return false; }
-
-    // Rendering support
-
-    // Stop requesting renders, but don't do full deactivation
-    // needed to work around the issues caused by Oculus 
-    // processing messages in the middle of submitFrame
-    virtual void stop() = 0;
-
-    /**
-     *  Called by the application before the frame rendering.  Can be used for
-     *  render timing related calls (for instance, the Oculus begin frame timing
-     *  call)
-     */
-    virtual void preRender() = 0;
-    /**
-     *  Called by the application immediately before calling the display function.
-     *  For OpenGL based plugins, this is the best place to put activate the output
-     *  OpenGL context
-     */
-    virtual void preDisplay() = 0;
-
-    /**
-     *  Sends the scene texture to the display plugin.
-     */
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) = 0;
-
-    /**
-     *  Called by the application immeidately after display.  For OpenGL based
-     *  displays, this is the best place to put the buffer swap
-     */
-    virtual void finishFrame() = 0;
-
-    // Does the rendering surface have current focus?
-    virtual bool hasFocus() const = 0;
-
-    // The size of the rendering target (may be larger than the device size due to distortion)
-    virtual glm::uvec2 getRecommendedRenderSize() const = 0;
-
-    // The size of the UI
-    virtual glm::uvec2 getRecommendedUiSize() const {
-        return getRecommendedRenderSize();
-    }
-
-    // By default the aspect ratio is just the render size
-    virtual float getRecommendedAspectRatio() const {
-        return aspect(getRecommendedRenderSize());
-    }
-
-    // Stereo specific methods
-    virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
-        return baseProjection;
-    }
-
-    // HMD specific methods
-    // TODO move these into another class?
-    virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
-        static const glm::mat4 transform; return transform;
-    }
-
-    virtual glm::mat4 getHeadPose() const {
-        static const glm::mat4 pose; return pose;
-    }
-
-    // Needed for timewarp style features
-    virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
-        // NOOP
-    }
-
-    virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
-
-    virtual void abandonCalibration() {}
-    virtual void resetSensors() {}
-    virtual float devicePixelRatio() { return 1.0;  }
-
-
-    static const QString& MENU_PATH();
-signals:
-    void recommendedFramebufferSizeChanged(const QSize & size);
-    void requestRender();
-};
+#include <plugins/DisplayPlugin.h>
 
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
index 914f80d983..ce512962ff 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp
@@ -25,6 +25,6 @@ bool NullDisplayPlugin::hasFocus() const {
 
 void NullDisplayPlugin::preRender() {}
 void NullDisplayPlugin::preDisplay() {}
-void NullDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) {}
+void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {}
 void NullDisplayPlugin::finishFrame() {}
 void NullDisplayPlugin::stop() {}
diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
index 4f2cc77b8f..8cd5c2bc37 100644
--- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
+++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h
@@ -21,7 +21,7 @@ public:
     virtual bool hasFocus() const override;
     virtual void preRender() override;
     virtual void preDisplay() override;
-    virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
+    virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override;
     virtual void finishFrame() override;
 
 private:
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 3791375c9e..3ef882fe76 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -9,6 +9,7 @@
 #include <QOpenGLContext>
 #include <QCoreApplication>
 
+#include <gl/Config.h>
 #include <gl/GlWindow.h>
 #include <GLMHelpers.h>
 
diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
index ffea6605af..6ddc791503 100644
--- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp
@@ -42,7 +42,7 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const {
 
 void WindowOpenGLDisplayPlugin::activate() {
     OpenGLDisplayPlugin::activate();
-    _window = CONTAINER->getPrimarySurface();
+    _window = _container->getPrimarySurface();
     _window->makeCurrent();
     customizeContext();
     _window->doneCurrent();
diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
index 245fd11ef7..174bf1bf36 100644
--- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp
@@ -89,7 +89,7 @@ bool OpenVrDisplayPlugin::isSupported() const {
 }
 
 void OpenVrDisplayPlugin::activate() {
-    CONTAINER->setIsOptionChecked(StandingHMDSensorMode, true);
+    _container->setIsOptionChecked(StandingHMDSensorMode, true);
 
     hmdRefCount++;
     vr::HmdError eError = vr::HmdError_None;
@@ -132,7 +132,7 @@ void OpenVrDisplayPlugin::activate() {
 }
 
 void OpenVrDisplayPlugin::deactivate() {
-    CONTAINER->setIsOptionChecked(StandingHMDSensorMode, false);
+    _container->setIsOptionChecked(StandingHMDSensorMode, false);
 
     hmdRefCount--;
 
diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
index 4f7b0a1a78..f7e71313df 100644
--- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp
@@ -74,21 +74,21 @@ void StereoDisplayPlugin::activate() {
         if (screen == qApp->primaryScreen()) {
             checked = true;
         }
-        auto action = CONTAINER->addMenuItem(MENU_PATH(), name,
+        auto action = _container->addMenuItem(MENU_PATH(), name,
             [this](bool clicked) { updateScreen(); }, true, checked, "Screens");
         _screenActions[i] = action;
     }
 
-    CONTAINER->removeMenu(FRAMERATE);
+    _container->removeMenu(FRAMERATE);
 
-    CONTAINER->setFullscreen(qApp->primaryScreen());
+    _container->setFullscreen(qApp->primaryScreen());
     WindowOpenGLDisplayPlugin::activate();
 }
 
 void StereoDisplayPlugin::updateScreen() {
     for (uint32_t i = 0; i < _screenActions.size(); ++i) {
         if (_screenActions[i]->isChecked()) {
-            CONTAINER->setFullscreen(qApp->screens().at(i));
+            _container->setFullscreen(qApp->screens().at(i));
             break;
         }
     }
@@ -96,7 +96,7 @@ void StereoDisplayPlugin::updateScreen() {
 
 void StereoDisplayPlugin::deactivate() {
     _screenActions.clear();
-    CONTAINER->unsetFullscreen();
+    _container->unsetFullscreen();
     WindowOpenGLDisplayPlugin::deactivate();
 }
 
diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.h b/libraries/input-plugins/src/input-plugins/InputPlugin.h
index 787922e04c..d03f884ec7 100644
--- a/libraries/input-plugins/src/input-plugins/InputPlugin.h
+++ b/libraries/input-plugins/src/input-plugins/InputPlugin.h
@@ -10,14 +10,4 @@
 //
 #pragma once
 
-#include <plugins/Plugin.h>
-
-class InputPlugin : public Plugin {
-public:
-    virtual bool isJointController() const = 0;
-
-    virtual void pluginFocusOutEvent() = 0;
-
-    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
-};
-
+#include <plugins/InputPlugin.h>
diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
index 5e0f3277b1..024eb86182 100644
--- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp
@@ -94,8 +94,8 @@ void SixenseManager::activate() {
     _calibrationState = CALIBRATION_STATE_IDLE;
     _avatarPosition = DEFAULT_AVATAR_POSITION;
 
-    CONTAINER->addMenu(MENU_PATH);
-    CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
+    _container->addMenu(MENU_PATH);
+    _container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
                            [this] (bool clicked) { this->setSixenseFilter(clicked); },
                            true, true);
 
@@ -136,8 +136,8 @@ void SixenseManager::deactivate() {
     InputPlugin::deactivate();
 
 #ifdef HAVE_SIXENSE
-    CONTAINER->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
-    CONTAINER->removeMenu(MENU_PATH);
+    _container->removeMenuItem(MENU_NAME, TOGGLE_SMOOTH);
+    _container->removeMenu(MENU_PATH);
 
     _poseStateMap.clear();
     _collectedSamples.clear();
@@ -319,7 +319,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
                 _avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
                 const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
                 _avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
-                CONTAINER->requestReset();
+                _container->requestReset();
                 qCDebug(inputplugins, "succeess: sixense calibration");
             }
             break;
diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
index e90006e014..69b2b5b2c6 100644
--- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
+++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp
@@ -75,8 +75,8 @@ bool ViveControllerManager::isSupported() const {
 void ViveControllerManager::activate() {
     InputPlugin::activate();
 #ifdef Q_OS_WIN
-    CONTAINER->addMenu(MENU_PATH);
-    CONTAINER->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
+    _container->addMenu(MENU_PATH);
+    _container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS,
         [this] (bool clicked) { this->setRenderControllers(clicked); },
         true, true);
 
@@ -146,8 +146,8 @@ void ViveControllerManager::deactivate() {
     InputPlugin::deactivate();
 
 #ifdef Q_OS_WIN
-    CONTAINER->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
-    CONTAINER->removeMenu(MENU_PATH);
+    _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
+    _container->removeMenu(MENU_PATH);
 
     hmdRefCount--;
 
diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h
new file mode 100644
index 0000000000..5b00391f09
--- /dev/null
+++ b/libraries/plugins/src/plugins/DisplayPlugin.h
@@ -0,0 +1,140 @@
+//
+//  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
+//
+#pragma once
+
+#include <functional>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/quaternion.hpp>
+
+#include <QtCore/QSize>
+#include <QtCore/QPoint>
+
+#include <GLMHelpers.h>
+#include <RegisteredMetaTypes.h>
+
+#include "Plugin.h"
+
+enum Eye {
+    Left,
+    Right,
+    Mono
+};
+
+/*
+ * Helper method to iterate over each eye
+ */
+template <typename F>
+void for_each_eye(F f) {
+    f(Left);
+    f(Right);
+}
+
+/*
+ * Helper method to iterate over each eye, with an additional lambda to take action between the eyes
+ */
+template <typename F, typename FF>
+void for_each_eye(F f, FF ff) {
+    f(Eye::Left);
+    ff();
+    f(Eye::Right);
+}
+
+class QWindow;
+
+#define AVERAGE_HUMAN_IPD 0.064f
+
+class DisplayPlugin : public Plugin {
+    Q_OBJECT
+public:
+    virtual bool isHmd() const { return false; }
+    virtual int getHmdScreen() const { return -1; }
+    /// By default, all HMDs are stereo
+    virtual bool isStereo() const { return isHmd(); }
+    virtual bool isThrottled() const { return false; }
+
+    // Rendering support
+
+    // Stop requesting renders, but don't do full deactivation
+    // needed to work around the issues caused by Oculus 
+    // processing messages in the middle of submitFrame
+    virtual void stop() = 0;
+
+    /**
+     *  Called by the application before the frame rendering.  Can be used for
+     *  render timing related calls (for instance, the Oculus begin frame timing
+     *  call)
+     */
+    virtual void preRender() = 0;
+    /**
+     *  Called by the application immediately before calling the display function.
+     *  For OpenGL based plugins, this is the best place to put activate the output
+     *  OpenGL context
+     */
+    virtual void preDisplay() = 0;
+
+    /**
+     *  Sends the scene texture to the display plugin.
+     */
+    virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0;
+
+    /**
+     *  Called by the application immeidately after display.  For OpenGL based
+     *  displays, this is the best place to put the buffer swap
+     */
+    virtual void finishFrame() = 0;
+
+    // Does the rendering surface have current focus?
+    virtual bool hasFocus() const = 0;
+
+    // The size of the rendering target (may be larger than the device size due to distortion)
+    virtual glm::uvec2 getRecommendedRenderSize() const = 0;
+
+    // The size of the UI
+    virtual glm::uvec2 getRecommendedUiSize() const {
+        return getRecommendedRenderSize();
+    }
+
+    // By default the aspect ratio is just the render size
+    virtual float getRecommendedAspectRatio() const {
+        return aspect(getRecommendedRenderSize());
+    }
+
+    // Stereo specific methods
+    virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const {
+        return baseProjection;
+    }
+
+    // HMD specific methods
+    // TODO move these into another class?
+    virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
+        static const glm::mat4 transform; return transform;
+    }
+
+    virtual glm::mat4 getHeadPose() const {
+        static const glm::mat4 pose; return pose;
+    }
+
+    // Needed for timewarp style features
+    virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
+        // NOOP
+    }
+
+    virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
+
+    virtual void abandonCalibration() {}
+    virtual void resetSensors() {}
+    virtual float devicePixelRatio() { return 1.0;  }
+
+
+    static const QString& MENU_PATH();
+signals:
+    void recommendedFramebufferSizeChanged(const QSize & size);
+    void requestRender();
+};
+
diff --git a/libraries/plugins/src/plugins/Forward.h b/libraries/plugins/src/plugins/Forward.h
index 1a9298d13c..78ec8fdcb3 100644
--- a/libraries/plugins/src/plugins/Forward.h
+++ b/libraries/plugins/src/plugins/Forward.h
@@ -21,3 +21,4 @@ using DisplayPluginPointer = QSharedPointer<DisplayPlugin>;
 using DisplayPluginList = QVector<DisplayPluginPointer>;
 using InputPluginPointer = QSharedPointer<InputPlugin>;
 using InputPluginList = QVector<InputPluginPointer>;
+
diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h
new file mode 100644
index 0000000000..e9d8ac8d86
--- /dev/null
+++ b/libraries/plugins/src/plugins/InputPlugin.h
@@ -0,0 +1,23 @@
+//
+//  InputPlugin.h
+//  input-plugins/src/input-plugins
+//
+//  Created by Sam Gondelman on 7/13/2015
+//  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
+
+#include "Plugin.h"
+
+class InputPlugin : public Plugin {
+public:
+    virtual bool isJointController() const = 0;
+
+    virtual void pluginFocusOutEvent() = 0;
+
+    virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0;
+};
+
diff --git a/libraries/plugins/src/plugins/Plugin.cpp b/libraries/plugins/src/plugins/Plugin.cpp
index 2c0b9fa5cf..7c30f252c9 100644
--- a/libraries/plugins/src/plugins/Plugin.cpp
+++ b/libraries/plugins/src/plugins/Plugin.cpp
@@ -7,12 +7,10 @@
 //
 #include "Plugin.h"
 
-PluginContainer* Plugin::CONTAINER{ nullptr };
-
 QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
 
 void Plugin::setContainer(PluginContainer* container) {
-    CONTAINER = container;
+    _container = container;
 }
 
 bool Plugin::isSupported() const { return true; }
diff --git a/libraries/plugins/src/plugins/Plugin.h b/libraries/plugins/src/plugins/Plugin.h
index f53d309e97..c030b1073f 100644
--- a/libraries/plugins/src/plugins/Plugin.h
+++ b/libraries/plugins/src/plugins/Plugin.h
@@ -24,7 +24,7 @@ public:
 
     virtual bool isSupported() const;
     
-    static void setContainer(PluginContainer* container);
+    void setContainer(PluginContainer* container);
 
     /// Called when plugin is initially loaded, typically at application start
     virtual void init();
@@ -57,8 +57,8 @@ public:
     virtual void loadSettings() {}
 
 protected:
-    bool _active{ false };
-    static PluginContainer* CONTAINER;
+    bool _active { false };
+    PluginContainer* _container { nullptr };
     static QString UNKNOWN_PLUGIN_ID;
 
 };
diff --git a/libraries/plugins/src/plugins/PluginManager.cpp b/libraries/plugins/src/plugins/PluginManager.cpp
index 2deb41fb13..27e326fcba 100644
--- a/libraries/plugins/src/plugins/PluginManager.cpp
+++ b/libraries/plugins/src/plugins/PluginManager.cpp
@@ -6,15 +6,54 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 #include "PluginManager.h"
+
 #include <mutex>
 
-#include "Forward.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QPluginLoader>
+
+#include "RuntimePlugin.h"
+#include "DisplayPlugin.h"
+#include "InputPlugin.h"
+#include "PluginContainer.h"
+
 
 PluginManager* PluginManager::getInstance() {
     static PluginManager _manager;
     return &_manager;
 }
 
+using Loader = QSharedPointer<QPluginLoader>;
+using LoaderList = QList<Loader>;
+
+const LoaderList& getLoadedPlugins() {
+    static std::once_flag once;
+    static LoaderList loadedPlugins;
+    std::call_once(once, [&] {
+        QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins/";
+        QDir pluginDir(pluginPath);
+        pluginDir.setFilter(QDir::Files);
+        if (pluginDir.exists()) {
+            qDebug() << "Loading runtime plugins from " << pluginPath;
+            auto candidates = pluginDir.entryList();
+            for (auto plugin : candidates) {
+                qDebug() << "Attempting plugins " << plugin;
+                QSharedPointer<QPluginLoader> loader(new QPluginLoader(pluginPath + plugin));
+                if (loader->load()) {
+                    qDebug() << "Plugins " << plugin << " success";
+                    loadedPlugins.push_back(loader);
+                }
+            }
+        }
+    });
+    return loadedPlugins;
+}
+
+PluginManager::PluginManager() {
+}
+
 // TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
 extern DisplayPluginList getDisplayPlugins();
 extern InputPluginList getInputPlugins();
@@ -23,8 +62,25 @@ extern void saveInputPluginSettings(const InputPluginList& plugins);
 const DisplayPluginList& PluginManager::getDisplayPlugins() {
     static DisplayPluginList displayPlugins;
     static std::once_flag once;
+
     std::call_once(once, [&] {
+        // Grab the built in plugins
         displayPlugins = ::getDisplayPlugins();
+
+        // Now grab the dynamic plugins
+        for (auto loader : getLoadedPlugins()) {
+            DisplayProvider* displayProvider = qobject_cast<DisplayProvider*>(loader->instance());
+            if (displayProvider) {
+                for (auto displayPlugin : displayProvider->getDisplayPlugins()) {
+                    displayPlugins.push_back(displayPlugin);
+                }
+            }
+        }
+        auto& container = PluginContainer::getInstance();
+        for (auto plugin : displayPlugins) {
+            plugin->setContainer(&container);
+        }
+
     });
     return displayPlugins;
 }
@@ -34,6 +90,21 @@ const InputPluginList& PluginManager::getInputPlugins() {
     static std::once_flag once;
     std::call_once(once, [&] {
         inputPlugins = ::getInputPlugins();
+
+        // Now grab the dynamic plugins
+        for (auto loader : getLoadedPlugins()) {
+            InputProvider* inputProvider = qobject_cast<InputProvider*>(loader->instance());
+            if (inputProvider) {
+                for (auto inputPlugin : inputProvider->getInputPlugins()) {
+                    inputPlugins.push_back(inputPlugin);
+                }
+            }
+        }
+
+        auto& container = PluginContainer::getInstance();
+        for (auto plugin : inputPlugins) {
+            plugin->setContainer(&container);
+        }
     });
     return inputPlugins;
 }
diff --git a/libraries/plugins/src/plugins/PluginManager.h b/libraries/plugins/src/plugins/PluginManager.h
index 09dcc9d107..17619a93c0 100644
--- a/libraries/plugins/src/plugins/PluginManager.h
+++ b/libraries/plugins/src/plugins/PluginManager.h
@@ -12,6 +12,7 @@
 class PluginManager : public QObject {
 public:
   static PluginManager* getInstance();
+  PluginManager();
 
   const DisplayPluginList& getDisplayPlugins();
   const InputPluginList& getInputPlugins();
diff --git a/libraries/plugins/src/plugins/RuntimePlugin.h b/libraries/plugins/src/plugins/RuntimePlugin.h
new file mode 100644
index 0000000000..d7bf31ea28
--- /dev/null
+++ b/libraries/plugins/src/plugins/RuntimePlugin.h
@@ -0,0 +1,36 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/24
+//  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
+
+#include <assert.h>
+
+#include <QString>
+#include <QObject>
+
+#include "Forward.h"
+
+class DisplayProvider {
+public:
+    virtual ~DisplayProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() = 0;
+};
+
+#define DisplayProvider_iid "com.highfidelity.plugins.display"
+Q_DECLARE_INTERFACE(DisplayProvider, DisplayProvider_iid)
+
+
+class InputProvider {
+public:
+    virtual ~InputProvider() {}
+    virtual InputPluginList getInputPlugins() = 0;
+};
+
+#define InputProvider_iid "com.highfidelity.plugins.input"
+Q_DECLARE_INTERFACE(InputProvider, InputProvider_iid)
+
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644
index 0000000000..55b18b122c
--- /dev/null
+++ b/plugins/CMakeLists.txt
@@ -0,0 +1,18 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  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
+#
+
+# add the plugin directories
+file(GLOB PLUGIN_SUBDIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*")
+list(REMOVE_ITEM PLUGIN_SUBDIRS "CMakeFiles")
+
+foreach(DIR ${PLUGIN_SUBDIRS})
+  if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${DIR}")
+    add_subdirectory(${DIR})
+  endif()
+endforeach()
+
diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt
new file mode 100644
index 0000000000..62999cbb7e
--- /dev/null
+++ b/plugins/oculus/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  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
+#
+
+if (WIN32)
+
+    set(TARGET_NAME oculus)
+    setup_hifi_plugin()
+    link_hifi_libraries(shared gl plugins display-plugins)
+    
+    include_hifi_library_headers(octree)
+    
+    add_dependency_external_projects(LibOVR)
+    find_package(LibOVR REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
+
+endif()
\ No newline at end of file
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp
similarity index 95%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp
rename to plugins/oculus/src/OculusBaseDisplayPlugin.cpp
index 859a4a810a..4c80b9a51d 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.cpp
+++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp
@@ -61,6 +61,14 @@ bool OculusBaseDisplayPlugin::isSupported() const {
 #endif
 }
 
+// DLL based display plugins MUST initialize GLEW inside the DLL code.
+void OculusBaseDisplayPlugin::customizeContext() {
+    glewExperimental = true;
+    GLenum err = glewInit();
+    glGetError();
+    WindowOpenGLDisplayPlugin::customizeContext();
+}
+
 void OculusBaseDisplayPlugin::init() {
 }
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h
similarity index 96%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h
rename to plugins/oculus/src/OculusBaseDisplayPlugin.h
index 6307f6bbf9..ba1924bfff 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusBaseDisplayPlugin.h
+++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h
@@ -7,7 +7,7 @@
 //
 #pragma once
 
-#include "../WindowOpenGLDisplayPlugin.h"
+#include <display-plugins/WindowOpenGLDisplayPlugin.h>
 
 #include <QTimer>
 
@@ -35,6 +35,7 @@ public:
     virtual float getIPD() const override final;
 
 protected:
+    virtual void customizeContext() override;
     virtual void preRender() override final;
     virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.cpp
rename to plugins/oculus/src/OculusDebugDisplayPlugin.cpp
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDebugDisplayPlugin.h
rename to plugins/oculus/src/OculusDebugDisplayPlugin.h
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp
similarity index 97%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp
rename to plugins/oculus/src/OculusDisplayPlugin.cpp
index 3e2290f104..923b8bde6e 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.cpp
+++ b/plugins/oculus/src/OculusDisplayPlugin.cpp
@@ -7,11 +7,14 @@
 //
 #include "OculusDisplayPlugin.h"
 
-#include <QGLWidget>
+#include <QtOpenGL/QGLWidget>
+
+// FIXME get rid of this
+#include <gl/Config.h>
+#include <plugins/PluginContainer.h>
 
 #include "OculusHelpers.h"
 
-#include <plugins/PluginContainer.h>
 
 #if (OVR_MAJOR_VERSION >= 6)
 
@@ -142,16 +145,16 @@ static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate";
 
 void OculusDisplayPlugin::activate() {
 
-    CONTAINER->addMenuItem(MENU_PATH(), MONO_PREVIEW,
+    _container->addMenuItem(MENU_PATH(), MONO_PREVIEW,
         [this](bool clicked) {
             _monoPreview = clicked;
         }, true, true);
-    CONTAINER->removeMenu(FRAMERATE);
+    _container->removeMenu(FRAMERATE);
     OculusBaseDisplayPlugin::activate();
 }
 
 void OculusDisplayPlugin::customizeContext() {
-    WindowOpenGLDisplayPlugin::customizeContext();
+    OculusBaseDisplayPlugin::customizeContext();
 #if (OVR_MAJOR_VERSION >= 6)
     _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd));
     _sceneFbo->Init(getRecommendedRenderSize());
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusDisplayPlugin.h
rename to plugins/oculus/src/OculusDisplayPlugin.h
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.cpp
rename to plugins/oculus/src/OculusHelpers.cpp
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h
similarity index 100%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusHelpers.h
rename to plugins/oculus/src/OculusHelpers.h
diff --git a/plugins/oculus/src/OculusProvider.cpp b/plugins/oculus/src/OculusProvider.cpp
new file mode 100644
index 0000000000..40dfb9df9a
--- /dev/null
+++ b/plugins/oculus/src/OculusProvider.cpp
@@ -0,0 +1,54 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/25
+//  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 <mutex>
+
+#include <QtCore/QObject>
+#include <QtCore/QtPlugin>
+#include <QtCore/QStringList>
+
+#include <plugins/RuntimePlugin.h>
+#include <plugins/DisplayPlugin.h>
+
+#include "OculusDisplayPlugin.h"
+#include "OculusDebugDisplayPlugin.h"
+
+class OculusProvider : public QObject, public DisplayProvider
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
+    Q_INTERFACES(DisplayProvider)
+
+public:
+    OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
+    virtual ~OculusProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() override {
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            DisplayPluginPointer plugin(new OculusDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+
+            // Windows Oculus Simulator... uses head tracking and the same rendering 
+            // as the connected hardware, but without using the SDK to display to the 
+            // Rift.  Useful for debugging Rift performance with nSight.
+            plugin = DisplayPluginPointer(new OculusDebugDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+        });
+        return _displayPlugins;
+    }
+
+private:
+    DisplayPluginList _displayPlugins;
+};
+
+#include "OculusProvider.moc"
diff --git a/plugins/oculus/src/oculus.json b/plugins/oculus/src/oculus.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/plugins/oculus/src/oculus.json
@@ -0,0 +1 @@
+{}
diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt
new file mode 100644
index 0000000000..bf9d22410d
--- /dev/null
+++ b/plugins/oculusLegacy/CMakeLists.txt
@@ -0,0 +1,22 @@
+#
+#  Created by Bradley Austin Davis on 2015/10/25
+#  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
+#
+
+if (NOT WIN32)
+
+    set(TARGET_NAME oculusLegacy)
+    setup_hifi_plugin()
+    link_hifi_libraries(shared gl plugins display-plugins)
+    
+    include_hifi_library_headers(octree)
+    
+    add_dependency_external_projects(LibOVR)
+    find_package(LibOVR REQUIRED)
+    target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
+    target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES})
+
+endif()
\ No newline at end of file
diff --git a/plugins/oculusLegacy/src/OculusHelpers.cpp b/plugins/oculusLegacy/src/OculusHelpers.cpp
new file mode 100644
index 0000000000..fff2a38344
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusHelpers.cpp
@@ -0,0 +1,9 @@
+//
+//  Created by Bradley Austin Davis on 2015/08/08
+//  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 "OculusHelpers.h"
diff --git a/plugins/oculusLegacy/src/OculusHelpers.h b/plugins/oculusLegacy/src/OculusHelpers.h
new file mode 100644
index 0000000000..b4bcdc1511
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusHelpers.h
@@ -0,0 +1,85 @@
+//
+//  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
+
+#include <OVR_CAPI_GL.h>
+#include <GLMHelpers.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+
+// Convenience method for looping over each eye with a lambda
+template <typename Function>
+inline void ovr_for_each_eye(Function function) {
+    for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
+        eye < ovrEyeType::ovrEye_Count;
+        eye = static_cast<ovrEyeType>(eye + 1)) {
+        function(eye);
+    }
+}
+
+inline glm::mat4 toGlm(const ovrMatrix4f & om) {
+    return glm::transpose(glm::make_mat4(&om.M[0][0]));
+}
+
+inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
+    return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
+}
+
+inline glm::vec3 toGlm(const ovrVector3f & ov) {
+    return glm::make_vec3(&ov.x);
+}
+
+inline glm::vec2 toGlm(const ovrVector2f & ov) {
+    return glm::make_vec2(&ov.x);
+}
+
+inline glm::uvec2 toGlm(const ovrSizei & ov) {
+    return glm::uvec2(ov.w, ov.h);
+}
+
+inline glm::quat toGlm(const ovrQuatf & oq) {
+    return glm::make_quat(&oq.x);
+}
+
+inline glm::mat4 toGlm(const ovrPosef & op) {
+    glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
+    glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
+    return translation * orientation;
+}
+
+inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
+    ovrMatrix4f result;
+    glm::mat4 transposed(glm::transpose(m));
+    memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
+    return result;
+}
+
+inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
+    return{ v.x, v.y, v.z };
+}
+
+inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
+    return{ v.x, v.y };
+}
+
+inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
+    return{ (int)v.x, (int)v.y };
+}
+
+inline ovrQuatf ovrFromGlm(const glm::quat & q) {
+    return{ q.x, q.y, q.z, q.w };
+}
+
+inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
+    glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
+    glm::quat orientation = glm::quat_cast(m);
+    ovrPosef result;
+    result.Orientation = ovrFromGlm(orientation);
+    result.Position = ovrFromGlm(translation);
+    return result; 
+}
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
similarity index 90%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp
rename to plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
index 205444397f..5a253cdbbf 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.cpp
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp
@@ -42,10 +42,8 @@ uvec2 OculusLegacyDisplayPlugin::getRecommendedRenderSize() const {
 }
 
 void OculusLegacyDisplayPlugin::preRender() {
-#if (OVR_MAJOR_VERSION == 5)
     ovrHmd_GetEyePoses(_hmd, _frameIndex, _eyeOffsets, _eyePoses, &_trackingState);
     ovrHmd_BeginFrame(_hmd, _frameIndex);
-#endif
     WindowOpenGLDisplayPlugin::preRender();
 }
 
@@ -54,32 +52,21 @@ glm::mat4 OculusLegacyDisplayPlugin::getProjection(Eye eye, const glm::mat4& bas
 }
 
 void OculusLegacyDisplayPlugin::resetSensors() {
-#if (OVR_MAJOR_VERSION == 5)
     ovrHmd_RecenterPose(_hmd);
-#endif
 }
 
 glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
-#if (OVR_MAJOR_VERSION == 5)
     return toGlm(_eyePoses[eye]);
-#else
-    return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye);
-#endif
 }
 
 // Should NOT be used for rendering as this will mess up timewarp.  Use the getModelview() method above for
 // any use of head poses for rendering, ensuring you use the correct eye
 glm::mat4 OculusLegacyDisplayPlugin::getHeadPose() const {
-#if (OVR_MAJOR_VERSION == 5)
     return toGlm(_trackingState.HeadPose.ThePose);
-#else
-    return WindowOpenGLDisplayPlugin::getHeadPose();
-#endif
 }
 
 
 bool OculusLegacyDisplayPlugin::isSupported() const {
-#if (OVR_MAJOR_VERSION == 5)
     if (!ovr_Initialize(nullptr)) {
         return false;
     }
@@ -104,14 +91,10 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
   
     ovr_Shutdown();
     return result;
-#else 
-    return false;
-#endif
 }
 
 void OculusLegacyDisplayPlugin::activate() {
-#if (OVR_MAJOR_VERSION == 5)
-    if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
+    if (!(ovr_Initialize(nullptr))) {
         Q_ASSERT(false);
         qFatal("Failed to Initialize SDK");
     }
@@ -149,8 +132,8 @@ void OculusLegacyDisplayPlugin::activate() {
 
     _frameIndex = 0;
 
-    if (!OVR_SUCCESS(ovrHmd_ConfigureTracking(_hmd,
-        ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) {
+    if (!ovrHmd_ConfigureTracking(_hmd,
+        ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) {
         qFatal("Could not attach to sensor device");
     }
 
@@ -158,7 +141,7 @@ void OculusLegacyDisplayPlugin::activate() {
 
     int screen = getHmdScreen();
     if (screen != -1) {
-        CONTAINER->setFullscreen(qApp->screens()[screen]);
+        _container->setFullscreen(qApp->screens()[screen]);
     }
     
     _window->installEventFilter(this);
@@ -189,11 +172,9 @@ void OculusLegacyDisplayPlugin::activate() {
     #endif
         ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
     Q_ASSERT(result);
-#endif
 }
 
 void OculusLegacyDisplayPlugin::deactivate() {
-#if (OVR_MAJOR_VERSION == 5)
     _window->removeEventFilter(this);
 
     WindowOpenGLDisplayPlugin::deactivate();
@@ -202,12 +183,11 @@ void OculusLegacyDisplayPlugin::deactivate() {
     if (_hmdScreen >= 0) {
         riftScreen = qApp->screens()[_hmdScreen];
     }
-    CONTAINER->unsetFullscreen(riftScreen);
+    _container->unsetFullscreen(riftScreen);
     
     ovrHmd_Destroy(_hmd);
     _hmd = nullptr;
     ovr_Shutdown();
-#endif
 }
 
 void OculusLegacyDisplayPlugin::preDisplay() {
@@ -216,17 +196,14 @@ void OculusLegacyDisplayPlugin::preDisplay() {
 
 void OculusLegacyDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
     ++_frameIndex;
-#if (OVR_MAJOR_VERSION == 5)
     ovr_for_each_eye([&](ovrEyeType eye) {
         reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = finalTexture;
     });
     ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures);
-#endif
 }
 
 // Pass input events on to the application
 bool OculusLegacyDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
-#if (OVR_MAJOR_VERSION == 5)
     if (!_hswDismissed && (event->type() == QEvent::KeyPress)) {
         static ovrHSWDisplayState hswState;
         ovrHmd_GetHSWDisplayState(_hmd, &hswState);
@@ -236,7 +213,6 @@ bool OculusLegacyDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
             _hswDismissed = true;
         }
     }    
-#endif
     return WindowOpenGLDisplayPlugin::eventFilter(receiver, event);
 }
 
diff --git a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
similarity index 97%
rename from libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h
rename to plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
index 9e2e47f434..2e95cee9bb 100644
--- a/libraries/display-plugins/src/display-plugins/oculus/OculusLegacyDisplayPlugin.h
+++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h
@@ -7,7 +7,7 @@
 //
 #pragma once
 
-#include "../WindowOpenGLDisplayPlugin.h"
+#include <display-plugins/WindowOpenGLDisplayPlugin.h>
 
 #include <QTimer>
 
diff --git a/plugins/oculusLegacy/src/OculusProvider.cpp b/plugins/oculusLegacy/src/OculusProvider.cpp
new file mode 100644
index 0000000000..606563e0ad
--- /dev/null
+++ b/plugins/oculusLegacy/src/OculusProvider.cpp
@@ -0,0 +1,45 @@
+//
+//  Created by Bradley Austin Davis on 2015/10/25
+//  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 <mutex>
+
+#include <QtCore/QObject>
+#include <QtCore/QtPlugin>
+#include <QtCore/QStringList>
+
+#include <plugins/RuntimePlugin.h>
+#include <plugins/DisplayPlugin.h>
+
+#include "OculusLegacyDisplayPlugin.h"
+
+class OculusProvider : public QObject, public DisplayProvider
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID DisplayProvider_iid FILE "oculus.json")
+    Q_INTERFACES(DisplayProvider)
+
+public:
+    OculusProvider(QObject* parent = nullptr) : QObject(parent) {}
+    virtual ~OculusProvider() {}
+
+    virtual DisplayPluginList getDisplayPlugins() override {
+        static std::once_flag once;
+        std::call_once(once, [&] {
+            DisplayPluginPointer plugin(new OculusLegacyDisplayPlugin());
+            if (plugin->isSupported()) {
+                _displayPlugins.push_back(plugin);
+            }
+        });
+        return _displayPlugins;
+    }
+
+private:
+    DisplayPluginList _displayPlugins;
+};
+
+#include "OculusProvider.moc"
diff --git a/plugins/oculusLegacy/src/oculus.json b/plugins/oculusLegacy/src/oculus.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/plugins/oculusLegacy/src/oculus.json
@@ -0,0 +1 @@
+{}
diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp
index a7b1be15ca..139d9b282c 100644
--- a/tests/controllers/src/main.cpp
+++ b/tests/controllers/src/main.cpp
@@ -80,9 +80,6 @@ using namespace controller;
 class PluginContainerProxy : public QObject, PluginContainer {
     Q_OBJECT
 public:
-    PluginContainerProxy() {
-        Plugin::setContainer(this);
-    }
     virtual ~PluginContainerProxy() {}
     virtual void addMenu(const QString& menuName) override {}
     virtual void removeMenu(const QString& menuName) override {}