diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt
index 8e0328a87db6c1d9a382cb74f536d50060bb6e19..c5e93b08bb42c14df039f0207bb62e2e8f0d68e2 100644
--- a/apps/OpenSpace/CMakeLists.txt
+++ b/apps/OpenSpace/CMakeLists.txt
@@ -1,26 +1,28 @@
-#########################################################################################
-#                                                                                       #
-# OpenSpace                                                                             #
-#                                                                                       #
-# Copyright (c) 2014-2015                                                               #
-#                                                                                       #
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this  #
-# software and associated documentation files (the "Software"), to deal in the Software #
-# without restriction, including without limitation the rights to use, copy, modify,    #
-# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    #
-# permit persons to whom the Software is furnished to do so, subject to the following   #
-# conditions:                                                                           #
-#                                                                                       #
-# The above copyright notice and this permission notice shall be included in all copies #
-# or substantial portions of the Software.                                              #
-#                                                                                       #
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   #
-# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         #
-# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    #
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  #
-# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  #
-# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         #
-#########################################################################################
+##########################################################################################
+#                                                                                        #
+# OpenSpace                                                                              #
+#                                                                                        #
+# Copyright (c) 2014-2017                                                                #
+#                                                                                        #
+# Permission is hereby granted, free of charge, to any person obtaining a copy of this   #
+# software and associated documentation files (the "Software"), to deal in the Software  #
+# without restriction, including without limitation the rights to use, copy, modify,     #
+# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to     #
+# permit persons to whom the Software is furnished to do so, subject to the following    #
+# conditions:                                                                            #
+#                                                                                        #
+# The above copyright notice and this permission notice shall be included in all copies  #
+# or substantial portions of the Software.                                               #
+#                                                                                        #
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,    #
+# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A          #
+# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT     #
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF   #
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE   #
+# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                          #
+##########################################################################################
+
+include(${GHOUL_BASE_DIR}/support/cmake/CopySharedLibraries.cmake) 
 
 set(APPLICATION_NAME OpenSpace)
 set(APPLICATION_LINK_TO_OPENSPACE ON)
@@ -29,10 +31,13 @@ if (WIN32)
     set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
 endif ()
 
-##OpenVR section start####################
+
+########################
+# OpenVR section start #
+########################
 option(OPENSPACE_OPENVR_SUPPORT "Build OpenSpace application with OpenVR support" OFF)
 
-if(OPENSPACE_OPENVR_SUPPORT)
+if (OPENSPACE_OPENVR_SUPPORT)
     set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OPENSPACE_EXT_DIR}/sgct/cmake/modules/")
     
     find_package(OpenVR REQUIRED)
@@ -61,17 +66,60 @@ else()
     set(OPENVR_LIBRARY "")
     set(SGCT_OPENVR_DEFINITIONS "")
 endif()
-##OpenVR section end####################
+########################
+#  OpenVR section end  #
+########################
+
+########################
+# Spout section  start #
+########################
+if (WIN32)
+    option(OPENSPACE_SPOUT_SUPPORT "Build OpenSpace application with Spout support" OFF)
+endif ()
+
+set(SPOUT_INCLUDE_DIRS "")
+set(SPOUT_LIBRARY "")
+set(SPOUT_DEFINITIONS "")
+if (OPENSPACE_SPOUT_SUPPORT)
+    set(SPOUT_INCLUDE_DIRS ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout)
+    set(SPOUT_LIBRARY ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout/SpoutLibrary.lib)
+    set(SPOUT_DEFINITIONS "OPENSPACE_HAS_SPOUT")
+endif ()
+
+########################
+#  Spout section  end  #
+########################
 
 add_executable(${APPLICATION_NAME}
     ${SGCT_OPENVR_FILES}
     ${OPENSPACE_APPS_DIR}/OpenSpace/main.cpp
     ${RESOURCE_FILE}
 )
