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