-target_include_directories(${APPLICATION_NAME} PUBLIC ${OPENSPACE_BASE_DIR}/include ${OPENVR_INCLUDE_DIRS} ${SGCT_OPENVR_INCLUDE_DIRECTORY})
-target_link_libraries(${APPLICATION_NAME} libOpenSpace ${OPENVR_LIBRARY})
-target_compile_definitions(${APPLICATION_NAME} PUBLIC ${SGCT_OPENVR_DEFINITIONS})
+if (OPENSPACE_SPOUT_SUPPORT)
+    copy_files(
+        ${APPLICATION_NAME}
+        ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout/SpoutLibrary.dll
+    )
+endif ()
+
+target_include_directories(
+    ${APPLICATION_NAME} PUBLIC
+    ${OPENSPACE_BASE_DIR}/include
+    ${OPENVR_INCLUDE_DIRS}
+    ${SGCT_OPENVR_INCLUDE_DIRECTORY}
+    ${SPOUT_INCLUDE_DIRS}
+)
 
+target_link_libraries(${APPLICATION_NAME}
+    libOpenSpace
+    ${OPENVR_LIBRARY}
+    ${SPOUT_LIBRARY}
+)
+
+target_compile_definitions(${APPLICATION_NAME} PUBLIC
+    ${SGCT_OPENVR_DEFINITIONS}
+    ${SPOUT_DEFINITIONS}
+)
 
 if (MSVC)
     target_link_libraries(${APPLICATION_NAME} Dbghelp.lib)
diff --git a/apps/OpenSpace/ext/readme.md b/apps/OpenSpace/ext/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..2b6c3218215fcc170f420ff9c574459a4c1d4374
--- /dev/null
+++ b/apps/OpenSpace/ext/readme.md
@@ -0,0 +1,8 @@
+The spout folder is a copy of the folder:
+SpoutSDK/Source in the repository:
+https://github.com/leadedge/Spout2.git/SpoutSDK/Source/SPOUT_LIBRARY/Binaries
+and
+https://github.com/leadedge/Spout2.git/SpoutSDK/Source/SPOUT_LIBRARY/Include
+
+Last update:
+https://github.com/leadedge/Spout2/commit/28dbea6059cd7968c4d2b296d6739a5fdebe9104
diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.dll b/apps/OpenSpace/ext/spout/SpoutLibrary.dll
new file mode 100644
index 0000000000000000000000000000000000000000..36aca87f878bfa07156e03006923780a91ed05db
Binary files /dev/null and b/apps/OpenSpace/ext/spout/SpoutLibrary.dll differ
diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.h b/apps/OpenSpace/ext/spout/SpoutLibrary.h
new file mode 100644
index 0000000000000000000000000000000000000000..d50c0a11060348746be48b2cedd598bb98534979
--- /dev/null
+++ b/apps/OpenSpace/ext/spout/SpoutLibrary.h
@@ -0,0 +1,90 @@
+//
+//	SpoutLibrary.dll
+//
+//	Spout SDK dll compatible with any C++ compiler
+//
+
+#include <windows.h>
+#include <GL/GL.h>
+
+#define SPOUTLIBRARY_EXPORTS // defined for this DLL. The application imports rather than exports
+
+#ifdef SPOUTLIBRARY_EXPORTS
+#define SPOUTAPI __declspec(dllexport)
+#else
+#define SPOUTAPI __declspec(dllimport)
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// COM-Like abstract interface.
+// This interface doesn't require __declspec(dllexport/dllimport) specifier.
+// Method calls are dispatched via virtual table.
+// Any C++ compiler can use it.
+// Instances are obtained via factory function.
+//
+struct SPOUTLIBRARY
+{
+	// Sender
+	virtual bool CreateSender(const char *Sendername, unsigned int width, unsigned int height, DWORD dwFormat = 0) = 0;
+	virtual void ReleaseSender(DWORD dwMsec = 0) = 0;
+	virtual bool UpdateSender(const char* Sendername, unsigned int width, unsigned int height) = 0;
+	virtual bool SendTexture(GLuint TextureID, GLuint TextureTarget, unsigned int width, unsigned int height, bool bInvert = true, GLuint HostFBO = 0) = 0;
+	virtual bool SendImage(const unsigned char* pixels, unsigned int width, unsigned int height, GLenum glFormat = GL_RGBA, bool bInvert=false) = 0;
+
+	// Receiver
+	virtual bool CreateReceiver(char* Sendername, unsigned int &width, unsigned int &height, bool bUseActive = false) = 0;
+	virtual void ReleaseReceiver() = 0;
+	virtual bool ReceiveTexture(char* Sendername, unsigned int &width, unsigned int &height, GLuint TextureID = 0, GLuint TextureTarget = 0, bool bInvert = false, GLuint HostFBO = 0) = 0;
+	virtual bool ReceiveImage(char* Sendername, unsigned int &width, unsigned int &height, unsigned char* pixels, GLenum glFormat = GL_RGBA, bool bInvert = false, GLuint HostFBO=0) = 0;
+	virtual bool CheckReceiver(char* Sendername, unsigned int &width, unsigned int &height, bool &bConnected) = 0;
+	virtual bool GetImageSize(char* sendername, unsigned int &width, unsigned int &height, bool &bMemoryMode) = 0;	
+
+	virtual bool BindSharedTexture() = 0;
+	virtual bool UnBindSharedTexture() = 0;
+	
+	virtual bool DrawSharedTexture(float max_x = 1.0, float max_y = 1.0, float aspect = 1.0, bool bInvert = true) = 0;
+	virtual bool DrawToSharedTexture(GLuint TextureID, GLuint TextureTarget, unsigned int width, unsigned int height, float max_x = 1.0, float max_y = 1.0, float aspect = 1.0, bool bInvert = false, GLuint HostFBO = 0) = 0;
+
+	virtual int  GetSenderCount() = 0;
+	virtual bool GetSenderName(int index, char* sendername, int MaxSize = 256) = 0;
+	virtual bool GetSenderInfo(const char* sendername, unsigned int &width, unsigned int &height, HANDLE &dxShareHandle, DWORD &dwFormat) = 0;
+	virtual bool GetActiveSender(char* Sendername) = 0;
+	virtual bool SetActiveSender(const char* Sendername) = 0;
+	
+	// Utilities
+	virtual bool SetDX9(bool bDX9 = true) = 0; // User request to use DirectX 9 (default is DirectX 11)
+	virtual bool GetDX9() = 0; // Return the flag that has been set
+	virtual bool SetMemoryShareMode(bool bMem = true) = 0;
+	virtual bool GetMemoryShareMode() = 0;
+	virtual int  GetMaxSenders() = 0; // Get maximum senders allowed
+	virtual void SetMaxSenders(int maxSenders) = 0; // Set maximum senders allowed
+	virtual bool GetHostPath(const char *sendername, char *hostpath, int maxchars) = 0; // The path of the host that produced the sender
+	virtual int  GetVerticalSync() = 0;
+	virtual bool SetVerticalSync(bool bSync = true) = 0;
+	virtual bool SelectSenderPanel(const char* message = NULL) = 0;
+
+	// Access to globals
+	virtual bool GetSpoutSenderName(char * sendername, int maxchars) = 0; // get the global sender name
+	virtual bool IsSpoutInitialized() = 0; // has the class been initialized
+	
+	// Adapter functions
+	virtual int  GetNumAdapters() = 0; // Get the number of graphics adapters in the system
+	virtual bool GetAdapterName(int index, char *adaptername, int maxchars) = 0; // Get an adapter name
+	virtual bool SetAdapter(int index = 0) = 0; // Set required graphics adapter for output
+	virtual int  GetAdapter() = 0; // Get the SpoutDirectX global adapter index
+	
+	// Library release function
+    virtual void Release() = 0;
+
+};
+
+
+// Handle type. In C++ language the interface type is used.
+typedef SPOUTLIBRARY* SPOUTHANDLE;
+
+// Factory function that creates instances of the SPOUT object.
+extern "C" SPOUTAPI SPOUTHANDLE WINAPI GetSpout(VOID);
+
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.lib b/apps/OpenSpace/ext/spout/SpoutLibrary.lib
new file mode 100644
index 0000000000000000000000000000000000000000..435552b19504058fc0dbb2c10f17c6c4405d6c30
Binary files /dev/null and b/apps/OpenSpace/ext/spout/SpoutLibrary.lib differ
diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp
index 77683731967c914619c0c163abcb077925caa39c..73fe62041917c0829c6a9f9daead45ec844b9c98 100644
--- a/apps/OpenSpace/main.cpp
+++ b/apps/OpenSpace/main.cpp
@@ -52,12 +52,16 @@
 #include <SGCTOpenVR.h>
 #endif // OPENVR_SUPPORT
 
+#ifdef OPENSPACE_HAS_SPOUT
+#include "SpoutLibrary.h"
+#endif // OPENSPACE_HAS_SPOUT
+
+
 #define DEVELOPER_MODE
 
 namespace {
     
 const char* _loggerCat = "main";
-
 sgct::Engine* SgctEngine;
 
 #ifdef WIN32
@@ -131,6 +135,36 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) {
 sgct::SGCTWindow* FirstOpenVRWindow = nullptr;
 #endif
 
+#ifdef OPENSPACE_HAS_SPOUT
+
+const char* SpoutTag = "Spout";
+
+/**
+* This struct stores all information about a single render window.
+*/
+struct SpoutWindow {
+    struct SpoutData {
+        SPOUTHANDLE handle = nullptr;
+        bool initialized = false;
+    };
+
+    /// The left framebuffer (or main, if there is no stereo rendering)
+    SpoutData leftOrMain;
+
+    /// The right framebuffer
+    SpoutData right;
+
+    /// The window ID of this windows
+    size_t windowId = size_t(-1);
+};
+
+/// The list of all windows with spout senders
+std::vector<SpoutWindow> SpoutWindows;
+
+#endif // OPENSPACE_HAS_SPOUT
+
+
+
 std::pair<int, int> supportedOpenGLVersion() {
     // Just create a window in order to retrieve the available OpenGL version before we
     // create the real window
@@ -200,18 +234,69 @@ void mainInitFunc() {
     // Set the clear color for all non-linear projection viewports
     // @CLEANUP:  Why is this necessary?  We can set the clear color in the configuration
     // files --- abock
-    size_t nWindows = SgctEngine->getNumberOfWindows();
+    const size_t nWindows = SgctEngine->getNumberOfWindows();
     for (size_t i = 0; i < nWindows; ++i) {
         sgct::SGCTWindow* w = SgctEngine->getWindowPtr(i);
-        size_t nViewports = w->getNumberOfViewports();
+        const size_t nViewports = w->getNumberOfViewports();
         for (size_t j = 0; j < nViewports; ++j) {
             sgct_core::Viewport* v = w->getViewport(j);
             ghoul_assert(v != nullptr, "Number of reported viewports was incorrect");
             sgct_core::NonLinearProjection* p = v->getNonLinearProjectionPtr();
-            if (p)
+            if (p) {
                 p->setClearColor(glm::vec4(0.f, 0.f, 0.f, 1.f));
+            }
+        }
+    }
+
+#ifdef OPENSPACE_HAS_SPOUT
+    //SpoutWindows.resize(nWindows);
+    for (size_t i = 0; i < nWindows; ++i) {
+        auto windowPtr = SgctEngine->getWindowPtr(i);
+
+        if (!windowPtr->checkIfTagExists(SpoutTag)) {
+            continue;
+        }
+
+        SpoutWindow w;
+
+        w.windowId = i;
+
+        sgct::SGCTWindow::StereoMode sm = windowPtr->getStereoMode();
+        if (sm != sgct::SGCTWindow::No_Stereo && sm < sgct::SGCTWindow::Side_By_Side_Stereo) {
+            auto& left = w.leftOrMain;
+            left.handle = GetSpout();
+
+            left.initialized = left.handle->CreateSender(
+                (windowPtr->getName() + "_left").c_str(),
+                windowPtr->getXFramebufferResolution(),
+                windowPtr->getYFramebufferResolution()
+            );
+
+            auto& right = w.right;
+            right.handle = GetSpout();
+
+            right.initialized = right.handle->CreateSender(
+                (windowPtr->getName() + "_right").c_str(),
+                windowPtr->getXFramebufferResolution(),
+                windowPtr->getYFramebufferResolution()
+            );
         }
+        else {
+            auto windowPtr = SgctEngine->getWindowPtr(i);
+
+            auto& main = w.leftOrMain;
+            main.handle = GetSpout();
+
+            main.initialized = main.handle->CreateSender(
+                windowPtr->getName().c_str(),
+                windowPtr->getXFramebufferResolution(),
+                windowPtr->getYFramebufferResolution()
+            );
+        }
+
+        SpoutWindows.push_back(std::move(w));
     }
+#endif // OPENSPACE_HAS_SPOUT
     LTRACE("main::mainInitFunc(end)");
 }
 
@@ -231,7 +316,7 @@ void mainPostSyncPreDrawFunc() {
         // Update pose matrices for all tracked OpenVR devices once per frame
         sgct::SGCTOpenVR::updatePoses();
     }
-#endif
+#endif // OPENVR_SUPPORT
 
     LTRACE("main::postSynchronizationPreDraw(end)");
 }
@@ -274,9 +359,38 @@ void mainPostDrawFunc() {
         // Copy the first OpenVR window to the HMD
         sgct::SGCTOpenVR::copyWindowToHMD(FirstOpenVRWindow);
     }
-#endif
+#endif // OPENVR_SUPPORT
 
     OsEng.postDraw();
+
+#ifdef OPENSPACE_HAS_SPOUT
+    for (const SpoutWindow& w : SpoutWindows) {
+        sgct::SGCTWindow* window = SgctEngine->getWindowPtr(w.windowId);
+        if (w.leftOrMain.initialized) {
+            GLuint texId = window->getFrameBufferTexture(sgct::Engine::LeftEye);
+            glBindTexture(GL_TEXTURE_2D, texId);
+            w.leftOrMain.handle->SendTexture(
+                texId,
+                GL_TEXTURE_2D,
+                window->getXFramebufferResolution(),
+                window->getYFramebufferResolution()
+            );
+        }
+
+        if (w.right.initialized) {
+            GLuint texId = window->getFrameBufferTexture(sgct::Engine::RightEye);
+            glBindTexture(GL_TEXTURE_2D, texId);
+            w.right.handle->SendTexture(
+                texId,
+                GL_TEXTURE_2D,
+                window->getXFramebufferResolution(),
+                window->getYFramebufferResolution()
+            );
+        }
+    }
+    glBindTexture(GL_TEXTURE_2D, 0);
+#endif // OPENSPACE_HAS_SPOUT
+
     LTRACE("main::mainPostDrawFunc(end)");
 }
 
@@ -449,6 +563,25 @@ int main_main(int argc, char** argv) {
         
         LDEBUG("Destroying SGCT Engine");
         delete SgctEngine;
+
+
+#ifdef OPENVR_SUPPORT
+        // Clean up OpenVR
+        sgct::SGCTOpenVR::shutdown();
+#endif
+
+#ifdef OPENSPACE_HAS_SPOUT
+        for (SpoutWindow& w : SpoutWindows) {
+            if (w.leftOrMain.handle) {
+                w.leftOrMain.handle->ReleaseReceiver();
+                w.leftOrMain.handle->Release();
+            }
+            if (w.right.handle) {
+                w.right.handle->ReleaseReceiver();
+                w.right.handle->Release();
+            }
+        }
+#endif // OPENSPACE_HAS_SPOUT
     };
     
     bool initSuccess = SgctEngine->init(versionMapping[glVersion]);
@@ -466,11 +599,6 @@ int main_main(int argc, char** argv) {
     
     cleanup();
     
-#ifdef OPENVR_SUPPORT
-    // Clean up OpenVR
-    sgct::SGCTOpenVR::shutdown();
-#endif
-    
     // Exit program
     exit(EXIT_SUCCESS); 
 }
diff --git a/openspace.cfg b/openspace.cfg
index 971434804f313058c88e42e910fbf7ca87d9892f..6180aa6e10b21ac29ca16935e1d7ff2ffa368487 100644
--- a/openspace.cfg
+++ b/openspace.cfg
@@ -9,6 +9,8 @@ return {
     -- A regular 1280x720 window
     SGCTConfig = sgct.config.single{},
 
+    -- SGCTConfig = sgct.config.single{res={1920, 1080}, shared=true},
+
     -- A regular 1920x1080 window
     -- SGCTConfig = sgct.config.single{1920, 1080},   
 
diff --git a/scripts/configuration_helper.lua b/scripts/configuration_helper.lua
index a6736408899af4c6dff52961395a77bb8d664c8e..036865a67b6053da80dc672a9aaacc6c372f683f 100644
--- a/scripts/configuration_helper.lua
+++ b/scripts/configuration_helper.lua
@@ -1,4 +1,4 @@
--- Helper functions that are useful to customize the openspace.cfg loading
+-- shared: Determines whether the contents of the window should be shared using the SPOUT library [example: shared=true] {default: false}-- Helper functions that are useful to customize the openspace.cfg loading
 
 --[[
 ########################################################################################## 
@@ -24,9 +24,11 @@ function sgct.makeConfig(config) end
 -- fullScreen: Whether the application should run in exclusive full screen [example: fullScreen=true] {default: false}
 -- border: Whether the application should have window decorations (aka. border) [example: border=false] {default: true}
 -- monitor: Determines the monitor on which the application is started [example: monitor=2] {default: 0}
+-- shared: Determines whether the contents of the window should be shared using the SPOUT library [example: shared=true] {default: false}
 
 -- Expert settings:
--- name: The name of the window [example: window="Foobar"] {defualt: "OpenSpace"}
+-- name: The name of the window [example: window="Foobar"] {default: "OpenSpace"}
+-- tags: A list of string tags that are passed to the window [example: tags ={"GUI"}] {default: {}}
 -- vsync: Whether the rendering speed is locked to the refreshrate [example: vsync=true] {default: false}
 -- refreshRate: If vsync is enabled, this is the target framerate [example: refreshRate=30] {default: infinity}
 -- stereo: Select the stereo rendering mode as supported by SGCT [example: stereo='anaglyph_red_cyan'] {default: 'none'}
@@ -56,9 +58,11 @@ function sgct.config.single(arg) end
 -- fullScreen: Whether the application should run in exclusive full screen [example: fullScreen=true] {default: false}
 -- border: Whether the application should have window decorations (aka. border) [example: border=false] {default: true}
 -- monitor: Determines the monitor on which the application is started [example: monitor=2] {default: 0}
+-- shared: Determines whether the contents of the window should be shared using the SPOUT library [example: shared=true] {default: false}
 
 -- Expert settings:
--- name: The name of the window [example: window="Foobar"] {defualt: "OpenSpace"}
+-- name: The name of the window [example: window="Foobar"] {default: "OpenSpace"}
+-- tags: A list of string tags that are passed to the window [example: tags ={"GUI"}] {default: {}}
 -- vsync: Whether the rendering speed is locked to the refreshrate [example: vsync=true] {default: false}
 -- refreshRate: If vsync is enabled, this is the target framerate [example: refreshRate=30] {default: infinity}
 -- stereo: Select the stereo rendering mode as supported by SGCT [example: stereo='anaglyph_red_cyan'] {default: 'none'}
@@ -81,13 +85,16 @@ function sgct.config.single(arg) end
 -- sgct.config.fisheye(msaa=1) -> 1280x720 resolution without multisampling
 function sgct.config.fisheye(arg) end
 
+function sgct.config.cube(arg) end
+
+
 --[[
 ########################################################################################## 
                             Internal helper functions
 ########################################################################################## 
 ]]--
 
-function generateSingleViewport(down, up, left, right)
+function generateSingleViewportFOV(down, up, left, right)
     return
 [[
 <Viewport>
@@ -103,6 +110,23 @@ end
 
 
 
+function generateSingleViewport(lowerLeft, upperLeft, upperRight)
+    return
+[[
+<Viewport>
+    <Pos x="0.0" y="0.0" />
+    <Size x="1.0" y="1.0" />
+    <Projectionplane>
+        <Pos x="]] .. lowerLeft[1] .. [[" y="]] .. lowerLeft[2] .. [[" z="]] .. lowerLeft[3] .. [[" />
+        <Pos x="]] .. upperLeft[1] .. [[" y="]] .. upperLeft[2] .. [[" z="]] .. upperLeft[3] .. [[" />
+        <Pos x="]] .. upperRight[1] .. [[" y="]] .. upperRight[2] .. [[" z="]] .. upperRight[3] .. [[" />
+    </Projectionplane>
+</Viewport>
+]]
+end
+
+
+
 function generateFisheyeViewport(fov, quality, tilt, background, crop, offset)
     local b = [[
             <Background 
@@ -163,6 +187,12 @@ function generateWindow(arg)
 ]]
     end
 
+    local tags = ""
+    if arg["tags"] then
+        tags = table.concat(arg["tags"], ",")
+    end
+
+
     return
 [[
     <Window 
@@ -171,6 +201,7 @@ function generateWindow(arg)
         border="]] .. tostring(arg["border"]) .. [["
         name="]] .. arg["name"] .. [["
         monitor="]] .. arg["monitor"] .. [["
+        tags="]] .. tags .. [["
     >
         <Stereo type="]] .. arg["stereo"] .. [[" />
         <Size x="]] .. arg["windowSize"][1] .. [[" y="]] .. arg["windowSize"][2] .. [[" />
@@ -314,13 +345,13 @@ function generateCluster(arg)
     externalControlPort="20500"
     debug="]] .. tostring(arg["sgctDebug"]) .. [["
 >
-]]..arg["settings"]..[[
-]]..arg["scene"]..[[
+]] .. (arg["settings"] or "") .. [[
+]] .. (arg["scene"] or "") .. [[
     <Node address="localhost" port="20401">
-]].. arg["window"] ..[[
+]] .. arg["window"] ..[[
     </Node>
 ]] .. arg["user"] .. [[
-]] .. arg["capture"] .. [[
+]] .. (arg["capture"] or "") .. [[
 </Cluster>
 ]]
 end
@@ -347,6 +378,21 @@ function generateSingleWindowConfig(arg)
         assert(type(arg["res"][2]) == "number", "res[2] must be a number")
     end
 
+    assert(
+        type(arg["shared"]) == "boolean" or type(arg["shared"]) == "nil",
+        "shared must be a boolean or nil"
+    )
+
+    assert(
+        type(arg["tags"]) == "table" or type(arg["tags"]) == "nil",
+        "tags must be a table or nil"
+    )
+    if (type(arg["tags"]) == "table") and (next(arg["tags"]) ~= nil) then
+        for index, value in ipairs(arg["tags"]) do
+            assert(type(value) == "string", "Each tag must be a string")
+        end
+    end
+
     assert(
         type(arg["windowSize"]) == "table" or type(arg["windowSize"]) == "nil",
         "windowSize must be a table or nil"
@@ -505,6 +551,10 @@ function generateSingleWindowConfig(arg)
     if arg["monitor"] == nil then
         arg["monitor"] = 0
     end
+    
+    if arg["tags"] == nil then
+        arg["tags"] = {}
+    end
 
     if arg["msaa"] == nil then
         arg["msaa"] = 8
@@ -514,6 +564,11 @@ function generateSingleWindowConfig(arg)
         arg["border"] = true
     end
 
+     if arg["shared"] then
+        local t = arg["tags"]
+        t[#t + 1] = "Spout"
+    end
+
     if arg["name"] == nil then
         arg["name"] = "OpenSpace"
     end
@@ -583,7 +638,7 @@ function sgct.config.single(arg)
     end
     
     arg["fov"] = arg["fov"] or { down = 16.875, up = 16.875, left = 30.0, right = 30.0 }
-    arg["viewport"] = generateSingleViewport(
+    arg["viewport"] = generateSingleViewportFOV(
         arg["fov"]["down"],
         arg["fov"]["up"], 
         arg["fov"]["left"],
@@ -680,3 +735,78 @@ function sgct.config.fisheye(arg)
 
     return sgct.makeConfig(generateSingleWindowConfig(arg))
 end
+
+
+
+function sgct.config.cube(arg)
+    function getCubeWindow(location, res, size)
+        local pos
+        local lowerLeft
+        local upperLeft
+        local upperRight
+        if location == 'left' then
+            pos = { 0, size[2] }
+            lowerLeft =     { -1, -1,  1 }
+            upperLeft =     { -1,  1,  1 }
+            upperRight =    { -1,  1, -1 }
+        elseif location == 'right' then
+            pos = { 2 * size[1], size[2] }
+            lowerLeft =     {  1, -1, -1 }
+            upperLeft =     {  1,  1, -1 }
+            upperRight =    {  1,  1,  1 }
+        elseif location == 'up' then
+            pos = { size[1], 0 }
+            lowerLeft =     {  1,  1, -1 }
+            upperLeft =     {  1,  1,  1 }
+            upperRight =    { -1,  1,  1 }
+        elseif location == 'down' then
+            pos = { size[1], 2 * size[2] }
+            lowerLeft =     { -1, -1,  1 }
+            upperLeft =     { -1, -1, -1 }
+            upperRight =    {  1, -1, -1 }
+        elseif location == 'back' then
+            pos = { 2 * size[1], 2 * size[2] }
+            lowerLeft =     {  1, -1,  1 }
+            upperLeft =     {  1,  1,  1 }
+            upperRight =    { -1,  1,  1 }
+        elseif location == 'front' then
+            pos = { size[1], size[2] }
+            lowerLeft =     { -1, -1, -1 }
+            upperLeft =     { -1,  1, -1 }
+            upperRight =    {  1,  1, -1 }
+        end
+
+        arg = {}
+        arg["msaa"] = 8
+        arg["border"] = false
+        arg["name"] = "OpenSpace_" .. location
+        arg["tags"] = { "Spout" }
+        arg["windowSize"] = size
+        arg["windowPos"] = pos
+        arg["res"] = { res, res }
+        arg["viewport"] = generateSingleViewport(lowerLeft, upperLeft, upperRight)
+
+        return generateWindow(arg)
+    end
+
+    function getControlWindow(down, up, left, right)
+        arg = {}
+        arg["viewport"] = generateSingleViewportFOV(down, up, left, right)
+        return generateWindow(arg)
+    end
+
+
+    res = 1024
+    size = {640, 360}
+    
+    arg["scene"] = generateScene(arg)
+    arg["settings"] = generateSettings(arg)
+    arg["window"] = getControlWindow(16.875, 16.875, 30.0, 30.0) .. getCubeWindow('front', res, size) .. getCubeWindow('back', res, size) .. 
+        getCubeWindow('left', res, size) .. getCubeWindow('right', res, size) .. 
+        getCubeWindow('up', res, size) .. getCubeWindow('down', res, size)
+
+    arg["user"] = generateUser(arg)
+    arg["capture"] = generateCapture(arg)
+
+    return sgct.makeConfig(generateCluster(arg))
+end