From 98534bc1ec190982f1a51b83b655a4fd31e50fb3 Mon Sep 17 00:00:00 2001 From: Klas Eskilson Date: Thu, 13 Jul 2017 12:08:47 -0400 Subject: [PATCH] Normalize ALL the line endings (#361) * Normalize ALL the line endings * Add Ghoul respository and openspace.cfg --- config/openvr_htcVive.xml | 46 +- config/openvr_oculusRiftCv1.xml | 46 +- config/single.xml | 48 +- config/single_fisheye.xml | 74 +- config/single_gui.xml | 74 +- config/single_two_win.xml | 62 +- config/two_nodes.xml | 70 +- data/scene/juno.scene | 126 +- ext/ghoul | 2 +- ext/tinythread.cpp | 606 +++--- ext/tinythread.h | 1428 ++++++------- modules/globebrowsing/other/pixelbuffer.cpp | 168 +- modules/globebrowsing/other/pixelbuffer.h | 280 +-- .../other/pixelbuffercontainer.h | 230 +- .../other/pixelbuffercontainer.inl | 260 +-- .../tile/rawtiledatareader/tiledatatype.cpp | 1228 +++++------ .../tile/rawtiledatareader/tiledatatype.h | 122 +- modules/globebrowsing/tile/textureformat.h | 86 +- .../tile/tiletextureinitdata.cpp | 304 +-- .../globebrowsing/tile/tiletextureinitdata.h | 182 +- .../newhorizons/util/projectioncomponent.cpp | 1900 ++++++++--------- modules/space/rendering/renderableplanet.cpp | 1126 +++++----- modules/volume/rawvolumewriter.h | 114 +- openspace.cfg | 190 +- src/engine/wrapper/sgctwindowwrapper.cpp | 496 ++--- src/rendering/framebufferrenderer.cpp | 1056 ++++----- src/util/syncbuffer.cpp | 124 +- support/cmake/support_macros.cmake | 1164 +++++----- 28 files changed, 5806 insertions(+), 5806 deletions(-) diff --git a/config/openvr_htcVive.xml b/config/openvr_htcVive.xml index b239d0283b..e663b11521 100644 --- a/config/openvr_htcVive.xml +++ b/config/openvr_htcVive.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/openvr_oculusRiftCv1.xml b/config/openvr_oculusRiftCv1.xml index 917991d559..e264dd3788 100644 --- a/config/openvr_oculusRiftCv1.xml +++ b/config/openvr_oculusRiftCv1.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single.xml b/config/single.xml index ed397f50fe..6f8f58b23b 100644 --- a/config/single.xml +++ b/config/single.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_fisheye.xml b/config/single_fisheye.xml index da491287e5..b9bc7415dd 100644 --- a/config/single_fisheye.xml +++ b/config/single_fisheye.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_gui.xml b/config/single_gui.xml index d17ab77c79..129232a9ea 100644 --- a/config/single_gui.xml +++ b/config/single_gui.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_two_win.xml b/config/single_two_win.xml index 3c20b3191e..2f7f49efc6 100644 --- a/config/single_two_win.xml +++ b/config/single_two_win.xml @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/two_nodes.xml b/config/two_nodes.xml index 941fb90cb8..b4ae20f8c0 100644 --- a/config/two_nodes.xml +++ b/config/two_nodes.xml @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/scene/juno.scene b/data/scene/juno.scene index 403b508435..eee0999a82 100755 --- a/data/scene/juno.scene +++ b/data/scene/juno.scene @@ -1,63 +1,63 @@ -function preInitialization() - --[[ - The scripts in this function are executed after the scene is loaded but before the - scene elements have been initialized, thus they should be used to set the time at - which the scene should start and other settings that might determine initialization - critical objects. - ]]-- - openspace.spice.loadKernel("${SPICE}/naif0012.tls") - openspace.spice.loadKernel("${SPICE}/pck00010.tpc") - - openspace.time.setTime("2016-07-05T10:05:00.00") - - dofile(openspace.absPath('${SCRIPTS}/common.lua')) - openspace.clearKeys() - helper.setCommonKeys() - helper.setDeltaTimeKeys({ - 1, 5, 10, 20, 40, 90, 360, 720, 2880, 14400, - 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 - }) -end - -function postInitialization() - --[[ - The scripts in this function are executed after all objects in the scene have been - created and initialized, but before the first render call. This is the place to set - graphical settings for the renderables. - ]]-- - openspace.printInfo("Setting default values") - openspace.setPropertyValue("Sun.renderable.enabled", false) - openspace.setPropertyValue("SunMarker.renderable.enabled", true) - openspace.setPropertyValue("EarthMarker.renderable.enabled", true) - - openspace.setPropertyValue("MilkyWay.renderable.transparency", 0.55) - openspace.setPropertyValue("MilkyWay.renderable.segments", 50) - - openspace.setPropertyValue('Jupiter.renderable.performShading', false); - - openspace.printInfo("Done setting default values") -end - -return { - ScenePath = ".", - CommonFolder = "common", - Camera = { - Focus = "Juno", - Position = {1, 0, 0, 5}, - }, - Modules = { - "sun", - "mercury", - "venus", - "earth", - "mars", - "jupiter", - "saturn/saturn", - "uranus", - "neptune", - "stars", - "milkyway", - "missions/juno" - } -} - +function preInitialization() + --[[ + The scripts in this function are executed after the scene is loaded but before the + scene elements have been initialized, thus they should be used to set the time at + which the scene should start and other settings that might determine initialization + critical objects. + ]]-- + openspace.spice.loadKernel("${SPICE}/naif0012.tls") + openspace.spice.loadKernel("${SPICE}/pck00010.tpc") + + openspace.time.setTime("2016-07-05T10:05:00.00") + + dofile(openspace.absPath('${SCRIPTS}/common.lua')) + openspace.clearKeys() + helper.setCommonKeys() + helper.setDeltaTimeKeys({ + 1, 5, 10, 20, 40, 90, 360, 720, 2880, 14400, + 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 + }) +end + +function postInitialization() + --[[ + The scripts in this function are executed after all objects in the scene have been + created and initialized, but before the first render call. This is the place to set + graphical settings for the renderables. + ]]-- + openspace.printInfo("Setting default values") + openspace.setPropertyValue("Sun.renderable.enabled", false) + openspace.setPropertyValue("SunMarker.renderable.enabled", true) + openspace.setPropertyValue("EarthMarker.renderable.enabled", true) + + openspace.setPropertyValue("MilkyWay.renderable.transparency", 0.55) + openspace.setPropertyValue("MilkyWay.renderable.segments", 50) + + openspace.setPropertyValue('Jupiter.renderable.performShading', false); + + openspace.printInfo("Done setting default values") +end + +return { + ScenePath = ".", + CommonFolder = "common", + Camera = { + Focus = "Juno", + Position = {1, 0, 0, 5}, + }, + Modules = { + "sun", + "mercury", + "venus", + "earth", + "mars", + "jupiter", + "saturn/saturn", + "uranus", + "neptune", + "stars", + "milkyway", + "missions/juno" + } +} + diff --git a/ext/ghoul b/ext/ghoul index d1b4177c44..128284f0e7 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit d1b4177c4456fed24686b44f9e69cf23c7fe43ee +Subproject commit 128284f0e7f6584678398efa2b9f8fac60a646ce diff --git a/ext/tinythread.cpp b/ext/tinythread.cpp index 5b5bd41cf4..690eceea1a 100644 --- a/ext/tinythread.cpp +++ b/ext/tinythread.cpp @@ -1,303 +1,303 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#include -#include "tinythread.h" - -#if defined(_TTHREAD_POSIX_) - #include - #include -#elif defined(_TTHREAD_WIN32_) - #include -#endif - - -namespace tthread { - -//------------------------------------------------------------------------------ -// condition_variable -//------------------------------------------------------------------------------ -// NOTE 1: The Win32 implementation of the condition_variable class is based on -// the corresponding implementation in GLFW, which in turn is based on a -// description by Douglas C. Schmidt and Irfan Pyarali: -// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html -// -// NOTE 2: Windows Vista actually has native support for condition variables -// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to -// be portable with pre-Vista Windows versions, so TinyThread++ does not use -// Vista condition variables. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_WIN32_) - #define _CONDITION_EVENT_ONE 0 - #define _CONDITION_EVENT_ALL 1 -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::condition_variable() : mWaitersCount(0) -{ - mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::~condition_variable() -{ - CloseHandle(mEvents[_CONDITION_EVENT_ONE]); - CloseHandle(mEvents[_CONDITION_EVENT_ALL]); - DeleteCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::_wait() -{ - // Wait for either event to become signaled due to notify_one() or - // notify_all() being called - int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); - - // Check if we are the last waiter - EnterCriticalSection(&mWaitersCountLock); - -- mWaitersCount; - bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (mWaitersCount == 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we are the last waiter to be notified to stop waiting, reset the event - if(lastWaiter) - ResetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_one() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ONE]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_all() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - - -//------------------------------------------------------------------------------ -// POSIX pthread_t to unique thread::id mapping logic. -// Note: Here we use a global thread safe std::map to convert instances of -// pthread_t to small thread identifier numbers (unique within one process). -// This method should be portable across different POSIX implementations. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_POSIX_) -static thread::id _pthread_t_to_ID(const pthread_t &aHandle) -{ - static mutex idMapLock; - static std::map idMap; - static unsigned long int idCount(1); - - lock_guard guard(idMapLock); - if(idMap.find(aHandle) == idMap.end()) - idMap[aHandle] = idCount ++; - return thread::id(idMap[aHandle]); -} -#endif // _TTHREAD_POSIX_ - - -//------------------------------------------------------------------------------ -// thread -//------------------------------------------------------------------------------ - -/// Information to pass to the new thread (what to run). -struct _thread_start_info { - void (*mFunction)(void *); ///< Pointer to the function to be executed. - void * mArg; ///< Function argument for the thread function. - thread * mThread; ///< Pointer to the thread object. -}; - -// Thread wrapper function. -#if defined(_TTHREAD_WIN32_) -unsigned WINAPI thread::wrapper_function(void * aArg) -#elif defined(_TTHREAD_POSIX_) -void * thread::wrapper_function(void * aArg) -#endif -{ - // Get thread startup information - _thread_start_info * ti = (_thread_start_info *) aArg; - - try - { - // Call the actual client thread function - ti->mFunction(ti->mArg); - } - catch(...) - { - // Uncaught exceptions will terminate the application (default behavior - // according to C++11) - std::terminate(); - } - - // The thread is no longer executing - lock_guard guard(ti->mThread->mDataMutex); - ti->mThread->mNotAThread = true; - - // The thread is responsible for freeing the startup information - delete ti; - - return 0; -} - -thread::thread(void (*aFunction)(void *), void * aArg) -{ - // Serialize access to this thread structure - lock_guard guard(mDataMutex); - - // Fill out the thread startup information (passed to the thread wrapper, - // which will eventually free it) - _thread_start_info * ti = new _thread_start_info; - ti->mFunction = aFunction; - ti->mArg = aArg; - ti->mThread = this; - - // The thread is now alive - mNotAThread = false; - - // Create the thread -#if defined(_TTHREAD_WIN32_) - mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) - mHandle = 0; -#endif - - // Did we fail to create the thread? - if(!mHandle) - { - mNotAThread = true; - delete ti; - } -} - -thread::~thread() -{ - if(joinable()) - std::terminate(); -} - -void thread::join() -{ - if(joinable()) - { -#if defined(_TTHREAD_WIN32_) - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_join(mHandle, NULL); -#endif - } -} - -bool thread::joinable() const -{ - mDataMutex.lock(); - bool result = !mNotAThread; - mDataMutex.unlock(); - return result; -} - -void thread::detach() -{ - mDataMutex.lock(); - if(!mNotAThread) - { -#if defined(_TTHREAD_WIN32_) - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_detach(mHandle); -#endif - mNotAThread = true; - } - mDataMutex.unlock(); -} - -thread::id thread::get_id() const -{ - if(!joinable()) - return id(); -#if defined(_TTHREAD_WIN32_) - return id((unsigned long int) mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(mHandle); -#endif -} - -unsigned thread::hardware_concurrency() -{ -#if defined(_TTHREAD_WIN32_) - SYSTEM_INFO si; - GetSystemInfo(&si); - return (int) si.dwNumberOfProcessors; -#elif defined(_SC_NPROCESSORS_ONLN) - return (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(_SC_NPROC_ONLN) - return (int) sysconf(_SC_NPROC_ONLN); -#else - // The standard requires this function to return zero if the number of - // hardware cores could not be determined. - return 0; -#endif -} - - -//------------------------------------------------------------------------------ -// this_thread -//------------------------------------------------------------------------------ - -thread::id this_thread::get_id() -{ -#if defined(_TTHREAD_WIN32_) - return thread::id((unsigned long int) GetCurrentThreadId()); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(pthread_self()); -#endif -} - -} +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2010-2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#include +#include "tinythread.h" + +#if defined(_TTHREAD_POSIX_) + #include + #include +#elif defined(_TTHREAD_WIN32_) + #include +#endif + + +namespace tthread { + +//------------------------------------------------------------------------------ +// condition_variable +//------------------------------------------------------------------------------ +// NOTE 1: The Win32 implementation of the condition_variable class is based on +// the corresponding implementation in GLFW, which in turn is based on a +// description by Douglas C. Schmidt and Irfan Pyarali: +// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html +// +// NOTE 2: Windows Vista actually has native support for condition variables +// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to +// be portable with pre-Vista Windows versions, so TinyThread++ does not use +// Vista condition variables. +//------------------------------------------------------------------------------ + +#if defined(_TTHREAD_WIN32_) + #define _CONDITION_EVENT_ONE 0 + #define _CONDITION_EVENT_ALL 1 +#endif + +#if defined(_TTHREAD_WIN32_) +condition_variable::condition_variable() : mWaitersCount(0) +{ + mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&mWaitersCountLock); +} +#endif + +#if defined(_TTHREAD_WIN32_) +condition_variable::~condition_variable() +{ + CloseHandle(mEvents[_CONDITION_EVENT_ONE]); + CloseHandle(mEvents[_CONDITION_EVENT_ALL]); + DeleteCriticalSection(&mWaitersCountLock); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::_wait() +{ + // Wait for either event to become signaled due to notify_one() or + // notify_all() being called + int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); + + // Check if we are the last waiter + EnterCriticalSection(&mWaitersCountLock); + -- mWaitersCount; + bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (mWaitersCount == 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we are the last waiter to be notified to stop waiting, reset the event + if(lastWaiter) + ResetEvent(mEvents[_CONDITION_EVENT_ALL]); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::notify_one() +{ + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ONE]); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::notify_all() +{ + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ALL]); +} +#endif + + +//------------------------------------------------------------------------------ +// POSIX pthread_t to unique thread::id mapping logic. +// Note: Here we use a global thread safe std::map to convert instances of +// pthread_t to small thread identifier numbers (unique within one process). +// This method should be portable across different POSIX implementations. +//------------------------------------------------------------------------------ + +#if defined(_TTHREAD_POSIX_) +static thread::id _pthread_t_to_ID(const pthread_t &aHandle) +{ + static mutex idMapLock; + static std::map idMap; + static unsigned long int idCount(1); + + lock_guard guard(idMapLock); + if(idMap.find(aHandle) == idMap.end()) + idMap[aHandle] = idCount ++; + return thread::id(idMap[aHandle]); +} +#endif // _TTHREAD_POSIX_ + + +//------------------------------------------------------------------------------ +// thread +//------------------------------------------------------------------------------ + +/// Information to pass to the new thread (what to run). +struct _thread_start_info { + void (*mFunction)(void *); ///< Pointer to the function to be executed. + void * mArg; ///< Function argument for the thread function. + thread * mThread; ///< Pointer to the thread object. +}; + +// Thread wrapper function. +#if defined(_TTHREAD_WIN32_) +unsigned WINAPI thread::wrapper_function(void * aArg) +#elif defined(_TTHREAD_POSIX_) +void * thread::wrapper_function(void * aArg) +#endif +{ + // Get thread startup information + _thread_start_info * ti = (_thread_start_info *) aArg; + + try + { + // Call the actual client thread function + ti->mFunction(ti->mArg); + } + catch(...) + { + // Uncaught exceptions will terminate the application (default behavior + // according to C++11) + std::terminate(); + } + + // The thread is no longer executing + lock_guard guard(ti->mThread->mDataMutex); + ti->mThread->mNotAThread = true; + + // The thread is responsible for freeing the startup information + delete ti; + + return 0; +} + +thread::thread(void (*aFunction)(void *), void * aArg) +{ + // Serialize access to this thread structure + lock_guard guard(mDataMutex); + + // Fill out the thread startup information (passed to the thread wrapper, + // which will eventually free it) + _thread_start_info * ti = new _thread_start_info; + ti->mFunction = aFunction; + ti->mArg = aArg; + ti->mThread = this; + + // The thread is now alive + mNotAThread = false; + + // Create the thread +#if defined(_TTHREAD_WIN32_) + mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); +#elif defined(_TTHREAD_POSIX_) + if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) + mHandle = 0; +#endif + + // Did we fail to create the thread? + if(!mHandle) + { + mNotAThread = true; + delete ti; + } +} + +thread::~thread() +{ + if(joinable()) + std::terminate(); +} + +void thread::join() +{ + if(joinable()) + { +#if defined(_TTHREAD_WIN32_) + WaitForSingleObject(mHandle, INFINITE); + CloseHandle(mHandle); +#elif defined(_TTHREAD_POSIX_) + pthread_join(mHandle, NULL); +#endif + } +} + +bool thread::joinable() const +{ + mDataMutex.lock(); + bool result = !mNotAThread; + mDataMutex.unlock(); + return result; +} + +void thread::detach() +{ + mDataMutex.lock(); + if(!mNotAThread) + { +#if defined(_TTHREAD_WIN32_) + CloseHandle(mHandle); +#elif defined(_TTHREAD_POSIX_) + pthread_detach(mHandle); +#endif + mNotAThread = true; + } + mDataMutex.unlock(); +} + +thread::id thread::get_id() const +{ + if(!joinable()) + return id(); +#if defined(_TTHREAD_WIN32_) + return id((unsigned long int) mWin32ThreadID); +#elif defined(_TTHREAD_POSIX_) + return _pthread_t_to_ID(mHandle); +#endif +} + +unsigned thread::hardware_concurrency() +{ +#if defined(_TTHREAD_WIN32_) + SYSTEM_INFO si; + GetSystemInfo(&si); + return (int) si.dwNumberOfProcessors; +#elif defined(_SC_NPROCESSORS_ONLN) + return (int) sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROC_ONLN) + return (int) sysconf(_SC_NPROC_ONLN); +#else + // The standard requires this function to return zero if the number of + // hardware cores could not be determined. + return 0; +#endif +} + + +//------------------------------------------------------------------------------ +// this_thread +//------------------------------------------------------------------------------ + +thread::id this_thread::get_id() +{ +#if defined(_TTHREAD_WIN32_) + return thread::id((unsigned long int) GetCurrentThreadId()); +#elif defined(_TTHREAD_POSIX_) + return _pthread_t_to_ID(pthread_self()); +#endif +} + +} diff --git a/ext/tinythread.h b/ext/tinythread.h index 956cf1d166..aed7b5856b 100644 --- a/ext/tinythread.h +++ b/ext/tinythread.h @@ -1,714 +1,714 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef _TINYTHREAD_H_ -#define _TINYTHREAD_H_ - -/// @file -/// @mainpage TinyThread++ API Reference -/// -/// @section intro_sec Introduction -/// TinyThread++ is a minimal, portable implementation of basic threading -/// classes for C++. -/// -/// They closely mimic the functionality and naming of the C++11 standard, and -/// should be easily replaceable with the corresponding std:: variants. -/// -/// @section port_sec Portability -/// The Win32 variant uses the native Win32 API for implementing the thread -/// classes, while for other systems, the POSIX threads API (pthread) is used. -/// -/// @section class_sec Classes -/// In order to mimic the threading API of the C++11 standard, subsets of -/// several classes are provided. The fundamental classes are: -/// @li tthread::thread -/// @li tthread::mutex -/// @li tthread::recursive_mutex -/// @li tthread::condition_variable -/// @li tthread::lock_guard -/// @li tthread::fast_mutex -/// -/// @section misc_sec Miscellaneous -/// The following special keywords are available: #thread_local. -/// -/// For more detailed information (including additional classes), browse the -/// different sections of this documentation. A good place to start is: -/// tinythread.h. - -// Which platform are we on? -#if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ -#endif - -// Platform specific includes -#if defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif -#else - #include - #include - #include - #include -#endif - -// Generic includes -#include - -/// TinyThread++ version (major number). -#define TINYTHREAD_VERSION_MAJOR 1 -/// TinyThread++ version (minor number). -#define TINYTHREAD_VERSION_MINOR 1 -/// TinyThread++ version (full version). -#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) - -// Do we have a fully featured C++11 compiler? -#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) - #define _TTHREAD_CPP11_ -#endif - -// ...at least partial C++11? -#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) - #define _TTHREAD_CPP11_PARTIAL_ -#endif - -// Macro for disabling assignments of objects. -#ifdef _TTHREAD_CPP11_PARTIAL_ - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&) = delete; \ - name& operator=(const name&) = delete; -#else - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&); \ - name& operator=(const name&); -#endif - -/// @def thread_local -/// Thread local storage keyword. -/// A variable that is declared with the @c thread_local keyword makes the -/// value of the variable local to each thread (known as thread-local storage, -/// or TLS). Example usage: -/// @code -/// // This variable is local to each thread. -/// thread_local int variable; -/// @endcode -/// @note The @c thread_local keyword is a macro that maps to the corresponding -/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard -/// allows for non-trivial types (e.g. classes with constructors and -/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 -/// compilers only allow for trivial types (e.g. @c int). So, to guarantee -/// portable code, only use trivial types for thread local storage. -/// @note This directive is currently not supported on Mac OS X (it will give -/// a compiler error), since compile-time TLS is not supported in the Mac OS X -/// executable format. Also, some older versions of MinGW (before GCC 4.x) do -/// not support this directive. -/// @hideinitializer - -#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define thread_local __thread - #else - #define thread_local __declspec(thread) - #endif -#endif - - -/// Main name space for TinyThread++. -/// This namespace is more or less equivalent to the @c std namespace for the -/// C++11 thread classes. For instance, the tthread::mutex class corresponds to -/// the std::mutex class. -namespace tthread { - -/// Mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is non-recursive (i.e. a -/// program may deadlock if the thread that owns a mutex object calls lock() -/// on that object). -/// @see recursive_mutex -class mutex { - public: - /// Constructor. - mutex() -#if defined(_TTHREAD_WIN32_) - : mAlreadyLocked(false) -#endif - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutex_init(&mHandle, NULL); -#endif - } - - /// Destructor. - ~mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); - while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... - mAlreadyLocked = true; -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); - if(ret && mAlreadyLocked) - { - LeaveCriticalSection(&mHandle); - ret = false; - } - return ret; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - mAlreadyLocked = false; - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; - bool mAlreadyLocked; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Recursive mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is recursive (i.e. a thread -/// may lock the mutex several times, as long as it unlocks the mutex the same -/// number of times). -/// @see mutex -class recursive_mutex { - public: - /// Constructor. - recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mHandle, &attr); -#endif - } - - /// Destructor. - ~recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - return TryEnterCriticalSection(&mHandle) ? true : false; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Lock guard class. -/// The constructor locks the mutex, and the destructor unlocks the mutex, so -/// the mutex will automatically be unlocked when the lock guard goes out of -/// scope. Example usage: -/// @code -/// mutex m; -/// int counter; -/// -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ counter; -/// } -/// @endcode - -template -class lock_guard { - public: - typedef T mutex_type; - - lock_guard() : mMutex(0) {} - - /// The constructor locks the mutex. - explicit lock_guard(mutex_type &aMutex) - { - mMutex = &aMutex; - mMutex->lock(); - } - - /// The destructor unlocks the mutex. - ~lock_guard() - { - if(mMutex) - mMutex->unlock(); - } - - private: - mutex_type * mMutex; -}; - -/// Condition variable class. -/// This is a signalling object for synchronizing the execution flow for -/// several threads. Example usage: -/// @code -/// // Shared data and associated mutex and condition variable objects -/// int count; -/// mutex m; -/// condition_variable cond; -/// -/// // Wait for the counter to reach a certain number -/// void wait_counter(int targetCount) -/// { -/// lock_guard guard(m); -/// while(count < targetCount) -/// cond.wait(m); -/// } -/// -/// // Increment the counter, and notify waiting threads -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ count; -/// cond.notify_all(); -/// } -/// @endcode -class condition_variable { - public: - /// Constructor. -#if defined(_TTHREAD_WIN32_) - condition_variable(); -#else - condition_variable() - { - pthread_cond_init(&mHandle, NULL); - } -#endif - - /// Destructor. -#if defined(_TTHREAD_WIN32_) - ~condition_variable(); -#else - ~condition_variable() - { - pthread_cond_destroy(&mHandle); - } -#endif - - /// Wait for the condition. - /// The function will block the calling thread until the condition variable - /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. - /// @param[in] aMutex A mutex that will be unlocked when the wait operation - /// starts, an locked again as soon as the wait operation is finished. - template - inline void wait(_mutexT &aMutex) - { -#if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(); - aMutex.lock(); -#else - pthread_cond_wait(&mHandle, &aMutex.mHandle); -#endif - } - - /// Notify one thread that is waiting for the condition. - /// If at least one thread is blocked waiting for this condition variable, - /// one will be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_one(); -#else - inline void notify_one() - { - pthread_cond_signal(&mHandle); - } -#endif - - /// Notify all threads that are waiting for the condition. - /// All threads that are blocked waiting for this condition variable will - /// be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_all(); -#else - inline void notify_all() - { - pthread_cond_broadcast(&mHandle); - } -#endif - - _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) - - private: -#if defined(_TTHREAD_WIN32_) - void _wait(); - HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. - unsigned int mWaitersCount; ///< Count of the number of waiters. - CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. -#else - pthread_cond_t mHandle; -#endif -}; - - -/// Thread class. -class thread { - public: -#if defined(_TTHREAD_WIN32_) - typedef HANDLE native_handle_type; -#else - typedef pthread_t native_handle_type; -#endif - - class id; - - /// Default constructor. - /// Construct a @c thread object without an associated thread of execution - /// (i.e. non-joinable). - thread() : mHandle(0), mNotAThread(true) -#if defined(_TTHREAD_WIN32_) - , mWin32ThreadID(0) -#endif - {} - - /// Thread starting constructor. - /// Construct a @c thread object with a new thread of execution. - /// @param[in] aFunction A function pointer to a function of type: - /// void fun(void * arg) - /// @param[in] aArg Argument to the thread function. - /// @note This constructor is not fully compatible with the standard C++ - /// thread class. It is more similar to the pthread_create() (POSIX) and - /// CreateThread() (Windows) functions. - thread(void (*aFunction)(void *), void * aArg); - - /// Destructor. - /// @note If the thread is joinable upon destruction, @c std::terminate() - /// will be called, which terminates the process. It is always wise to do - /// @c join() before deleting a thread object. - ~thread(); - - /// Wait for the thread to finish (join execution flows). - /// After calling @c join(), the thread object is no longer associated with - /// a thread of execution (i.e. it is not joinable, and you may not join - /// with it nor detach from it). - void join(); - - /// Check if the thread is joinable. - /// A thread object is joinable if it has an associated thread of execution. - bool joinable() const; - - /// Detach from the thread. - /// After calling @c detach(), the thread object is no longer assicated with - /// a thread of execution (i.e. it is not joinable). The thread continues - /// execution without the calling thread blocking, and when the thread - /// ends execution, any owned resources are released. - void detach(); - - /// Return the thread ID of a thread object. - id get_id() const; - - /// Get the native handle for this thread. - /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this - /// is a @c pthread_t. - inline native_handle_type native_handle() - { - return mHandle; - } - - /// Determine the number of threads which can possibly execute concurrently. - /// This function is useful for determining the optimal number of threads to - /// use for a task. - /// @return The number of hardware thread contexts in the system. - /// @note If this value is not defined, the function returns zero (0). - static unsigned hardware_concurrency(); - - _TTHREAD_DISABLE_ASSIGNMENT(thread) - - private: - native_handle_type mHandle; ///< Thread handle. - mutable mutex mDataMutex; ///< Serializer for access to the thread private data. - bool mNotAThread; ///< True if this object is not a thread of execution. -#if defined(_TTHREAD_WIN32_) - unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). -#endif - - // This is the internal thread wrapper function. -#if defined(_TTHREAD_WIN32_) - static unsigned WINAPI wrapper_function(void * aArg); -#else - static void * wrapper_function(void * aArg); -#endif -}; - -/// Thread ID. -/// The thread ID is a unique identifier for each thread. -/// @see thread::get_id() -class thread::id { - public: - /// Default constructor. - /// The default constructed ID is that of thread without a thread of - /// execution. - id() : mId(0) {}; - - id(unsigned long int aId) : mId(aId) {}; - - id(const id& aId) : mId(aId.mId) {}; - - inline id & operator=(const id &aId) - { - mId = aId.mId; - return *this; - } - - inline friend bool operator==(const id &aId1, const id &aId2) - { - return (aId1.mId == aId2.mId); - } - - inline friend bool operator!=(const id &aId1, const id &aId2) - { - return (aId1.mId != aId2.mId); - } - - inline friend bool operator<=(const id &aId1, const id &aId2) - { - return (aId1.mId <= aId2.mId); - } - - inline friend bool operator<(const id &aId1, const id &aId2) - { - return (aId1.mId < aId2.mId); - } - - inline friend bool operator>=(const id &aId1, const id &aId2) - { - return (aId1.mId >= aId2.mId); - } - - inline friend bool operator>(const id &aId1, const id &aId2) - { - return (aId1.mId > aId2.mId); - } - - inline friend std::ostream& operator <<(std::ostream &os, const id &obj) - { - os << obj.mId; - return os; - } - - private: - unsigned long int mId; -}; - - -// Related to - minimal to be able to support chrono. -typedef long long __intmax_t; - -/// Minimal implementation of the @c ratio class. This class provides enough -/// functionality to implement some basic @c chrono classes. -template <__intmax_t N, __intmax_t D = 1> class ratio { - public: - static double _as_double() { return double(N) / double(D); } -}; - -/// Minimal implementation of the @c chrono namespace. -/// The @c chrono namespace provides types for specifying time intervals. -namespace chrono { - /// Duration template class. This class provides enough functionality to - /// implement @c this_thread::sleep_for(). - template > class duration { - private: - _Rep rep_; - public: - typedef _Rep rep; - typedef _Period period; - - /// Construct a duration object with the given duration. - template - explicit duration(const _Rep2& r) : rep_(r) {}; - - /// Return the value of the duration object. - rep count() const - { - return rep_; - } - }; - - // Standard duration types. - typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. - typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. - typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. - typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. - typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. - typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. -} - -/// The namespace @c this_thread provides methods for dealing with the -/// calling thread. -namespace this_thread { - /// Return the thread ID of the calling thread. - thread::id get_id(); - - /// Yield execution to another thread. - /// Offers the operating system the opportunity to schedule another thread - /// that is ready to run on the current processor. - inline void yield() - { -#if defined(_TTHREAD_WIN32_) - Sleep(0); -#else - sched_yield(); -#endif - } - - /// Blocks the calling thread for a period of time. - /// @param[in] aTime Minimum time to put the thread to sleep. - /// Example usage: - /// @code - /// // Sleep for 100 milliseconds - /// this_thread::sleep_for(chrono::milliseconds(100)); - /// @endcode - /// @note Supported duration types are: nanoseconds, microseconds, - /// milliseconds, seconds, minutes and hours. - template void sleep_for(const chrono::duration<_Rep, _Period>& aTime) - { -#if defined(_TTHREAD_WIN32_) - Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); -#else - usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); -#endif - } -} - -} - -// Define/macro cleanup -#undef _TTHREAD_DISABLE_ASSIGNMENT - -#endif // _TINYTHREAD_H_ +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2010-2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef _TINYTHREAD_H_ +#define _TINYTHREAD_H_ + +/// @file +/// @mainpage TinyThread++ API Reference +/// +/// @section intro_sec Introduction +/// TinyThread++ is a minimal, portable implementation of basic threading +/// classes for C++. +/// +/// They closely mimic the functionality and naming of the C++11 standard, and +/// should be easily replaceable with the corresponding std:: variants. +/// +/// @section port_sec Portability +/// The Win32 variant uses the native Win32 API for implementing the thread +/// classes, while for other systems, the POSIX threads API (pthread) is used. +/// +/// @section class_sec Classes +/// In order to mimic the threading API of the C++11 standard, subsets of +/// several classes are provided. The fundamental classes are: +/// @li tthread::thread +/// @li tthread::mutex +/// @li tthread::recursive_mutex +/// @li tthread::condition_variable +/// @li tthread::lock_guard +/// @li tthread::fast_mutex +/// +/// @section misc_sec Miscellaneous +/// The following special keywords are available: #thread_local. +/// +/// For more detailed information (including additional classes), browse the +/// different sections of this documentation. A good place to start is: +/// tinythread.h. + +// Which platform are we on? +#if !defined(_TTHREAD_PLATFORM_DEFINED_) + #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define _TTHREAD_WIN32_ + #else + #define _TTHREAD_POSIX_ + #endif + #define _TTHREAD_PLATFORM_DEFINED_ +#endif + +// Platform specific includes +#if defined(_TTHREAD_WIN32_) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define __UNDEF_LEAN_AND_MEAN + #endif + #include + #ifdef __UNDEF_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN + #undef __UNDEF_LEAN_AND_MEAN + #endif +#else + #include + #include + #include + #include +#endif + +// Generic includes +#include + +/// TinyThread++ version (major number). +#define TINYTHREAD_VERSION_MAJOR 1 +/// TinyThread++ version (minor number). +#define TINYTHREAD_VERSION_MINOR 1 +/// TinyThread++ version (full version). +#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) + +// Do we have a fully featured C++11 compiler? +#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) + #define _TTHREAD_CPP11_ +#endif + +// ...at least partial C++11? +#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) + #define _TTHREAD_CPP11_PARTIAL_ +#endif + +// Macro for disabling assignments of objects. +#ifdef _TTHREAD_CPP11_PARTIAL_ + #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ + name(const name&) = delete; \ + name& operator=(const name&) = delete; +#else + #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ + name(const name&); \ + name& operator=(const name&); +#endif + +/// @def thread_local +/// Thread local storage keyword. +/// A variable that is declared with the @c thread_local keyword makes the +/// value of the variable local to each thread (known as thread-local storage, +/// or TLS). Example usage: +/// @code +/// // This variable is local to each thread. +/// thread_local int variable; +/// @endcode +/// @note The @c thread_local keyword is a macro that maps to the corresponding +/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard +/// allows for non-trivial types (e.g. classes with constructors and +/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 +/// compilers only allow for trivial types (e.g. @c int). So, to guarantee +/// portable code, only use trivial types for thread local storage. +/// @note This directive is currently not supported on Mac OS X (it will give +/// a compiler error), since compile-time TLS is not supported in the Mac OS X +/// executable format. Also, some older versions of MinGW (before GCC 4.x) do +/// not support this directive. +/// @hideinitializer + +#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) + #define thread_local __thread + #else + #define thread_local __declspec(thread) + #endif +#endif + + +/// Main name space for TinyThread++. +/// This namespace is more or less equivalent to the @c std namespace for the +/// C++11 thread classes. For instance, the tthread::mutex class corresponds to +/// the std::mutex class. +namespace tthread { + +/// Mutex class. +/// This is a mutual exclusion object for synchronizing access to shared +/// memory areas for several threads. The mutex is non-recursive (i.e. a +/// program may deadlock if the thread that owns a mutex object calls lock() +/// on that object). +/// @see recursive_mutex +class mutex { + public: + /// Constructor. + mutex() +#if defined(_TTHREAD_WIN32_) + : mAlreadyLocked(false) +#endif + { +#if defined(_TTHREAD_WIN32_) + InitializeCriticalSection(&mHandle); +#else + pthread_mutex_init(&mHandle, NULL); +#endif + } + + /// Destructor. + ~mutex() + { +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mHandle); +#else + pthread_mutex_destroy(&mHandle); +#endif + } + + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() + { +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mHandle); + while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... + mAlreadyLocked = true; +#else + pthread_mutex_lock(&mHandle); +#endif + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() + { +#if defined(_TTHREAD_WIN32_) + bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); + if(ret && mAlreadyLocked) + { + LeaveCriticalSection(&mHandle); + ret = false; + } + return ret; +#else + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; +#endif + } + + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() + { +#if defined(_TTHREAD_WIN32_) + mAlreadyLocked = false; + LeaveCriticalSection(&mHandle); +#else + pthread_mutex_unlock(&mHandle); +#endif + } + + _TTHREAD_DISABLE_ASSIGNMENT(mutex) + + private: +#if defined(_TTHREAD_WIN32_) + CRITICAL_SECTION mHandle; + bool mAlreadyLocked; +#else + pthread_mutex_t mHandle; +#endif + + friend class condition_variable; +}; + +/// Recursive mutex class. +/// This is a mutual exclusion object for synchronizing access to shared +/// memory areas for several threads. The mutex is recursive (i.e. a thread +/// may lock the mutex several times, as long as it unlocks the mutex the same +/// number of times). +/// @see mutex +class recursive_mutex { + public: + /// Constructor. + recursive_mutex() + { +#if defined(_TTHREAD_WIN32_) + InitializeCriticalSection(&mHandle); +#else + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mHandle, &attr); +#endif + } + + /// Destructor. + ~recursive_mutex() + { +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mHandle); +#else + pthread_mutex_destroy(&mHandle); +#endif + } + + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() + { +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mHandle); +#else + pthread_mutex_lock(&mHandle); +#endif + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() + { +#if defined(_TTHREAD_WIN32_) + return TryEnterCriticalSection(&mHandle) ? true : false; +#else + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; +#endif + } + + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() + { +#if defined(_TTHREAD_WIN32_) + LeaveCriticalSection(&mHandle); +#else + pthread_mutex_unlock(&mHandle); +#endif + } + + _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) + + private: +#if defined(_TTHREAD_WIN32_) + CRITICAL_SECTION mHandle; +#else + pthread_mutex_t mHandle; +#endif + + friend class condition_variable; +}; + +/// Lock guard class. +/// The constructor locks the mutex, and the destructor unlocks the mutex, so +/// the mutex will automatically be unlocked when the lock guard goes out of +/// scope. Example usage: +/// @code +/// mutex m; +/// int counter; +/// +/// void increment() +/// { +/// lock_guard guard(m); +/// ++ counter; +/// } +/// @endcode + +template +class lock_guard { + public: + typedef T mutex_type; + + lock_guard() : mMutex(0) {} + + /// The constructor locks the mutex. + explicit lock_guard(mutex_type &aMutex) + { + mMutex = &aMutex; + mMutex->lock(); + } + + /// The destructor unlocks the mutex. + ~lock_guard() + { + if(mMutex) + mMutex->unlock(); + } + + private: + mutex_type * mMutex; +}; + +/// Condition variable class. +/// This is a signalling object for synchronizing the execution flow for +/// several threads. Example usage: +/// @code +/// // Shared data and associated mutex and condition variable objects +/// int count; +/// mutex m; +/// condition_variable cond; +/// +/// // Wait for the counter to reach a certain number +/// void wait_counter(int targetCount) +/// { +/// lock_guard guard(m); +/// while(count < targetCount) +/// cond.wait(m); +/// } +/// +/// // Increment the counter, and notify waiting threads +/// void increment() +/// { +/// lock_guard guard(m); +/// ++ count; +/// cond.notify_all(); +/// } +/// @endcode +class condition_variable { + public: + /// Constructor. +#if defined(_TTHREAD_WIN32_) + condition_variable(); +#else + condition_variable() + { + pthread_cond_init(&mHandle, NULL); + } +#endif + + /// Destructor. +#if defined(_TTHREAD_WIN32_) + ~condition_variable(); +#else + ~condition_variable() + { + pthread_cond_destroy(&mHandle); + } +#endif + + /// Wait for the condition. + /// The function will block the calling thread until the condition variable + /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. + /// @param[in] aMutex A mutex that will be unlocked when the wait operation + /// starts, an locked again as soon as the wait operation is finished. + template + inline void wait(_mutexT &aMutex) + { +#if defined(_TTHREAD_WIN32_) + // Increment number of waiters + EnterCriticalSection(&mWaitersCountLock); + ++ mWaitersCount; + LeaveCriticalSection(&mWaitersCountLock); + + // Release the mutex while waiting for the condition (will decrease + // the number of waiters when done)... + aMutex.unlock(); + _wait(); + aMutex.lock(); +#else + pthread_cond_wait(&mHandle, &aMutex.mHandle); +#endif + } + + /// Notify one thread that is waiting for the condition. + /// If at least one thread is blocked waiting for this condition variable, + /// one will be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. +#if defined(_TTHREAD_WIN32_) + void notify_one(); +#else + inline void notify_one() + { + pthread_cond_signal(&mHandle); + } +#endif + + /// Notify all threads that are waiting for the condition. + /// All threads that are blocked waiting for this condition variable will + /// be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. +#if defined(_TTHREAD_WIN32_) + void notify_all(); +#else + inline void notify_all() + { + pthread_cond_broadcast(&mHandle); + } +#endif + + _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) + + private: +#if defined(_TTHREAD_WIN32_) + void _wait(); + HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. + unsigned int mWaitersCount; ///< Count of the number of waiters. + CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. +#else + pthread_cond_t mHandle; +#endif +}; + + +/// Thread class. +class thread { + public: +#if defined(_TTHREAD_WIN32_) + typedef HANDLE native_handle_type; +#else + typedef pthread_t native_handle_type; +#endif + + class id; + + /// Default constructor. + /// Construct a @c thread object without an associated thread of execution + /// (i.e. non-joinable). + thread() : mHandle(0), mNotAThread(true) +#if defined(_TTHREAD_WIN32_) + , mWin32ThreadID(0) +#endif + {} + + /// Thread starting constructor. + /// Construct a @c thread object with a new thread of execution. + /// @param[in] aFunction A function pointer to a function of type: + /// void fun(void * arg) + /// @param[in] aArg Argument to the thread function. + /// @note This constructor is not fully compatible with the standard C++ + /// thread class. It is more similar to the pthread_create() (POSIX) and + /// CreateThread() (Windows) functions. + thread(void (*aFunction)(void *), void * aArg); + + /// Destructor. + /// @note If the thread is joinable upon destruction, @c std::terminate() + /// will be called, which terminates the process. It is always wise to do + /// @c join() before deleting a thread object. + ~thread(); + + /// Wait for the thread to finish (join execution flows). + /// After calling @c join(), the thread object is no longer associated with + /// a thread of execution (i.e. it is not joinable, and you may not join + /// with it nor detach from it). + void join(); + + /// Check if the thread is joinable. + /// A thread object is joinable if it has an associated thread of execution. + bool joinable() const; + + /// Detach from the thread. + /// After calling @c detach(), the thread object is no longer assicated with + /// a thread of execution (i.e. it is not joinable). The thread continues + /// execution without the calling thread blocking, and when the thread + /// ends execution, any owned resources are released. + void detach(); + + /// Return the thread ID of a thread object. + id get_id() const; + + /// Get the native handle for this thread. + /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this + /// is a @c pthread_t. + inline native_handle_type native_handle() + { + return mHandle; + } + + /// Determine the number of threads which can possibly execute concurrently. + /// This function is useful for determining the optimal number of threads to + /// use for a task. + /// @return The number of hardware thread contexts in the system. + /// @note If this value is not defined, the function returns zero (0). + static unsigned hardware_concurrency(); + + _TTHREAD_DISABLE_ASSIGNMENT(thread) + + private: + native_handle_type mHandle; ///< Thread handle. + mutable mutex mDataMutex; ///< Serializer for access to the thread private data. + bool mNotAThread; ///< True if this object is not a thread of execution. +#if defined(_TTHREAD_WIN32_) + unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). +#endif + + // This is the internal thread wrapper function. +#if defined(_TTHREAD_WIN32_) + static unsigned WINAPI wrapper_function(void * aArg); +#else + static void * wrapper_function(void * aArg); +#endif +}; + +/// Thread ID. +/// The thread ID is a unique identifier for each thread. +/// @see thread::get_id() +class thread::id { + public: + /// Default constructor. + /// The default constructed ID is that of thread without a thread of + /// execution. + id() : mId(0) {}; + + id(unsigned long int aId) : mId(aId) {}; + + id(const id& aId) : mId(aId.mId) {}; + + inline id & operator=(const id &aId) + { + mId = aId.mId; + return *this; + } + + inline friend bool operator==(const id &aId1, const id &aId2) + { + return (aId1.mId == aId2.mId); + } + + inline friend bool operator!=(const id &aId1, const id &aId2) + { + return (aId1.mId != aId2.mId); + } + + inline friend bool operator<=(const id &aId1, const id &aId2) + { + return (aId1.mId <= aId2.mId); + } + + inline friend bool operator<(const id &aId1, const id &aId2) + { + return (aId1.mId < aId2.mId); + } + + inline friend bool operator>=(const id &aId1, const id &aId2) + { + return (aId1.mId >= aId2.mId); + } + + inline friend bool operator>(const id &aId1, const id &aId2) + { + return (aId1.mId > aId2.mId); + } + + inline friend std::ostream& operator <<(std::ostream &os, const id &obj) + { + os << obj.mId; + return os; + } + + private: + unsigned long int mId; +}; + + +// Related to - minimal to be able to support chrono. +typedef long long __intmax_t; + +/// Minimal implementation of the @c ratio class. This class provides enough +/// functionality to implement some basic @c chrono classes. +template <__intmax_t N, __intmax_t D = 1> class ratio { + public: + static double _as_double() { return double(N) / double(D); } +}; + +/// Minimal implementation of the @c chrono namespace. +/// The @c chrono namespace provides types for specifying time intervals. +namespace chrono { + /// Duration template class. This class provides enough functionality to + /// implement @c this_thread::sleep_for(). + template > class duration { + private: + _Rep rep_; + public: + typedef _Rep rep; + typedef _Period period; + + /// Construct a duration object with the given duration. + template + explicit duration(const _Rep2& r) : rep_(r) {}; + + /// Return the value of the duration object. + rep count() const + { + return rep_; + } + }; + + // Standard duration types. + typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. + typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. + typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. + typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. + typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. + typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. +} + +/// The namespace @c this_thread provides methods for dealing with the +/// calling thread. +namespace this_thread { + /// Return the thread ID of the calling thread. + thread::id get_id(); + + /// Yield execution to another thread. + /// Offers the operating system the opportunity to schedule another thread + /// that is ready to run on the current processor. + inline void yield() + { +#if defined(_TTHREAD_WIN32_) + Sleep(0); +#else + sched_yield(); +#endif + } + + /// Blocks the calling thread for a period of time. + /// @param[in] aTime Minimum time to put the thread to sleep. + /// Example usage: + /// @code + /// // Sleep for 100 milliseconds + /// this_thread::sleep_for(chrono::milliseconds(100)); + /// @endcode + /// @note Supported duration types are: nanoseconds, microseconds, + /// milliseconds, seconds, minutes and hours. + template void sleep_for(const chrono::duration<_Rep, _Period>& aTime) + { +#if defined(_TTHREAD_WIN32_) + Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); +#else + usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); +#endif + } +} + +} + +// Define/macro cleanup +#undef _TTHREAD_DISABLE_ASSIGNMENT + +#endif // _TINYTHREAD_H_ diff --git a/modules/globebrowsing/other/pixelbuffer.cpp b/modules/globebrowsing/other/pixelbuffer.cpp index 1882419d7b..22b8264a48 100644 --- a/modules/globebrowsing/other/pixelbuffer.cpp +++ b/modules/globebrowsing/other/pixelbuffer.cpp @@ -1,84 +1,84 @@ -/***************************************************************************************** - * * - * 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 -#include - -namespace { - const char* _loggerCat = "PixelBuffer"; -}; - -using namespace openspace::globebrowsing; - -PixelBuffer::PixelBuffer(size_t numBytes, Usage usage) - : _numBytes(numBytes) - , _usage(usage) - , _isMapped(false) -{ - glGenBuffers(1, &_id); - bind(); - glBufferData(GL_PIXEL_UNPACK_BUFFER, _numBytes, 0, static_cast(_usage)); - unbind(); -} - -PixelBuffer::~PixelBuffer() { - glDeleteBuffers(1, &_id); -} - -void* PixelBuffer::mapBuffer(Access access) { - void* dataPtr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(access)); - _isMapped = dataPtr ? true : false; - return dataPtr; -} - -void* PixelBuffer::mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access) { - void* dataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, offset, length, access); - _isMapped = dataPtr ? true : false; - return dataPtr; -} - -bool PixelBuffer::unMapBuffer() { - GLboolean success = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - if (!success) { - LERROR("Unable to unmap pixel buffer, data may be corrupt!"); - } - _isMapped = false; - return success == GL_TRUE; -} - -void PixelBuffer::bind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _id); -} - -void PixelBuffer::unbind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); -} - -bool PixelBuffer::isMapped() const { - return _isMapped; -} - -PixelBuffer::operator GLuint() const { - return _id; -} +/***************************************************************************************** + * * + * 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 +#include + +namespace { + const char* _loggerCat = "PixelBuffer"; +}; + +using namespace openspace::globebrowsing; + +PixelBuffer::PixelBuffer(size_t numBytes, Usage usage) + : _numBytes(numBytes) + , _usage(usage) + , _isMapped(false) +{ + glGenBuffers(1, &_id); + bind(); + glBufferData(GL_PIXEL_UNPACK_BUFFER, _numBytes, 0, static_cast(_usage)); + unbind(); +} + +PixelBuffer::~PixelBuffer() { + glDeleteBuffers(1, &_id); +} + +void* PixelBuffer::mapBuffer(Access access) { + void* dataPtr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(access)); + _isMapped = dataPtr ? true : false; + return dataPtr; +} + +void* PixelBuffer::mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access) { + void* dataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, offset, length, access); + _isMapped = dataPtr ? true : false; + return dataPtr; +} + +bool PixelBuffer::unMapBuffer() { + GLboolean success = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + if (!success) { + LERROR("Unable to unmap pixel buffer, data may be corrupt!"); + } + _isMapped = false; + return success == GL_TRUE; +} + +void PixelBuffer::bind() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _id); +} + +void PixelBuffer::unbind() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); +} + +bool PixelBuffer::isMapped() const { + return _isMapped; +} + +PixelBuffer::operator GLuint() const { + return _id; +} diff --git a/modules/globebrowsing/other/pixelbuffer.h b/modules/globebrowsing/other/pixelbuffer.h index 11e8f97811..1f9ee4918e 100644 --- a/modules/globebrowsing/other/pixelbuffer.h +++ b/modules/globebrowsing/other/pixelbuffer.h @@ -1,140 +1,140 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * Handles an OpenGL pixel buffer which contains data allocated on the GPU. A simple - * class that wraps the standard functionality of OpenGL pixel buffer objects. Once - * the PixelBuffer is created, data is allocated on the GPU. When mapping data to a - * address pointer, the user needs to ensure the data is unmapped before the data can - * be used on the GPU / CPU depending on Usage. - */ -class PixelBuffer -{ -public: - /** - * All kinds of usage for pixel buffer objects as defined by the OpenGL standard. - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml - */ - enum class Usage : std::underlying_type_t { - StreamDraw = static_cast>(GL_STREAM_DRAW), - StreamRead = static_cast>(GL_STREAM_READ), - StreamCopy = static_cast>(GL_STREAM_COPY), - StaticDraw = static_cast>(GL_STATIC_DRAW), - StaticRead = static_cast>(GL_STATIC_READ), - StaticCopy = static_cast>(GL_STATIC_COPY), - DynamicDraw = static_cast>(GL_DYNAMIC_DRAW), - DynamicRead = static_cast>(GL_DYNAMIC_READ), - DynamicCopy = static_cast>(GL_DYNAMIC_COPY) - }; - - /** - * Access hints for OpenGL buffer mapping - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMapBuffer.xml - */ - enum class Access : std::underlying_type_t { - ReadOnly = static_cast>(GL_READ_ONLY), - WriteOnly = static_cast>(GL_WRITE_ONLY), - ReadWrite = static_cast>(GL_READ_WRITE) - }; - - /** - * Allocates numBytes bytes on the GPU and creates an ID for the pixel - * buffer object. - * \param numBytes is the number of bytes to be allocated on GPU memory - * \param usage is the Usage for the pixel buffer - */ - PixelBuffer(size_t numBytes, Usage usage); - - /** - * calls glDeleteBuffers(). - */ - ~PixelBuffer(); - - /** - * Maps an address pointer to GPU direct memory access. The user must make sure the - * buffer is bound before calling this function. - * \param access is the access to which can be any of GL_READ_ONLY, - * GL_WRITE_ONLY, or GL_READ_WRITE - * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBuffer(Access access); - - /** - * Maps an address pointer to GPU direct memory access. Gives access to a range of - * the buffer. The user must make sure the buffer is bound before calling this - * function. - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is a bitfield describing the access as described in: - * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glMapBufferRange.xhtml - * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access); - - /** - * Maps the default buffer and makes the data available on the GPU - */ - bool unMapBuffer(); - - /** - * Calls glBindBuffer() - */ - void bind(); - - /** - * Calls glBindBuffer() with argument 0 to unmap any pixel buffer - */ - void unbind(); - - /** - * \returns true of the buffer is mapped, otherwise false - */ - bool isMapped() const; - - /** - * \returns the OpenGL id of the pixel buffer object - */ - operator GLuint() const; - -private: - GLuint _id; - const size_t _numBytes; - const Usage _usage; - bool _isMapped; -}; - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * Handles an OpenGL pixel buffer which contains data allocated on the GPU. A simple + * class that wraps the standard functionality of OpenGL pixel buffer objects. Once + * the PixelBuffer is created, data is allocated on the GPU. When mapping data to a + * address pointer, the user needs to ensure the data is unmapped before the data can + * be used on the GPU / CPU depending on Usage. + */ +class PixelBuffer +{ +public: + /** + * All kinds of usage for pixel buffer objects as defined by the OpenGL standard. + * See: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml + */ + enum class Usage : std::underlying_type_t { + StreamDraw = static_cast>(GL_STREAM_DRAW), + StreamRead = static_cast>(GL_STREAM_READ), + StreamCopy = static_cast>(GL_STREAM_COPY), + StaticDraw = static_cast>(GL_STATIC_DRAW), + StaticRead = static_cast>(GL_STATIC_READ), + StaticCopy = static_cast>(GL_STATIC_COPY), + DynamicDraw = static_cast>(GL_DYNAMIC_DRAW), + DynamicRead = static_cast>(GL_DYNAMIC_READ), + DynamicCopy = static_cast>(GL_DYNAMIC_COPY) + }; + + /** + * Access hints for OpenGL buffer mapping + * See: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMapBuffer.xml + */ + enum class Access : std::underlying_type_t { + ReadOnly = static_cast>(GL_READ_ONLY), + WriteOnly = static_cast>(GL_WRITE_ONLY), + ReadWrite = static_cast>(GL_READ_WRITE) + }; + + /** + * Allocates numBytes bytes on the GPU and creates an ID for the pixel + * buffer object. + * \param numBytes is the number of bytes to be allocated on GPU memory + * \param usage is the Usage for the pixel buffer + */ + PixelBuffer(size_t numBytes, Usage usage); + + /** + * calls glDeleteBuffers(). + */ + ~PixelBuffer(); + + /** + * Maps an address pointer to GPU direct memory access. The user must make sure the + * buffer is bound before calling this function. + * \param access is the access to which can be any of GL_READ_ONLY, + * GL_WRITE_ONLY, or GL_READ_WRITE + * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping + * failed + */ + void* mapBuffer(Access access); + + /** + * Maps an address pointer to GPU direct memory access. Gives access to a range of + * the buffer. The user must make sure the buffer is bound before calling this + * function. + * \param offet is the number of bytes to the first address to get in the buffer + * \param length is the number of bytes to access in the buffer + * \param access is a bitfield describing the access as described in: + * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glMapBufferRange.xhtml + * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping + * failed + */ + void* mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access); + + /** + * Maps the default buffer and makes the data available on the GPU + */ + bool unMapBuffer(); + + /** + * Calls glBindBuffer() + */ + void bind(); + + /** + * Calls glBindBuffer() with argument 0 to unmap any pixel buffer + */ + void unbind(); + + /** + * \returns true of the buffer is mapped, otherwise false + */ + bool isMapped() const; + + /** + * \returns the OpenGL id of the pixel buffer object + */ + operator GLuint() const; + +private: + GLuint _id; + const size_t _numBytes; + const Usage _usage; + bool _isMapped; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.h b/modules/globebrowsing/other/pixelbuffercontainer.h index 8dc0aa2dc6..f1fdcfb9aa 100644 --- a/modules/globebrowsing/other/pixelbuffercontainer.h +++ b/modules/globebrowsing/other/pixelbuffercontainer.h @@ -1,115 +1,115 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ - -#include - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * Templated class which owns one or many PixelBuffers. The - * KeyType is used to map a pixel buffer but only if it is not already - * mapped. - */ -template -class PixelBufferContainer -{ -public: - /** - * Creates numPixelBuffers pixel buffer objects, each with numBytesPerBuffer bytes - * allocated on the GPU. - * \param numBytesPerBuffer is the number of bytes per pixel buffer. All pixel - * buffers within a PixelBufferContainer have the same number of bytes - * \param usage is the Usage as described by PixelBuffer - * \param numPixelBuffers is the number of pixel buffers to create for this container. - * If numPixelBuffers is omitted, no pixel buffers are created. - */ - PixelBufferContainer(size_t numBytesPerBuffer, - globebrowsing::PixelBuffer::Usage usage, size_t numPixelBuffers = 0); - ~PixelBufferContainer() = default; - - /** - * Finds a Pixel buffer and maps it if it is available. - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param access is the access as described by PixelBuffer - * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr - * is returned. The mapping can fail if the buffer identified with key - * is already mapped or if something else failed. - */ - void* mapBuffer(KeyType key, PixelBuffer::Access access); - - /** - * Finds a Pixel buffer and maps a range of it if it is available. - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is the access as described by PixelBuffer - * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr - * is returned. The mapping can fail if the buffer identified with key - * is already mapped or if something else failed. - */ - void* mapBufferRange(KeyType key, GLintptr offset, GLsizeiptr length, - BufferAccessMask access); - - /** - * Unmaps all buffers in the PixelBufferContainer. - * \returns true if the unmapping succeeded, otherwise false. - */ - bool resetMappedBuffers(); - - /** - * Unmaps a buffer that has previously been mapped. This buffer is identified using - * key. - * \param key is the identifier of the mapped buffer. - * \returns true if the unmapping succeeded, otherwise false. - */ - bool unMapBuffer(KeyType key); - - /** - * \returns the GLuint id of a pixel buffer identified by key - * if it currently is mapped. - */ - GLuint idOfMappedBuffer(KeyType key); -private: - const globebrowsing::PixelBuffer::Usage _usage; - - std::vector> _pixelBuffers; - - // Maps from KeyType to index of mapped buffers - std::map _indexMap; -}; - -} // namespace globebrowsing -} // namespace openspace - -#include "pixelbuffercontainer.inl" - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ + +#include + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * Templated class which owns one or many PixelBuffers. The + * KeyType is used to map a pixel buffer but only if it is not already + * mapped. + */ +template +class PixelBufferContainer +{ +public: + /** + * Creates numPixelBuffers pixel buffer objects, each with numBytesPerBuffer bytes + * allocated on the GPU. + * \param numBytesPerBuffer is the number of bytes per pixel buffer. All pixel + * buffers within a PixelBufferContainer have the same number of bytes + * \param usage is the Usage as described by PixelBuffer + * \param numPixelBuffers is the number of pixel buffers to create for this container. + * If numPixelBuffers is omitted, no pixel buffers are created. + */ + PixelBufferContainer(size_t numBytesPerBuffer, + globebrowsing::PixelBuffer::Usage usage, size_t numPixelBuffers = 0); + ~PixelBufferContainer() = default; + + /** + * Finds a Pixel buffer and maps it if it is available. + * \param key is the identifier for the pixel buffer which can be used later when + * unmapping the mapped pixel buffer. + * \param access is the access as described by PixelBuffer + * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr + * is returned. The mapping can fail if the buffer identified with key + * is already mapped or if something else failed. + */ + void* mapBuffer(KeyType key, PixelBuffer::Access access); + + /** + * Finds a Pixel buffer and maps a range of it if it is available. + * \param key is the identifier for the pixel buffer which can be used later when + * unmapping the mapped pixel buffer. + * \param offet is the number of bytes to the first address to get in the buffer + * \param length is the number of bytes to access in the buffer + * \param access is the access as described by PixelBuffer + * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr + * is returned. The mapping can fail if the buffer identified with key + * is already mapped or if something else failed. + */ + void* mapBufferRange(KeyType key, GLintptr offset, GLsizeiptr length, + BufferAccessMask access); + + /** + * Unmaps all buffers in the PixelBufferContainer. + * \returns true if the unmapping succeeded, otherwise false. + */ + bool resetMappedBuffers(); + + /** + * Unmaps a buffer that has previously been mapped. This buffer is identified using + * key. + * \param key is the identifier of the mapped buffer. + * \returns true if the unmapping succeeded, otherwise false. + */ + bool unMapBuffer(KeyType key); + + /** + * \returns the GLuint id of a pixel buffer identified by key + * if it currently is mapped. + */ + GLuint idOfMappedBuffer(KeyType key); +private: + const globebrowsing::PixelBuffer::Usage _usage; + + std::vector> _pixelBuffers; + + // Maps from KeyType to index of mapped buffers + std::map _indexMap; +}; + +} // namespace globebrowsing +} // namespace openspace + +#include "pixelbuffercontainer.inl" + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.inl b/modules/globebrowsing/other/pixelbuffercontainer.inl index e3a1433e0a..c1a4e4aaa2 100644 --- a/modules/globebrowsing/other/pixelbuffercontainer.inl +++ b/modules/globebrowsing/other/pixelbuffercontainer.inl @@ -1,130 +1,130 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -namespace openspace { -namespace globebrowsing { - -template -PixelBufferContainer::PixelBufferContainer(size_t numBytesPerBuffer, - PixelBuffer::Usage usage, size_t numPixelBuffers) - : _usage(usage) -{ - for (size_t i = 0; i < numPixelBuffers; ++i) { - _pixelBuffers.push_back(std::make_unique(numBytesPerBuffer, _usage)); - } -} - -template -void* PixelBufferContainer::mapBuffer(KeyType key, PixelBuffer::Access access) { - typename std::map::const_iterator iter = _indexMap.find(key); - const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (size_t i = 0; i < _pixelBuffers.size(); ++i) { - if (!_pixelBuffers[i]->isMapped()) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBuffer(access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - // Add this index to the map of mapped pixel buffers - _indexMap.emplace(key, i); - return dataPtr; - } - } - } - return nullptr; -} - -template -void* PixelBufferContainer::mapBufferRange(KeyType key, GLintptr offset, - GLsizeiptr length, BufferAccessMask access) -{ - typename std::map::const_iterator iter = _indexMap.find(key); - bool notFoundAmongMappedBuffers = iter == _indexMap.end(); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (int i = 0; i < _pixelBuffers.size(); ++i) { - bool bufferIsMapped = _pixelBuffers[i]->isMapped(); - if (!bufferIsMapped) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBufferRange(offset, length, access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - _indexMap.emplace(key, i); - return dataPtr; - } - } - } - return nullptr; -} - -template -bool PixelBufferContainer::resetMappedBuffers() { - bool success = true; - for (auto iter = _indexMap.begin(); iter != _indexMap.end(); iter++) { - int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success &= _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -bool PixelBufferContainer::unMapBuffer(KeyType key) { - bool success = false; - typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success = _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -GLuint PixelBufferContainer::idOfMappedBuffer(KeyType key) { - typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - int index = iter->second; // Index where the mapped buffer is stored - return *_pixelBuffers[index]; - } - return 0; -} - -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +namespace openspace { +namespace globebrowsing { + +template +PixelBufferContainer::PixelBufferContainer(size_t numBytesPerBuffer, + PixelBuffer::Usage usage, size_t numPixelBuffers) + : _usage(usage) +{ + for (size_t i = 0; i < numPixelBuffers; ++i) { + _pixelBuffers.push_back(std::make_unique(numBytesPerBuffer, _usage)); + } +} + +template +void* PixelBufferContainer::mapBuffer(KeyType key, PixelBuffer::Access access) { + typename std::map::const_iterator iter = _indexMap.find(key); + const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); + + if (!notFoundAmongMappedBuffers) { // This PBO is already mapped + ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); + return nullptr; + } + + // Find a pixel buffer that is unmapped + for (size_t i = 0; i < _pixelBuffers.size(); ++i) { + if (!_pixelBuffers[i]->isMapped()) { + _pixelBuffers[i]->bind(); + void* dataPtr = _pixelBuffers[i]->mapBuffer(access); + _pixelBuffers[i]->unbind(); + if (dataPtr) { // Success in mapping + // Add this index to the map of mapped pixel buffers + _indexMap.emplace(key, i); + return dataPtr; + } + } + } + return nullptr; +} + +template +void* PixelBufferContainer::mapBufferRange(KeyType key, GLintptr offset, + GLsizeiptr length, BufferAccessMask access) +{ + typename std::map::const_iterator iter = _indexMap.find(key); + bool notFoundAmongMappedBuffers = iter == _indexMap.end(); + + if (!notFoundAmongMappedBuffers) { // This PBO is already mapped + ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); + return nullptr; + } + + // Find a pixel buffer that is unmapped + for (int i = 0; i < _pixelBuffers.size(); ++i) { + bool bufferIsMapped = _pixelBuffers[i]->isMapped(); + if (!bufferIsMapped) { + _pixelBuffers[i]->bind(); + void* dataPtr = _pixelBuffers[i]->mapBufferRange(offset, length, access); + _pixelBuffers[i]->unbind(); + if (dataPtr) { // Success in mapping + _indexMap.emplace(key, i); + return dataPtr; + } + } + } + return nullptr; +} + +template +bool PixelBufferContainer::resetMappedBuffers() { + bool success = true; + for (auto iter = _indexMap.begin(); iter != _indexMap.end(); iter++) { + int index = iter->second; // Index where the mapped buffer is stored + _pixelBuffers[index]->bind(); + success &= _pixelBuffers[index]->unMapBuffer(); + _pixelBuffers[index]->unbind(); + _indexMap.erase(iter); // This key should no longer be among the mapped buffers + } + return success; +} + +template +bool PixelBufferContainer::unMapBuffer(KeyType key) { + bool success = false; + typename std::map::const_iterator iter = _indexMap.find(key); + if (iter != _indexMap.end()) { // Found a mapped pixel buffer + int index = iter->second; // Index where the mapped buffer is stored + _pixelBuffers[index]->bind(); + success = _pixelBuffers[index]->unMapBuffer(); + _pixelBuffers[index]->unbind(); + _indexMap.erase(iter); // This key should no longer be among the mapped buffers + } + return success; +} + +template +GLuint PixelBufferContainer::idOfMappedBuffer(KeyType key) { + typename std::map::const_iterator iter = _indexMap.find(key); + if (iter != _indexMap.end()) { // Found a mapped pixel buffer + int index = iter->second; // Index where the mapped buffer is stored + return *_pixelBuffers[index]; + } + return 0; +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp index ed8590a14a..03a08c4ed0 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp @@ -1,614 +1,614 @@ -/***************************************************************************************** - * * - * 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 - -#ifdef GLOBEBROWSING_USE_GDAL -#include -#include -#endif // GLOBEBROWSING_USE_GDAL - -#include -#include // abspath -#include - -#include - -#include - -#include -#include - -namespace { - const char* _loggerCat = "TileDataType"; -} - -namespace openspace { -namespace globebrowsing { -namespace tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL - -float interpretFloat(GDALDataType gdalType, const char* src) { - switch (gdalType) { - case GDT_Byte: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt16: - return static_cast(*reinterpret_cast(src)); - case GDT_Int16: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt32: - return static_cast(*reinterpret_cast(src)); - case GDT_Int32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float64: - return static_cast(*reinterpret_cast(src)); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t numberOfBytes(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return sizeof(GLubyte); - case GDT_UInt16: - return sizeof(GLushort); - case GDT_Int16: - return sizeof(GLshort); - case GDT_UInt32: - return sizeof(GLuint); - case GDT_Int32: - return sizeof(GLint); - case GDT_Float32: - return sizeof(GLfloat); - case GDT_Float64: - return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t getMaximumValue(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return 1 << 8; - case GDT_UInt16: - return 1 << 16; - case GDT_Int16: - return 1 << 15; - case GDT_UInt32: - return size_t(1) << 32; - case GDT_Int32: - return 1 << 31; - default: - ghoul_assert(false, "Unknown data type"); - } -} - -TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType) { - TextureFormat format; - - switch (rasterCount) { - case 1: // Red - format.ghoulFormat = ghoul::opengl::Texture::Format::Red; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_R8; - break; - case GDT_UInt16: - format.glFormat = GL_R16UI; - break; - case GDT_Int16: - format.glFormat = GL_R16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_R32UI; - break; - case GDT_Int32: - format.glFormat = GL_R32I; - break; - case GDT_Float32: - format.glFormat = GL_R32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 2: - format.ghoulFormat = ghoul::opengl::Texture::Format::RG; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RG8; - break; - case GDT_UInt16: - format.glFormat = GL_RG16UI; - break; - case GDT_Int16: - format.glFormat = GL_RG16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RG32UI; - break; - case GDT_Int32: - format.glFormat = GL_RG32I; - break; - case GDT_Float32: - format.glFormat = GL_RG32F; - break; - case GDT_Float64: - format.glFormat = GL_RED; - break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 3: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGB; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGB8; - break; - case GDT_UInt16: - format.glFormat = GL_RGB16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGB32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGB32I; - break; - case GDT_Float32: - format.glFormat = GL_RGB32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 4: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGBA; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGBA8; - break; - case GDT_UInt16: - format.glFormat = GL_RGBA16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGBA32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGBA32I; - break; - case GDT_Float32: - format.glFormat = GL_RGBA32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - default: - LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); - break; - } - return format; -} - -TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType) { - TextureFormat format; - - switch (rasterCount) { - case 1: // Red - format.ghoulFormat = ghoul::opengl::Texture::Format::Red; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_R8; - break; - case GDT_UInt16: - format.glFormat = GL_R16UI; - break; - case GDT_Int16: - format.glFormat = GL_R16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_R32UI; - break; - case GDT_Int32: - format.glFormat = GL_R32I; - break; - case GDT_Float32: - format.glFormat = GL_R32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 2: - format.ghoulFormat = ghoul::opengl::Texture::Format::RG; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RG8; - break; - case GDT_UInt16: - format.glFormat = GL_RG16UI; - break; - case GDT_Int16: - format.glFormat = GL_RG16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RG32UI; - break; - case GDT_Int32: - format.glFormat = GL_RG32I; - break; - case GDT_Float32: - format.glFormat = GL_RG32F; - break; - case GDT_Float64: - format.glFormat = GL_RED; - break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 3: - format.ghoulFormat = ghoul::opengl::Texture::Format::BGR; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGB8; - break; - case GDT_UInt16: - format.glFormat = GL_RGB16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGB32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGB32I; - break; - case GDT_Float32: - format.glFormat = GL_RGB32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 4: - format.ghoulFormat = ghoul::opengl::Texture::Format::BGRA; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGBA8; - break; - case GDT_UInt16: - format.glFormat = GL_RGBA16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGBA32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGBA32I; - break; - case GDT_Float32: - format.glFormat = GL_RGBA32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - default: - LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); - break; - } - return format; -} - -GLenum getOpenGLDataType(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return GL_UNSIGNED_BYTE; - case GDT_UInt16: - return GL_UNSIGNED_SHORT; - case GDT_Int16: - return GL_SHORT; - case GDT_UInt32: - return GL_UNSIGNED_INT; - case GDT_Int32: - return GL_INT; - case GDT_Float32: - return GL_FLOAT; - case GDT_Float64: - return GL_DOUBLE; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - return GL_UNSIGNED_BYTE; - } -} - -GDALDataType getGdalDataType(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return GDT_Byte; - case GL_UNSIGNED_SHORT: - return GDT_UInt16; - case GL_SHORT: - return GDT_Int16; - case GL_UNSIGNED_INT: - return GDT_UInt32; - case GL_INT: - return GDT_Int32; - case GL_FLOAT: - return GDT_Float32; - case GL_DOUBLE: - return GDT_Float64; - default: - LERROR("OpenGL data type unknown to GDAL: " << glType); - return GDT_Unknown; - } -} - -#endif // GLOBEBROWSING_USE_GDAL - -size_t numberOfRasters(ghoul::opengl::Texture::Format format) { - switch (format) { - case ghoul::opengl::Texture::Format::Red: return 1; - case ghoul::opengl::Texture::Format::RG: return 2; - case ghoul::opengl::Texture::Format::RGB:; // Intentional fallthrough - case ghoul::opengl::Texture::Format::BGR: return 3; - case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough - case ghoul::opengl::Texture::Format::BGRA: return 4; - default: ghoul_assert(false, "Unknown format"); - } -} - -size_t numberOfBytes(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_BYTE: return sizeof(GLbyte); - case GL_UNSIGNED_SHORT: return sizeof(GLushort); - case GL_SHORT: return sizeof(GLshort); - case GL_UNSIGNED_INT: return sizeof(GLuint); - case GL_INT: return sizeof(GLint); - case GL_HALF_FLOAT: return sizeof(GLhalf); - case GL_FLOAT: return sizeof(GLfloat); - case GL_DOUBLE: return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t getMaximumValue(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return 1 << 8; - case GL_UNSIGNED_SHORT: - return 1 << 16; - case GL_SHORT: - return 1 << 15; - case GL_UNSIGNED_INT: - return size_t(1) << 32; - case GL_INT: - return 1 << 31; - default: - ghoul_assert(false, "Unknown data type"); - } -} - -float interpretFloat(GLenum glType, const char* src) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return static_cast(*reinterpret_cast(src)); - case GL_UNSIGNED_SHORT: - return static_cast(*reinterpret_cast(src)); - case GL_SHORT: - return static_cast(*reinterpret_cast(src)); - case GL_UNSIGNED_INT: - return static_cast(*reinterpret_cast(src)); - case GL_INT: - return static_cast(*reinterpret_cast(src)); - case GL_HALF_FLOAT: - return static_cast(*reinterpret_cast(src)); - case GL_FLOAT: - return static_cast(*reinterpret_cast(src)); - case GL_DOUBLE: - return static_cast(*reinterpret_cast(src)); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { - switch (format) { - case ghoul::opengl::Texture::Format::Red: - switch (glType) { - case GL_BYTE: - return GL_R8; - case GL_UNSIGNED_BYTE: - return GL_R8; - case GL_INT: - return GL_R32I; - case GL_UNSIGNED_INT: - return GL_R32UI; - case GL_FLOAT: - return GL_R32F; - case GL_HALF_FLOAT: - return GL_R16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RG: - switch (glType) { - case GL_BYTE: - return GL_RG8; - case GL_UNSIGNED_BYTE: - return GL_RG8; - case GL_INT: - return GL_RG32I; - case GL_UNSIGNED_INT: - return GL_RG32UI; - case GL_FLOAT: - return GL_RG32F; - case GL_HALF_FLOAT: - return GL_RG16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RGB: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RGBA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::BGR: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::BGRA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - default: - LERROR( - "Unknown format for OpenGL texture: " << - static_cast - >(format) - ); - return GLenum(0); - break; - } -} - -} // namespace tiledatatype -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * 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 + +#ifdef GLOBEBROWSING_USE_GDAL +#include +#include +#endif // GLOBEBROWSING_USE_GDAL + +#include +#include // abspath +#include + +#include + +#include + +#include +#include + +namespace { + const char* _loggerCat = "TileDataType"; +} + +namespace openspace { +namespace globebrowsing { +namespace tiledatatype { + +#ifdef GLOBEBROWSING_USE_GDAL + +float interpretFloat(GDALDataType gdalType, const char* src) { + switch (gdalType) { + case GDT_Byte: + return static_cast(*reinterpret_cast(src)); + case GDT_UInt16: + return static_cast(*reinterpret_cast(src)); + case GDT_Int16: + return static_cast(*reinterpret_cast(src)); + case GDT_UInt32: + return static_cast(*reinterpret_cast(src)); + case GDT_Int32: + return static_cast(*reinterpret_cast(src)); + case GDT_Float32: + return static_cast(*reinterpret_cast(src)); + case GDT_Float64: + return static_cast(*reinterpret_cast(src)); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t numberOfBytes(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return sizeof(GLubyte); + case GDT_UInt16: + return sizeof(GLushort); + case GDT_Int16: + return sizeof(GLshort); + case GDT_UInt32: + return sizeof(GLuint); + case GDT_Int32: + return sizeof(GLint); + case GDT_Float32: + return sizeof(GLfloat); + case GDT_Float64: + return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t getMaximumValue(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return 1 << 8; + case GDT_UInt16: + return 1 << 16; + case GDT_Int16: + return 1 << 15; + case GDT_UInt32: + return size_t(1) << 32; + case GDT_Int32: + return 1 << 31; + default: + ghoul_assert(false, "Unknown data type"); + } +} + +TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType) { + TextureFormat format; + + switch (rasterCount) { + case 1: // Red + format.ghoulFormat = ghoul::opengl::Texture::Format::Red; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_R8; + break; + case GDT_UInt16: + format.glFormat = GL_R16UI; + break; + case GDT_Int16: + format.glFormat = GL_R16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_R32UI; + break; + case GDT_Int32: + format.glFormat = GL_R32I; + break; + case GDT_Float32: + format.glFormat = GL_R32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 2: + format.ghoulFormat = ghoul::opengl::Texture::Format::RG; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RG8; + break; + case GDT_UInt16: + format.glFormat = GL_RG16UI; + break; + case GDT_Int16: + format.glFormat = GL_RG16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RG32UI; + break; + case GDT_Int32: + format.glFormat = GL_RG32I; + break; + case GDT_Float32: + format.glFormat = GL_RG32F; + break; + case GDT_Float64: + format.glFormat = GL_RED; + break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 3: + format.ghoulFormat = ghoul::opengl::Texture::Format::RGB; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGB8; + break; + case GDT_UInt16: + format.glFormat = GL_RGB16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGB32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGB32I; + break; + case GDT_Float32: + format.glFormat = GL_RGB32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 4: + format.ghoulFormat = ghoul::opengl::Texture::Format::RGBA; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGBA8; + break; + case GDT_UInt16: + format.glFormat = GL_RGBA16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGBA32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGBA32I; + break; + case GDT_Float32: + format.glFormat = GL_RGBA32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + default: + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + break; + } + return format; +} + +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType) { + TextureFormat format; + + switch (rasterCount) { + case 1: // Red + format.ghoulFormat = ghoul::opengl::Texture::Format::Red; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_R8; + break; + case GDT_UInt16: + format.glFormat = GL_R16UI; + break; + case GDT_Int16: + format.glFormat = GL_R16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_R32UI; + break; + case GDT_Int32: + format.glFormat = GL_R32I; + break; + case GDT_Float32: + format.glFormat = GL_R32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 2: + format.ghoulFormat = ghoul::opengl::Texture::Format::RG; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RG8; + break; + case GDT_UInt16: + format.glFormat = GL_RG16UI; + break; + case GDT_Int16: + format.glFormat = GL_RG16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RG32UI; + break; + case GDT_Int32: + format.glFormat = GL_RG32I; + break; + case GDT_Float32: + format.glFormat = GL_RG32F; + break; + case GDT_Float64: + format.glFormat = GL_RED; + break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 3: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGR; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGB8; + break; + case GDT_UInt16: + format.glFormat = GL_RGB16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGB32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGB32I; + break; + case GDT_Float32: + format.glFormat = GL_RGB32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 4: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGRA; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGBA8; + break; + case GDT_UInt16: + format.glFormat = GL_RGBA16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGBA32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGBA32I; + break; + case GDT_Float32: + format.glFormat = GL_RGBA32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + default: + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + break; + } + return format; +} + +GLenum getOpenGLDataType(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return GL_UNSIGNED_BYTE; + case GDT_UInt16: + return GL_UNSIGNED_SHORT; + case GDT_Int16: + return GL_SHORT; + case GDT_UInt32: + return GL_UNSIGNED_INT; + case GDT_Int32: + return GL_INT; + case GDT_Float32: + return GL_FLOAT; + case GDT_Float64: + return GL_DOUBLE; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + return GL_UNSIGNED_BYTE; + } +} + +GDALDataType getGdalDataType(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return GDT_Byte; + case GL_UNSIGNED_SHORT: + return GDT_UInt16; + case GL_SHORT: + return GDT_Int16; + case GL_UNSIGNED_INT: + return GDT_UInt32; + case GL_INT: + return GDT_Int32; + case GL_FLOAT: + return GDT_Float32; + case GL_DOUBLE: + return GDT_Float64; + default: + LERROR("OpenGL data type unknown to GDAL: " << glType); + return GDT_Unknown; + } +} + +#endif // GLOBEBROWSING_USE_GDAL + +size_t numberOfRasters(ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: return 1; + case ghoul::opengl::Texture::Format::RG: return 2; + case ghoul::opengl::Texture::Format::RGB:; // Intentional fallthrough + case ghoul::opengl::Texture::Format::BGR: return 3; + case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough + case ghoul::opengl::Texture::Format::BGRA: return 4; + default: ghoul_assert(false, "Unknown format"); + } +} + +size_t numberOfBytes(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_BYTE: return sizeof(GLbyte); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_INT: return sizeof(GLint); + case GL_HALF_FLOAT: return sizeof(GLhalf); + case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t getMaximumValue(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return 1 << 8; + case GL_UNSIGNED_SHORT: + return 1 << 16; + case GL_SHORT: + return 1 << 15; + case GL_UNSIGNED_INT: + return size_t(1) << 32; + case GL_INT: + return 1 << 31; + default: + ghoul_assert(false, "Unknown data type"); + } +} + +float interpretFloat(GLenum glType, const char* src) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_INT: + return static_cast(*reinterpret_cast(src)); + case GL_INT: + return static_cast(*reinterpret_cast(src)); + case GL_HALF_FLOAT: + return static_cast(*reinterpret_cast(src)); + case GL_FLOAT: + return static_cast(*reinterpret_cast(src)); + case GL_DOUBLE: + return static_cast(*reinterpret_cast(src)); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: + switch (glType) { + case GL_BYTE: + return GL_R8; + case GL_UNSIGNED_BYTE: + return GL_R8; + case GL_INT: + return GL_R32I; + case GL_UNSIGNED_INT: + return GL_R32UI; + case GL_FLOAT: + return GL_R32F; + case GL_HALF_FLOAT: + return GL_R16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RG: + switch (glType) { + case GL_BYTE: + return GL_RG8; + case GL_UNSIGNED_BYTE: + return GL_RG8; + case GL_INT: + return GL_RG32I; + case GL_UNSIGNED_INT: + return GL_RG32UI; + case GL_FLOAT: + return GL_RG32F; + case GL_HALF_FLOAT: + return GL_RG16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RGB: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RGBA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::BGR: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::BGRA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + default: + LERROR( + "Unknown format for OpenGL texture: " << + static_cast + >(format) + ); + return GLenum(0); + break; + } +} + +} // namespace tiledatatype +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h index 7476b018e8..a0961bd6d0 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h @@ -1,61 +1,61 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ - -#include -#include - -#include - -#ifdef GLOBEBROWSING_USE_GDAL -#include -#endif // GLOBEBROWSING_USE_GDAL - -namespace openspace { -namespace globebrowsing { -namespace tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL - GLenum getOpenGLDataType(GDALDataType gdalType); -GDALDataType getGdalDataType(GLenum glType); -TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); -TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType); -size_t getMaximumValue(GDALDataType gdalType); -size_t numberOfBytes(GDALDataType gdalType); -float interpretFloat(GDALDataType gdalType, const char* src); -#endif // GLOBEBROWSING_USE_GDAL - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format); -size_t numberOfRasters(ghoul::opengl::Texture::Format format); -size_t numberOfBytes(GLenum glType); -size_t getMaximumValue(GLenum glType); -float interpretFloat(GLenum glType, const char* src); - -} // namespace tiledatatype -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ + +#include +#include + +#include + +#ifdef GLOBEBROWSING_USE_GDAL +#include +#endif // GLOBEBROWSING_USE_GDAL + +namespace openspace { +namespace globebrowsing { +namespace tiledatatype { + +#ifdef GLOBEBROWSING_USE_GDAL + GLenum getOpenGLDataType(GDALDataType gdalType); +GDALDataType getGdalDataType(GLenum glType); +TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType); +size_t getMaximumValue(GDALDataType gdalType); +size_t numberOfBytes(GDALDataType gdalType); +float interpretFloat(GDALDataType gdalType, const char* src); +#endif // GLOBEBROWSING_USE_GDAL + +GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format); +size_t numberOfRasters(ghoul::opengl::Texture::Format format); +size_t numberOfBytes(GLenum glType); +size_t getMaximumValue(GLenum glType); +float interpretFloat(GLenum glType, const char* src); + +} // namespace tiledatatype +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ diff --git a/modules/globebrowsing/tile/textureformat.h b/modules/globebrowsing/tile/textureformat.h index a8a9aa9bb3..607a804faf 100644 --- a/modules/globebrowsing/tile/textureformat.h +++ b/modules/globebrowsing/tile/textureformat.h @@ -1,43 +1,43 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ - -#include -#include - -namespace openspace { -namespace globebrowsing { - -struct TextureFormat { - ghoul::opengl::Texture::Format ghoulFormat; - GLenum glFormat; -}; - - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ + +#include +#include + +namespace openspace { +namespace globebrowsing { + +struct TextureFormat { + ghoul::opengl::Texture::Format ghoulFormat; + GLenum glFormat; +}; + + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ diff --git a/modules/globebrowsing/tile/tiletextureinitdata.cpp b/modules/globebrowsing/tile/tiletextureinitdata.cpp index eddc426296..31045b8534 100644 --- a/modules/globebrowsing/tile/tiletextureinitdata.cpp +++ b/modules/globebrowsing/tile/tiletextureinitdata.cpp @@ -1,152 +1,152 @@ -/***************************************************************************************** - * * - * 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 -#include - -namespace openspace { -namespace globebrowsing { - -const glm::ivec2 TileTextureInitData::tilePixelStartOffset = glm::ivec2(-2); -const glm::ivec2 TileTextureInitData::tilePixelSizeDifference = glm::ivec2(4); - -TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glType, - Format textureFormat, ShouldAllocateDataOnCPU shouldAllocateDataOnCPU) - : _glType(glType) - , _ghoulTextureFormat(textureFormat) - , _shouldAllocateDataOnCPU(shouldAllocateDataOnCPU) -{ - _dimensionsWithoutPadding = glm::ivec3(width, height, 1); - _dimensionsWithPadding = glm::ivec3( - width + tilePixelSizeDifference.x, height + tilePixelSizeDifference.y, 1); - _nRasters = tiledatatype::numberOfRasters(_ghoulTextureFormat); - _bytesPerDatum = tiledatatype::numberOfBytes(glType); - _bytesPerPixel = _nRasters * _bytesPerDatum; - _bytesPerLine = _bytesPerPixel * _dimensionsWithPadding.x; - _totalNumBytes = _bytesPerLine * _dimensionsWithPadding.y; - _glTextureFormat = tiledatatype::glTextureFormat(_glType, - _ghoulTextureFormat); - calculateHashKey(); -}; - -TileTextureInitData::TileTextureInitData(const TileTextureInitData& original) - : TileTextureInitData( - original.dimensionsWithoutPadding().x, - original.dimensionsWithoutPadding().y, - original.glType(), - original.ghoulTextureFormat(), - original.shouldAllocateDataOnCPU() ? ShouldAllocateDataOnCPU::Yes : ShouldAllocateDataOnCPU::No) -{ }; - -glm::ivec3 TileTextureInitData::dimensionsWithPadding() const { - return _dimensionsWithPadding; -} - -glm::ivec3 TileTextureInitData::dimensionsWithoutPadding() const { - return _dimensionsWithoutPadding; -} - -size_t TileTextureInitData::nRasters() const { - return _nRasters; -} - -size_t TileTextureInitData::bytesPerDatum() const { - return _bytesPerDatum; -} - -size_t TileTextureInitData::bytesPerPixel() const { - return _bytesPerPixel; -} - -size_t TileTextureInitData::bytesPerLine() const { - return _bytesPerLine; -} - -size_t TileTextureInitData::totalNumBytes() const { - return _totalNumBytes; -} - -GLenum TileTextureInitData::glType() const { - return _glType; -} - -TileTextureInitData::Format TileTextureInitData::ghoulTextureFormat() const { - return _ghoulTextureFormat; -} - -GLenum TileTextureInitData::glTextureFormat() const { - return _glTextureFormat; -} - -bool TileTextureInitData::shouldAllocateDataOnCPU() const { - return _shouldAllocateDataOnCPU; -} - -TileTextureInitData::HashKey TileTextureInitData::hashKey() const { - return _hashKey; -} - -void TileTextureInitData::calculateHashKey() { - ghoul_assert(_dimensionsWithoutPadding.x > 0, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.y > 0, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.x <= 1024, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.y <= 1024, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.z == 1, "Incorrect dimension"); - unsigned int format = getUniqueIdFromTextureFormat(_ghoulTextureFormat); - ghoul_assert(format < 256, "Incorrect format"); - - _hashKey = 0LL; - - _hashKey |= _dimensionsWithoutPadding.x; - _hashKey |= _dimensionsWithoutPadding.y << 10; - _hashKey |= static_cast>(_glType) << (10 + 16); - _hashKey |= format << (10 + 16 + 4); -}; - -unsigned int TileTextureInitData::getUniqueIdFromTextureFormat( - Format textureFormat) const -{ - using Format = Format; - switch (textureFormat) { - case Format::Red: - return 0; - case Format::RG: - return 1; - case Format::RGB: - return 2; - case Format::BGR: - return 3; - case Format::RGBA: - return 4; - case Format::BGRA: - return 5; - case Format::DepthComponent: - return 6; - default: - ghoul_assert(false, "Unknown texture format"); - } -} - -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * 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 +#include + +namespace openspace { +namespace globebrowsing { + +const glm::ivec2 TileTextureInitData::tilePixelStartOffset = glm::ivec2(-2); +const glm::ivec2 TileTextureInitData::tilePixelSizeDifference = glm::ivec2(4); + +TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glType, + Format textureFormat, ShouldAllocateDataOnCPU shouldAllocateDataOnCPU) + : _glType(glType) + , _ghoulTextureFormat(textureFormat) + , _shouldAllocateDataOnCPU(shouldAllocateDataOnCPU) +{ + _dimensionsWithoutPadding = glm::ivec3(width, height, 1); + _dimensionsWithPadding = glm::ivec3( + width + tilePixelSizeDifference.x, height + tilePixelSizeDifference.y, 1); + _nRasters = tiledatatype::numberOfRasters(_ghoulTextureFormat); + _bytesPerDatum = tiledatatype::numberOfBytes(glType); + _bytesPerPixel = _nRasters * _bytesPerDatum; + _bytesPerLine = _bytesPerPixel * _dimensionsWithPadding.x; + _totalNumBytes = _bytesPerLine * _dimensionsWithPadding.y; + _glTextureFormat = tiledatatype::glTextureFormat(_glType, + _ghoulTextureFormat); + calculateHashKey(); +}; + +TileTextureInitData::TileTextureInitData(const TileTextureInitData& original) + : TileTextureInitData( + original.dimensionsWithoutPadding().x, + original.dimensionsWithoutPadding().y, + original.glType(), + original.ghoulTextureFormat(), + original.shouldAllocateDataOnCPU() ? ShouldAllocateDataOnCPU::Yes : ShouldAllocateDataOnCPU::No) +{ }; + +glm::ivec3 TileTextureInitData::dimensionsWithPadding() const { + return _dimensionsWithPadding; +} + +glm::ivec3 TileTextureInitData::dimensionsWithoutPadding() const { + return _dimensionsWithoutPadding; +} + +size_t TileTextureInitData::nRasters() const { + return _nRasters; +} + +size_t TileTextureInitData::bytesPerDatum() const { + return _bytesPerDatum; +} + +size_t TileTextureInitData::bytesPerPixel() const { + return _bytesPerPixel; +} + +size_t TileTextureInitData::bytesPerLine() const { + return _bytesPerLine; +} + +size_t TileTextureInitData::totalNumBytes() const { + return _totalNumBytes; +} + +GLenum TileTextureInitData::glType() const { + return _glType; +} + +TileTextureInitData::Format TileTextureInitData::ghoulTextureFormat() const { + return _ghoulTextureFormat; +} + +GLenum TileTextureInitData::glTextureFormat() const { + return _glTextureFormat; +} + +bool TileTextureInitData::shouldAllocateDataOnCPU() const { + return _shouldAllocateDataOnCPU; +} + +TileTextureInitData::HashKey TileTextureInitData::hashKey() const { + return _hashKey; +} + +void TileTextureInitData::calculateHashKey() { + ghoul_assert(_dimensionsWithoutPadding.x > 0, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.y > 0, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.x <= 1024, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.y <= 1024, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.z == 1, "Incorrect dimension"); + unsigned int format = getUniqueIdFromTextureFormat(_ghoulTextureFormat); + ghoul_assert(format < 256, "Incorrect format"); + + _hashKey = 0LL; + + _hashKey |= _dimensionsWithoutPadding.x; + _hashKey |= _dimensionsWithoutPadding.y << 10; + _hashKey |= static_cast>(_glType) << (10 + 16); + _hashKey |= format << (10 + 16 + 4); +}; + +unsigned int TileTextureInitData::getUniqueIdFromTextureFormat( + Format textureFormat) const +{ + using Format = Format; + switch (textureFormat) { + case Format::Red: + return 0; + case Format::RG: + return 1; + case Format::RGB: + return 2; + case Format::BGR: + return 3; + case Format::RGBA: + return 4; + case Format::BGRA: + return 5; + case Format::DepthComponent: + return 6; + default: + ghoul_assert(false, "Unknown texture format"); + } +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tiletextureinitdata.h b/modules/globebrowsing/tile/tiletextureinitdata.h index 8dd27c8b0c..874e232933 100644 --- a/modules/globebrowsing/tile/tiletextureinitdata.h +++ b/modules/globebrowsing/tile/tiletextureinitdata.h @@ -1,91 +1,91 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ - -#include -#include -#include - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * All information needed to create a texture used for a Tile. - */ -class TileTextureInitData -{ -public: - using HashKey = unsigned long long; - using ShouldAllocateDataOnCPU = ghoul::Boolean; - using Format = ghoul::opengl::Texture::Format; - - TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat, - ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No); - - TileTextureInitData(const TileTextureInitData& original); - - ~TileTextureInitData() = default; - - glm::ivec3 dimensionsWithPadding() const; - glm::ivec3 dimensionsWithoutPadding() const; - size_t nRasters() const; - size_t bytesPerDatum() const; - size_t bytesPerPixel() const; - size_t bytesPerLine() const; - size_t totalNumBytes() const; - GLenum glType() const; - Format ghoulTextureFormat() const; - GLenum glTextureFormat() const; - bool shouldAllocateDataOnCPU() const; - HashKey hashKey() const; - - const static glm::ivec2 tilePixelStartOffset; - const static glm::ivec2 tilePixelSizeDifference; - -private: - void calculateHashKey(); - unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const; - - HashKey _hashKey; - glm::ivec3 _dimensionsWithPadding; - glm::ivec3 _dimensionsWithoutPadding; - GLenum _glType; - Format _ghoulTextureFormat; - GLenum _glTextureFormat; - size_t _nRasters; - size_t _bytesPerDatum; - size_t _bytesPerPixel; - size_t _bytesPerLine; - size_t _totalNumBytes; - bool _shouldAllocateDataOnCPU; -}; - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ + +#include +#include +#include + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * All information needed to create a texture used for a Tile. + */ +class TileTextureInitData +{ +public: + using HashKey = unsigned long long; + using ShouldAllocateDataOnCPU = ghoul::Boolean; + using Format = ghoul::opengl::Texture::Format; + + TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat, + ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No); + + TileTextureInitData(const TileTextureInitData& original); + + ~TileTextureInitData() = default; + + glm::ivec3 dimensionsWithPadding() const; + glm::ivec3 dimensionsWithoutPadding() const; + size_t nRasters() const; + size_t bytesPerDatum() const; + size_t bytesPerPixel() const; + size_t bytesPerLine() const; + size_t totalNumBytes() const; + GLenum glType() const; + Format ghoulTextureFormat() const; + GLenum glTextureFormat() const; + bool shouldAllocateDataOnCPU() const; + HashKey hashKey() const; + + const static glm::ivec2 tilePixelStartOffset; + const static glm::ivec2 tilePixelSizeDifference; + +private: + void calculateHashKey(); + unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const; + + HashKey _hashKey; + glm::ivec3 _dimensionsWithPadding; + glm::ivec3 _dimensionsWithoutPadding; + GLenum _glType; + Format _ghoulTextureFormat; + GLenum _glTextureFormat; + size_t _nRasters; + size_t _bytesPerDatum; + size_t _bytesPerPixel; + size_t _bytesPerLine; + size_t _totalNumBytes; + bool _shouldAllocateDataOnCPU; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index e22fee5148..e31b2883c2 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -1,950 +1,950 @@ -/***************************************************************************************** - * * - * 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 - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - const char* keyPotentialTargets = "PotentialTargets"; - - const char* keyInstrument = "Instrument.Name"; - const char* keyInstrumentFovy = "Instrument.Fovy"; - const char* keyInstrumentAspect = "Instrument.Aspect"; - - const char* keyTranslation = "DataInputTranslation"; - - const char* keyProjObserver = "Observer"; - const char* keyProjTarget = "Target"; - const char* keyProjAberration = "Aberration"; - - const char* keySequenceDir = "Sequence"; - const char* keySequenceType = "SequenceType"; - - const char* keyNeedsTextureMapDilation = "TextureMap"; - const char* keyNeedsShadowing = "ShadowMap"; - const char* keyTextureMapAspectRatio = "AspectRatio"; - - const char* sequenceTypeImage = "image-sequence"; - const char* sequenceTypePlaybook = "playbook"; - const char* sequenceTypeHybrid = "hybrid"; - const char* sequenceTypeInstrumentTimes = "instrument-times"; - - const char* placeholderFile = - "${OPENSPACE_DATA}/scene/common/textures/placeholder.png"; - - const char* _loggerCat = "ProjectionComponent"; -} - -namespace openspace { - -using ghoul::Dictionary; -using glm::ivec2; - -documentation::Documentation ProjectionComponent::Documentation() { - using namespace documentation; - return { - "Projection Component", - "newhorizons_projectioncomponent", - { - { - keyInstrument, - new StringAnnotationVerifier("A SPICE name of an instrument"), - "The instrument that is used to perform the projections", - Optional::No - }, - { - keyInstrumentFovy, - new DoubleVerifier, - "The field of view in degrees along the y axis", - Optional::No - }, - { - keyInstrumentAspect, - new DoubleVerifier, - "The aspect ratio of the instrument in relation between x and y axis", - Optional::No - }, - { - keyProjObserver, - new StringAnnotationVerifier("A SPICE name of the observing object"), - "The observer that is doing the projection. This has to be a valid SPICE " - "name or SPICE integer.", - Optional::No - }, - { - keyProjTarget, - new StringAnnotationVerifier("A SPICE name of the observed object"), - "The observed object that is projected on. This has to be a valid SPICE " - "name or SPICE integer.", - Optional::No - }, - { - keyProjAberration, - new StringInListVerifier({ - // from SpiceManager::AberrationCorrection::AberrationCorrection - "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S" - }), - "The aberration correction that is supposed to be used for the " - "projection. The values for the correction correspond to the SPICE " - "definition as described in " - "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html", - Optional::No - }, - { - keyPotentialTargets, - new StringListVerifier, - "The list of potential targets that are involved with the image " - "projection", - Optional::Yes - }, - { - keyNeedsTextureMapDilation, - new BoolVerifier, - "Determines whether a dilation step of the texture map has to be " - "performed after each projection. This is necessary if the texture of " - "the projected object is a texture map where the borders are not " - "touching. The default value is 'false'.", - Optional::Yes - }, - { - keyNeedsShadowing, - new BoolVerifier, - "Determines whether the object requires a self-shadowing algorithm. This " - "is necessary if the object is concave and might cast a shadow on itself " - "during presentation. The default value is 'false'.", - Optional::Yes - }, - { - keyTextureMapAspectRatio, - new DoubleVerifier, - "Sets the desired aspect ratio of the projected texture. This might be " - "necessary as planets usually have 2x1 aspect ratios, whereas this does " - "not hold for non-planet objects (comets, asteroids, etc). The default " - "value is '1.0'.", - Optional::Yes - } - - } - }; -} - -ProjectionComponent::ProjectionComponent() - : properties::PropertyOwner("ProjectionComponent") - , _performProjection("performProjection", "Perform Projections", true) - , _clearAllProjections("clearAllProjections", "Clear Projections", false) - , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) - , _textureSize("textureSize", "Texture Size", ivec2(16), ivec2(16), ivec2(32768)) - , _applyTextureSize("applyTextureSize", "Apply Texture Size") - , _textureSizeDirty(false) - , _projectionTexture(nullptr) -{ - _shadowing.isEnabled = false; - _dilation.isEnabled = false; - - addProperty(_performProjection); - addProperty(_clearAllProjections); - addProperty(_projectionFading); - - addProperty(_textureSize); - addProperty(_applyTextureSize); - _applyTextureSize.onChange([this]() { _textureSizeDirty = true; }); -} - -void ProjectionComponent::initialize(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ProjectionComponent" - ); - _instrumentID = dictionary.value(keyInstrument); - _projectorID = dictionary.value(keyProjObserver); - _projecteeID = dictionary.value(keyProjTarget); - _fovy = static_cast(dictionary.value(keyInstrumentFovy)); - _aspectRatio = static_cast(dictionary.value(keyInstrumentAspect)); - - _aberration = SpiceManager::AberrationCorrection( - dictionary.value(keyProjAberration) - ); - - if (dictionary.hasKeyAndValue(keyPotentialTargets)) { - ghoul::Dictionary potentialTargets = dictionary.value( - keyPotentialTargets - ); - - _potentialTargets.reserve(potentialTargets.size()); - for (int i = 1; i <= potentialTargets.size(); ++i) { - _potentialTargets.emplace_back( - potentialTargets.value(std::to_string(i)) - ); - } - } - - if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) { - _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); - } - - if (dictionary.hasKeyAndValue(keyNeedsShadowing)) { - _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); - } - - _projectionTextureAspectRatio = 1.f; - if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) { - _projectionTextureAspectRatio = - static_cast(dictionary.value(keyTextureMapAspectRatio)); - } - - std::string name; - dictionary.getValue(SceneGraphNode::KeyName, name); - - std::vector parsers; - - std::string sequenceSource; - std::string sequenceType; - bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource); - if (foundSequence) { - sequenceSource = absPath(sequenceSource); - - dictionary.getValue(keySequenceType, sequenceType); - //Important: client must define translation-list in mod file IFF playbook - if (dictionary.hasKey(keyTranslation)) { - ghoul::Dictionary translationDictionary; - //get translation dictionary - dictionary.getValue(keyTranslation, translationDictionary); - - if (sequenceType == sequenceTypePlaybook) { - parsers.push_back(new HongKangParser( - name, - sequenceSource, - _projectorID, - translationDictionary, - _potentialTargets)); - } - else if (sequenceType == sequenceTypeImage) { - parsers.push_back(new LabelParser( - name, - sequenceSource, - translationDictionary)); - } - else if (sequenceType == sequenceTypeHybrid) { - //first read labels - parsers.push_back(new LabelParser( - name, - sequenceSource, - translationDictionary)); - - std::string _eventFile; - bool foundEventFile = dictionary.getValue("EventFile", _eventFile); - if (foundEventFile) { - //then read playbook - _eventFile = absPath(_eventFile); - parsers.push_back(new HongKangParser( - name, - _eventFile, - _projectorID, - translationDictionary, - _potentialTargets)); - } - else { - LWARNING("No eventfile has been provided, please check modfiles"); - } - } - else if (sequenceType == sequenceTypeInstrumentTimes) { - parsers.push_back(new InstrumentTimesParser( - name, - sequenceSource, - translationDictionary)); - } - - for (SequenceParser* parser : parsers) { - openspace::ImageSequencer::ref().runSequenceParser(parser); - delete parser; - } - } - else { - LWARNING("No playbook translation provided, please make sure all spice calls match playbook!"); - } - } -} - -bool ProjectionComponent::initializeGL() { - int maxSize = OpenGLCap.max2DTextureSize(); - glm::ivec2 size; - - if (_projectionTextureAspectRatio > 1.f) { - size.x = maxSize; - size.y = static_cast(maxSize / _projectionTextureAspectRatio); - } - else { - size.x = static_cast(maxSize * _projectionTextureAspectRatio); - size.y = maxSize; - } - - _textureSize.setMaxValue(size); - _textureSize = size / 2; - - // We only want to use half the resolution per default: - size /= 2; - - bool success = generateProjectionLayerTexture(size); - success &= generateDepthTexture(size); - success &= auxiliaryRendertarget(); - success &= depthRendertarget(); - - using std::unique_ptr; - using ghoul::opengl::Texture; - using ghoul::io::TextureReader; - - unique_ptr texture = TextureReader::ref().loadTexture(absPath(placeholderFile)); - if (texture) { - texture->uploadTexture(); - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - texture->setFilter(Texture::FilterMode::Linear); - texture->setWrapping(Texture::WrappingMode::ClampToBorder); - } - _placeholderTexture = std::move(texture); - - if (_dilation.isEnabled) { - _dilation.program = ghoul::opengl::ProgramObject::Build( - "Dilation", - "${MODULE_NEWHORIZONS}/shaders/dilation_vs.glsl", - "${MODULE_NEWHORIZONS}/shaders/dilation_fs.glsl" - ); - - const GLfloat plane[] = { - -1, -1, - 1, 1, - -1, 1, - -1, -1, - 1, -1, - 1, 1, - }; - - glGenVertexArrays(1, &_dilation.vao); - glGenBuffers(1, &_dilation.vbo); - - glBindVertexArray(_dilation.vao); - glBindBuffer(GL_ARRAY_BUFFER, _dilation.vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(plane), plane, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(GLfloat) * 2, - reinterpret_cast(0) - ); - - glBindVertexArray(0); - } - - return success; -} - -bool ProjectionComponent::deinitialize() { - _projectionTexture = nullptr; - - glDeleteFramebuffers(1, &_fboID); - - if (_dilation.isEnabled) { - glDeleteFramebuffers(1, &_dilation.fbo); - glDeleteVertexArrays(1, &_dilation.vao); - glDeleteBuffers(1, &_dilation.vbo); - - _dilation.program = nullptr; - _dilation.texture = nullptr; - } - - return true; -} - -bool ProjectionComponent::isReady() const { - return (_projectionTexture != nullptr); -} - -void ProjectionComponent::imageProjectBegin() { - // keep handle to the current bound FBO - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - - if (_textureSizeDirty) { - LDEBUG("Changing texture size to " << std::to_string(_textureSize)); - - // If the texture size has changed, we have to allocate new memory and copy - // the image texture to the new target - - using ghoul::opengl::Texture; - using ghoul::opengl::FramebufferObject; - - // Make a copy of the old textures - std::unique_ptr oldProjectionTexture = std::move(_projectionTexture); - std::unique_ptr oldDilationStencil = std::move(_dilation.stencilTexture); - std::unique_ptr oldDilationTexture = std::move(_dilation.texture); - std::unique_ptr oldDepthTexture = std::move(_shadowing.texture); - - // Generate the new textures - generateProjectionLayerTexture(_textureSize); - - if (_shadowing.isEnabled) { - generateDepthTexture(_textureSize); - } - - auto copyFramebuffers = [](Texture* src, Texture* dst, const std::string& msg) { - glFramebufferTexture( - GL_READ_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *src, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Read Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glFramebufferTexture( - GL_DRAW_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *dst, - 0 - ); - - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Draw Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glBlitFramebuffer( - 0, 0, - src->dimensions().x, src->dimensions().y, - 0, 0, - dst->dimensions().x, dst->dimensions().y, - GL_COLOR_BUFFER_BIT, - GL_LINEAR - ); - }; - - auto copyDepthBuffer = [](Texture* src, Texture* dst, const std::string& msg) { - glFramebufferTexture( - GL_READ_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - *src, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Read Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glFramebufferTexture( - GL_DRAW_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - *dst, - 0 - ); - - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Draw Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glBlitFramebuffer( - 0, 0, - src->dimensions().x, src->dimensions().y, - 0, 0, - dst->dimensions().x, dst->dimensions().y, - GL_DEPTH_BUFFER_BIT, - GL_NEAREST - ); - }; - - GLuint fbos[2]; - glGenFramebuffers(2, fbos); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); - - copyFramebuffers( - oldProjectionTexture.get(), - _projectionTexture.get(), - "Projection" - ); - - if (_dilation.isEnabled) { - copyFramebuffers( - oldDilationStencil.get(), - _dilation.stencilTexture.get(), - "Dilation Stencil" - ); - - copyFramebuffers( - oldDilationTexture.get(), - _dilation.texture.get(), - "Dilation Texture" - ); - } - - if (_shadowing.isEnabled) { - copyDepthBuffer( - oldDepthTexture.get(), - _shadowing.texture.get(), - "Shadowing" - ); - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glDeleteFramebuffers(2, fbos); - - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_projectionTexture, - 0 - ); - - if (_dilation.isEnabled) { - // We only need the stencil texture if we need to dilate - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, - *_dilation.stencilTexture, - 0 - ); - - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_dilation.texture, - 0 - ); - } - - if (_shadowing.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - *_shadowing.texture, - 0 - ); - } - - _textureSizeDirty = false; - } - - glGetIntegerv(GL_VIEWPORT, _viewport); - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - - glViewport( - 0, 0, - static_cast(_projectionTexture->width()), - static_cast(_projectionTexture->height()) - ); - - if (_dilation.isEnabled) { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(2, buffers); - } -} - -bool ProjectionComponent::needsShadowMap() const { - return _shadowing.isEnabled; -} - -ghoul::opengl::Texture& ProjectionComponent::depthTexture() { - return *_shadowing.texture; -} - -void ProjectionComponent::depthMapRenderBegin() { - ghoul_assert(_shadowing.isEnabled, "Shadowing is not enabled"); - - // keep handle to the current bound FBO - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - glGetIntegerv(GL_VIEWPORT, _viewport); - - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glEnable(GL_DEPTH_TEST); - - glViewport( - 0, 0, - static_cast(_shadowing.texture->width()), - static_cast(_shadowing.texture->height()) - ); - - glClear(GL_DEPTH_BUFFER_BIT); -} - -void ProjectionComponent::depthMapRenderEnd() { - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); -} - -void ProjectionComponent::imageProjectEnd() { - if (_dilation.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - - glDisable(GL_BLEND); - - ghoul::opengl::TextureUnit unit[2]; - unit[0].activate(); - _projectionTexture->bind(); - - unit[1].activate(); - _dilation.stencilTexture->bind(); - - _dilation.program->activate(); - _dilation.program->setUniform("tex", unit[0]); - _dilation.program->setUniform("stencil", unit[1]); - - glBindVertexArray(_dilation.vao); - glDrawArrays(GL_TRIANGLES, 0, 6); - - _dilation.program->deactivate(); - - glEnable(GL_BLEND); - } - - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); -} - -void ProjectionComponent::update() { - if (_dilation.isEnabled && _dilation.program->isDirty()) { - _dilation.program->rebuildFromFile(); - } -} - -bool ProjectionComponent::depthRendertarget() { - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - // setup FBO - glGenFramebuffers(1, &_depthFboID); - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - *_shadowing.texture, - 0); - - glDrawBuffer(GL_NONE); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) - return false; - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - return true; -} - -bool ProjectionComponent::auxiliaryRendertarget() { - bool completeSuccess = true; - - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - - // setup FBO - glGenFramebuffers(1, &_fboID); - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_projectionTexture, - 0 - ); - // check FBO status - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main Framebuffer incomplete"); - completeSuccess &= false; - } - - - if (_dilation.isEnabled) { - // We only need the stencil texture if we need to dilate - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, - *_dilation.stencilTexture, - 0 - ); - - // check FBO status - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main Framebuffer incomplete"); - completeSuccess &= false; - } - - glGenFramebuffers(1, &_dilation.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_dilation.texture, - 0 - ); - - // check FBO status - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Dilation Framebuffer incomplete"); - completeSuccess &= false; - } - } - - // switch back to window-system-provided framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - - return completeSuccess; -} - -glm::mat4 ProjectionComponent::computeProjectorMatrix(const glm::vec3 loc, glm::dvec3 aim, - const glm::vec3 up, - const glm::dmat3& instrumentMatrix, - float fieldOfViewY, - float aspectRatio, - float nearPlane, float farPlane, - glm::vec3& boreSight) -{ - - //rotate boresight into correct alignment - boreSight = instrumentMatrix*aim; - glm::vec3 uptmp(instrumentMatrix*glm::dvec3(up)); - - // create view matrix - glm::vec3 e3 = glm::normalize(-boreSight); - glm::vec3 e1 = glm::normalize(glm::cross(uptmp, e3)); - glm::vec3 e2 = glm::normalize(glm::cross(e3, e1)); - - glm::mat4 projViewMatrix = glm::mat4(e1.x, e2.x, e3.x, 0.f, - e1.y, e2.y, e3.y, 0.f, - e1.z, e2.z, e3.z, 0.f, - glm::dot(e1, -loc), glm::dot(e2, -loc), glm::dot(e3, -loc), 1.f); - // create perspective projection matrix - glm::mat4 projProjectionMatrix = glm::perspective(glm::radians(fieldOfViewY), aspectRatio, nearPlane, farPlane); - - return projProjectionMatrix*projViewMatrix; -} - -bool ProjectionComponent::doesPerformProjection() const { - return _performProjection; -} - -bool ProjectionComponent::needsClearProjection() const { - return _clearAllProjections; -} - -float ProjectionComponent::projectionFading() const { - return _projectionFading; -} - -ghoul::opengl::Texture& ProjectionComponent::projectionTexture() const { - if (_dilation.isEnabled) { - return *_dilation.texture; - } - else { - return *_projectionTexture; - } -} - -std::string ProjectionComponent::projectorId() const { - return _projectorID; -} - -std::string ProjectionComponent::projecteeId() const { - return _projecteeID; -} - -std::string ProjectionComponent::instrumentId() const { - return _instrumentID; -} - -SpiceManager::AberrationCorrection ProjectionComponent::aberration() const { - return _aberration; -} - -float ProjectionComponent::fieldOfViewY() const { - return _fovy; -} - -float ProjectionComponent::aspectRatio() const { - return _aspectRatio; -} - -void ProjectionComponent::clearAllProjections() { - // keep handle to the current bound FBO - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - - GLint m_viewport[4]; - glGetIntegerv(GL_VIEWPORT, m_viewport); - //counter = 0; - glViewport(0, 0, static_cast(_projectionTexture->width()), static_cast(_projectionTexture->height())); - - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - - if (_dilation.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glClear(GL_COLOR_BUFFER_BIT); - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - glViewport(m_viewport[0], m_viewport[1], - m_viewport[2], m_viewport[3]); - - _clearAllProjections = false; -} - -std::shared_ptr ProjectionComponent::loadProjectionTexture( - const std::string& texturePath, - bool isPlaceholder) -{ - using std::unique_ptr; - using ghoul::opengl::Texture; - using ghoul::io::TextureReader; - - - if (isPlaceholder) { - return _placeholderTexture; - } - - - unique_ptr texture = TextureReader::ref().loadTexture(absPath(texturePath)); - if (texture) { - if (texture->format() == Texture::Format::Red) - ghoul::opengl::convertTextureFormat(*texture, Texture::Format::RGB); - texture->uploadTexture(); - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - texture->setFilter(Texture::FilterMode::Linear); - texture->setWrapping(Texture::WrappingMode::ClampToBorder); - } - return std::move(texture); -} - -bool ProjectionComponent::generateProjectionLayerTexture(const ivec2& size) { - LINFO( - "Creating projection texture of size '" << size.x << ", " << size.y << "'" - ); - _projectionTexture = std::make_unique ( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::RGBA - ); - if (_projectionTexture) { - _projectionTexture->uploadTexture(); - //_projectionTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - - if (_dilation.isEnabled) { - _dilation.texture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::RGBA - ); - - if (_dilation.texture) { - _dilation.texture->uploadTexture(); - //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - - _dilation.stencilTexture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::Red, - // @TODO: Remove the static cast ---abock - static_cast(ghoul::opengl::Texture::Format::Red) - ); - - if (_dilation.stencilTexture) { - _dilation.stencilTexture->uploadTexture(); - //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - - - return _projectionTexture != nullptr; - -} - -bool ProjectionComponent::generateDepthTexture(const ivec2& size) { - LINFO( - "Creating depth texture of size '" << size.x << ", " << size.y << "'" - ); - - _shadowing.texture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::DepthComponent, - GL_DEPTH_COMPONENT32F - ); - - if (_shadowing.texture) { - _shadowing.texture->uploadTexture(); - } - - return _shadowing.texture != nullptr; - -} - -} // namespace openspace +/***************************************************************************************** + * * + * 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 + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + const char* keyPotentialTargets = "PotentialTargets"; + + const char* keyInstrument = "Instrument.Name"; + const char* keyInstrumentFovy = "Instrument.Fovy"; + const char* keyInstrumentAspect = "Instrument.Aspect"; + + const char* keyTranslation = "DataInputTranslation"; + + const char* keyProjObserver = "Observer"; + const char* keyProjTarget = "Target"; + const char* keyProjAberration = "Aberration"; + + const char* keySequenceDir = "Sequence"; + const char* keySequenceType = "SequenceType"; + + const char* keyNeedsTextureMapDilation = "TextureMap"; + const char* keyNeedsShadowing = "ShadowMap"; + const char* keyTextureMapAspectRatio = "AspectRatio"; + + const char* sequenceTypeImage = "image-sequence"; + const char* sequenceTypePlaybook = "playbook"; + const char* sequenceTypeHybrid = "hybrid"; + const char* sequenceTypeInstrumentTimes = "instrument-times"; + + const char* placeholderFile = + "${OPENSPACE_DATA}/scene/common/textures/placeholder.png"; + + const char* _loggerCat = "ProjectionComponent"; +} + +namespace openspace { + +using ghoul::Dictionary; +using glm::ivec2; + +documentation::Documentation ProjectionComponent::Documentation() { + using namespace documentation; + return { + "Projection Component", + "newhorizons_projectioncomponent", + { + { + keyInstrument, + new StringAnnotationVerifier("A SPICE name of an instrument"), + "The instrument that is used to perform the projections", + Optional::No + }, + { + keyInstrumentFovy, + new DoubleVerifier, + "The field of view in degrees along the y axis", + Optional::No + }, + { + keyInstrumentAspect, + new DoubleVerifier, + "The aspect ratio of the instrument in relation between x and y axis", + Optional::No + }, + { + keyProjObserver, + new StringAnnotationVerifier("A SPICE name of the observing object"), + "The observer that is doing the projection. This has to be a valid SPICE " + "name or SPICE integer.", + Optional::No + }, + { + keyProjTarget, + new StringAnnotationVerifier("A SPICE name of the observed object"), + "The observed object that is projected on. This has to be a valid SPICE " + "name or SPICE integer.", + Optional::No + }, + { + keyProjAberration, + new StringInListVerifier({ + // from SpiceManager::AberrationCorrection::AberrationCorrection + "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S" + }), + "The aberration correction that is supposed to be used for the " + "projection. The values for the correction correspond to the SPICE " + "definition as described in " + "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html", + Optional::No + }, + { + keyPotentialTargets, + new StringListVerifier, + "The list of potential targets that are involved with the image " + "projection", + Optional::Yes + }, + { + keyNeedsTextureMapDilation, + new BoolVerifier, + "Determines whether a dilation step of the texture map has to be " + "performed after each projection. This is necessary if the texture of " + "the projected object is a texture map where the borders are not " + "touching. The default value is 'false'.", + Optional::Yes + }, + { + keyNeedsShadowing, + new BoolVerifier, + "Determines whether the object requires a self-shadowing algorithm. This " + "is necessary if the object is concave and might cast a shadow on itself " + "during presentation. The default value is 'false'.", + Optional::Yes + }, + { + keyTextureMapAspectRatio, + new DoubleVerifier, + "Sets the desired aspect ratio of the projected texture. This might be " + "necessary as planets usually have 2x1 aspect ratios, whereas this does " + "not hold for non-planet objects (comets, asteroids, etc). The default " + "value is '1.0'.", + Optional::Yes + } + + } + }; +} + +ProjectionComponent::ProjectionComponent() + : properties::PropertyOwner("ProjectionComponent") + , _performProjection("performProjection", "Perform Projections", true) + , _clearAllProjections("clearAllProjections", "Clear Projections", false) + , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) + , _textureSize("textureSize", "Texture Size", ivec2(16), ivec2(16), ivec2(32768)) + , _applyTextureSize("applyTextureSize", "Apply Texture Size") + , _textureSizeDirty(false) + , _projectionTexture(nullptr) +{ + _shadowing.isEnabled = false; + _dilation.isEnabled = false; + + addProperty(_performProjection); + addProperty(_clearAllProjections); + addProperty(_projectionFading); + + addProperty(_textureSize); + addProperty(_applyTextureSize); + _applyTextureSize.onChange([this]() { _textureSizeDirty = true; }); +} + +void ProjectionComponent::initialize(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "ProjectionComponent" + ); + _instrumentID = dictionary.value(keyInstrument); + _projectorID = dictionary.value(keyProjObserver); + _projecteeID = dictionary.value(keyProjTarget); + _fovy = static_cast(dictionary.value(keyInstrumentFovy)); + _aspectRatio = static_cast(dictionary.value(keyInstrumentAspect)); + + _aberration = SpiceManager::AberrationCorrection( + dictionary.value(keyProjAberration) + ); + + if (dictionary.hasKeyAndValue(keyPotentialTargets)) { + ghoul::Dictionary potentialTargets = dictionary.value( + keyPotentialTargets + ); + + _potentialTargets.reserve(potentialTargets.size()); + for (int i = 1; i <= potentialTargets.size(); ++i) { + _potentialTargets.emplace_back( + potentialTargets.value(std::to_string(i)) + ); + } + } + + if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) { + _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); + } + + if (dictionary.hasKeyAndValue(keyNeedsShadowing)) { + _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); + } + + _projectionTextureAspectRatio = 1.f; + if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) { + _projectionTextureAspectRatio = + static_cast(dictionary.value(keyTextureMapAspectRatio)); + } + + std::string name; + dictionary.getValue(SceneGraphNode::KeyName, name); + + std::vector parsers; + + std::string sequenceSource; + std::string sequenceType; + bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource); + if (foundSequence) { + sequenceSource = absPath(sequenceSource); + + dictionary.getValue(keySequenceType, sequenceType); + //Important: client must define translation-list in mod file IFF playbook + if (dictionary.hasKey(keyTranslation)) { + ghoul::Dictionary translationDictionary; + //get translation dictionary + dictionary.getValue(keyTranslation, translationDictionary); + + if (sequenceType == sequenceTypePlaybook) { + parsers.push_back(new HongKangParser( + name, + sequenceSource, + _projectorID, + translationDictionary, + _potentialTargets)); + } + else if (sequenceType == sequenceTypeImage) { + parsers.push_back(new LabelParser( + name, + sequenceSource, + translationDictionary)); + } + else if (sequenceType == sequenceTypeHybrid) { + //first read labels + parsers.push_back(new LabelParser( + name, + sequenceSource, + translationDictionary)); + + std::string _eventFile; + bool foundEventFile = dictionary.getValue("EventFile", _eventFile); + if (foundEventFile) { + //then read playbook + _eventFile = absPath(_eventFile); + parsers.push_back(new HongKangParser( + name, + _eventFile, + _projectorID, + translationDictionary, + _potentialTargets)); + } + else { + LWARNING("No eventfile has been provided, please check modfiles"); + } + } + else if (sequenceType == sequenceTypeInstrumentTimes) { + parsers.push_back(new InstrumentTimesParser( + name, + sequenceSource, + translationDictionary)); + } + + for (SequenceParser* parser : parsers) { + openspace::ImageSequencer::ref().runSequenceParser(parser); + delete parser; + } + } + else { + LWARNING("No playbook translation provided, please make sure all spice calls match playbook!"); + } + } +} + +bool ProjectionComponent::initializeGL() { + int maxSize = OpenGLCap.max2DTextureSize(); + glm::ivec2 size; + + if (_projectionTextureAspectRatio > 1.f) { + size.x = maxSize; + size.y = static_cast(maxSize / _projectionTextureAspectRatio); + } + else { + size.x = static_cast(maxSize * _projectionTextureAspectRatio); + size.y = maxSize; + } + + _textureSize.setMaxValue(size); + _textureSize = size / 2; + + // We only want to use half the resolution per default: + size /= 2; + + bool success = generateProjectionLayerTexture(size); + success &= generateDepthTexture(size); + success &= auxiliaryRendertarget(); + success &= depthRendertarget(); + + using std::unique_ptr; + using ghoul::opengl::Texture; + using ghoul::io::TextureReader; + + unique_ptr texture = TextureReader::ref().loadTexture(absPath(placeholderFile)); + if (texture) { + texture->uploadTexture(); + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + texture->setFilter(Texture::FilterMode::Linear); + texture->setWrapping(Texture::WrappingMode::ClampToBorder); + } + _placeholderTexture = std::move(texture); + + if (_dilation.isEnabled) { + _dilation.program = ghoul::opengl::ProgramObject::Build( + "Dilation", + "${MODULE_NEWHORIZONS}/shaders/dilation_vs.glsl", + "${MODULE_NEWHORIZONS}/shaders/dilation_fs.glsl" + ); + + const GLfloat plane[] = { + -1, -1, + 1, 1, + -1, 1, + -1, -1, + 1, -1, + 1, 1, + }; + + glGenVertexArrays(1, &_dilation.vao); + glGenBuffers(1, &_dilation.vbo); + + glBindVertexArray(_dilation.vao); + glBindBuffer(GL_ARRAY_BUFFER, _dilation.vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(plane), plane, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(GLfloat) * 2, + reinterpret_cast(0) + ); + + glBindVertexArray(0); + } + + return success; +} + +bool ProjectionComponent::deinitialize() { + _projectionTexture = nullptr; + + glDeleteFramebuffers(1, &_fboID); + + if (_dilation.isEnabled) { + glDeleteFramebuffers(1, &_dilation.fbo); + glDeleteVertexArrays(1, &_dilation.vao); + glDeleteBuffers(1, &_dilation.vbo); + + _dilation.program = nullptr; + _dilation.texture = nullptr; + } + + return true; +} + +bool ProjectionComponent::isReady() const { + return (_projectionTexture != nullptr); +} + +void ProjectionComponent::imageProjectBegin() { + // keep handle to the current bound FBO + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + + if (_textureSizeDirty) { + LDEBUG("Changing texture size to " << std::to_string(_textureSize)); + + // If the texture size has changed, we have to allocate new memory and copy + // the image texture to the new target + + using ghoul::opengl::Texture; + using ghoul::opengl::FramebufferObject; + + // Make a copy of the old textures + std::unique_ptr oldProjectionTexture = std::move(_projectionTexture); + std::unique_ptr oldDilationStencil = std::move(_dilation.stencilTexture); + std::unique_ptr oldDilationTexture = std::move(_dilation.texture); + std::unique_ptr oldDepthTexture = std::move(_shadowing.texture); + + // Generate the new textures + generateProjectionLayerTexture(_textureSize); + + if (_shadowing.isEnabled) { + generateDepthTexture(_textureSize); + } + + auto copyFramebuffers = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_COLOR_BUFFER_BIT, + GL_LINEAR + ); + }; + + auto copyDepthBuffer = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_DEPTH_BUFFER_BIT, + GL_NEAREST + ); + }; + + GLuint fbos[2]; + glGenFramebuffers(2, fbos); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); + + copyFramebuffers( + oldProjectionTexture.get(), + _projectionTexture.get(), + "Projection" + ); + + if (_dilation.isEnabled) { + copyFramebuffers( + oldDilationStencil.get(), + _dilation.stencilTexture.get(), + "Dilation Stencil" + ); + + copyFramebuffers( + oldDilationTexture.get(), + _dilation.texture.get(), + "Dilation Texture" + ); + } + + if (_shadowing.isEnabled) { + copyDepthBuffer( + oldDepthTexture.get(), + _shadowing.texture.get(), + "Shadowing" + ); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(2, fbos); + + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_projectionTexture, + 0 + ); + + if (_dilation.isEnabled) { + // We only need the stencil texture if we need to dilate + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + *_dilation.stencilTexture, + 0 + ); + + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_dilation.texture, + 0 + ); + } + + if (_shadowing.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_shadowing.texture, + 0 + ); + } + + _textureSizeDirty = false; + } + + glGetIntegerv(GL_VIEWPORT, _viewport); + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + + glViewport( + 0, 0, + static_cast(_projectionTexture->width()), + static_cast(_projectionTexture->height()) + ); + + if (_dilation.isEnabled) { + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(2, buffers); + } +} + +bool ProjectionComponent::needsShadowMap() const { + return _shadowing.isEnabled; +} + +ghoul::opengl::Texture& ProjectionComponent::depthTexture() { + return *_shadowing.texture; +} + +void ProjectionComponent::depthMapRenderBegin() { + ghoul_assert(_shadowing.isEnabled, "Shadowing is not enabled"); + + // keep handle to the current bound FBO + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + glGetIntegerv(GL_VIEWPORT, _viewport); + + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glEnable(GL_DEPTH_TEST); + + glViewport( + 0, 0, + static_cast(_shadowing.texture->width()), + static_cast(_shadowing.texture->height()) + ); + + glClear(GL_DEPTH_BUFFER_BIT); +} + +void ProjectionComponent::depthMapRenderEnd() { + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); +} + +void ProjectionComponent::imageProjectEnd() { + if (_dilation.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + + glDisable(GL_BLEND); + + ghoul::opengl::TextureUnit unit[2]; + unit[0].activate(); + _projectionTexture->bind(); + + unit[1].activate(); + _dilation.stencilTexture->bind(); + + _dilation.program->activate(); + _dilation.program->setUniform("tex", unit[0]); + _dilation.program->setUniform("stencil", unit[1]); + + glBindVertexArray(_dilation.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _dilation.program->deactivate(); + + glEnable(GL_BLEND); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); +} + +void ProjectionComponent::update() { + if (_dilation.isEnabled && _dilation.program->isDirty()) { + _dilation.program->rebuildFromFile(); + } +} + +bool ProjectionComponent::depthRendertarget() { + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + // setup FBO + glGenFramebuffers(1, &_depthFboID); + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_shadowing.texture, + 0); + + glDrawBuffer(GL_NONE); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + return true; +} + +bool ProjectionComponent::auxiliaryRendertarget() { + bool completeSuccess = true; + + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + + // setup FBO + glGenFramebuffers(1, &_fboID); + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_projectionTexture, + 0 + ); + // check FBO status + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main Framebuffer incomplete"); + completeSuccess &= false; + } + + + if (_dilation.isEnabled) { + // We only need the stencil texture if we need to dilate + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + *_dilation.stencilTexture, + 0 + ); + + // check FBO status + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main Framebuffer incomplete"); + completeSuccess &= false; + } + + glGenFramebuffers(1, &_dilation.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_dilation.texture, + 0 + ); + + // check FBO status + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Dilation Framebuffer incomplete"); + completeSuccess &= false; + } + } + + // switch back to window-system-provided framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + + return completeSuccess; +} + +glm::mat4 ProjectionComponent::computeProjectorMatrix(const glm::vec3 loc, glm::dvec3 aim, + const glm::vec3 up, + const glm::dmat3& instrumentMatrix, + float fieldOfViewY, + float aspectRatio, + float nearPlane, float farPlane, + glm::vec3& boreSight) +{ + + //rotate boresight into correct alignment + boreSight = instrumentMatrix*aim; + glm::vec3 uptmp(instrumentMatrix*glm::dvec3(up)); + + // create view matrix + glm::vec3 e3 = glm::normalize(-boreSight); + glm::vec3 e1 = glm::normalize(glm::cross(uptmp, e3)); + glm::vec3 e2 = glm::normalize(glm::cross(e3, e1)); + + glm::mat4 projViewMatrix = glm::mat4(e1.x, e2.x, e3.x, 0.f, + e1.y, e2.y, e3.y, 0.f, + e1.z, e2.z, e3.z, 0.f, + glm::dot(e1, -loc), glm::dot(e2, -loc), glm::dot(e3, -loc), 1.f); + // create perspective projection matrix + glm::mat4 projProjectionMatrix = glm::perspective(glm::radians(fieldOfViewY), aspectRatio, nearPlane, farPlane); + + return projProjectionMatrix*projViewMatrix; +} + +bool ProjectionComponent::doesPerformProjection() const { + return _performProjection; +} + +bool ProjectionComponent::needsClearProjection() const { + return _clearAllProjections; +} + +float ProjectionComponent::projectionFading() const { + return _projectionFading; +} + +ghoul::opengl::Texture& ProjectionComponent::projectionTexture() const { + if (_dilation.isEnabled) { + return *_dilation.texture; + } + else { + return *_projectionTexture; + } +} + +std::string ProjectionComponent::projectorId() const { + return _projectorID; +} + +std::string ProjectionComponent::projecteeId() const { + return _projecteeID; +} + +std::string ProjectionComponent::instrumentId() const { + return _instrumentID; +} + +SpiceManager::AberrationCorrection ProjectionComponent::aberration() const { + return _aberration; +} + +float ProjectionComponent::fieldOfViewY() const { + return _fovy; +} + +float ProjectionComponent::aspectRatio() const { + return _aspectRatio; +} + +void ProjectionComponent::clearAllProjections() { + // keep handle to the current bound FBO + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + + GLint m_viewport[4]; + glGetIntegerv(GL_VIEWPORT, m_viewport); + //counter = 0; + glViewport(0, 0, static_cast(_projectionTexture->width()), static_cast(_projectionTexture->height())); + + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + + if (_dilation.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glClear(GL_COLOR_BUFFER_BIT); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + glViewport(m_viewport[0], m_viewport[1], + m_viewport[2], m_viewport[3]); + + _clearAllProjections = false; +} + +std::shared_ptr ProjectionComponent::loadProjectionTexture( + const std::string& texturePath, + bool isPlaceholder) +{ + using std::unique_ptr; + using ghoul::opengl::Texture; + using ghoul::io::TextureReader; + + + if (isPlaceholder) { + return _placeholderTexture; + } + + + unique_ptr texture = TextureReader::ref().loadTexture(absPath(texturePath)); + if (texture) { + if (texture->format() == Texture::Format::Red) + ghoul::opengl::convertTextureFormat(*texture, Texture::Format::RGB); + texture->uploadTexture(); + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + texture->setFilter(Texture::FilterMode::Linear); + texture->setWrapping(Texture::WrappingMode::ClampToBorder); + } + return std::move(texture); +} + +bool ProjectionComponent::generateProjectionLayerTexture(const ivec2& size) { + LINFO( + "Creating projection texture of size '" << size.x << ", " << size.y << "'" + ); + _projectionTexture = std::make_unique ( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::RGBA + ); + if (_projectionTexture) { + _projectionTexture->uploadTexture(); + //_projectionTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + + if (_dilation.isEnabled) { + _dilation.texture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::RGBA + ); + + if (_dilation.texture) { + _dilation.texture->uploadTexture(); + //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + + _dilation.stencilTexture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::Red, + // @TODO: Remove the static cast ---abock + static_cast(ghoul::opengl::Texture::Format::Red) + ); + + if (_dilation.stencilTexture) { + _dilation.stencilTexture->uploadTexture(); + //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + + + return _projectionTexture != nullptr; + +} + +bool ProjectionComponent::generateDepthTexture(const ivec2& size) { + LINFO( + "Creating depth texture of size '" << size.x << ", " << size.y << "'" + ); + + _shadowing.texture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::DepthComponent, + GL_DEPTH_COMPONENT32F + ); + + if (_shadowing.texture) { + _shadowing.texture->uploadTexture(); + } + + return _shadowing.texture != nullptr; + +} + +} // namespace openspace diff --git a/modules/space/rendering/renderableplanet.cpp b/modules/space/rendering/renderableplanet.cpp index 2d05de4755..70e196d223 100644 --- a/modules/space/rendering/renderableplanet.cpp +++ b/modules/space/rendering/renderableplanet.cpp @@ -1,563 +1,563 @@ -/***************************************************************************************** - * * - * 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 - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _USE_MATH_DEFINES -#include - - -namespace { - const char* KeyGeometry = "Geometry"; - const char* KeyRadius = "Radius"; - const char* KeyColorTexture = "Textures.Color"; - const char* KeyNightTexture = "Textures.Night"; - const char* KeyHeightTexture = "Textures.Height"; - const char* KeyShading = "PerformShading"; - - - - static const std::string _loggerCat = "RenderablePlanet"; - - const char* keyFrame = "Frame"; - const char* keyShadowGroup = "Shadow_Group"; - const char* keyShadowSource = "Source"; - const char* keyShadowCaster = "Caster"; - const char* keyBody = "Body"; -} // namespace - -namespace openspace { - -documentation::Documentation RenderablePlanet::Documentation() { - using namespace documentation; - return { - "RenderablePlanet", - "space_renderable_planet", - { - { - KeyGeometry, - new ReferencingVerifier("space_geometry_planet"), - "Specifies the planet geometry that is used for this RenderablePlanet.", - Optional::No - }, - { - KeyRadius, - new DoubleVerifier, - "Specifies the radius of the planet. If this value is not specified, it " - "will try to query the SPICE library for radius values.", - Optional::Yes - }, - { - KeyColorTexture, - new StringVerifier, - "Specifies the color texture that is used for this RenderablePlanet.", - Optional::Yes - }, - { - KeyHeightTexture, - new StringVerifier, - "Specifies the height texture that is used for this RenderablePlanet.", - Optional::Yes - }, - { - KeyNightTexture, - new StringVerifier, - "Specifies the texture that is used for the night side of this " - "RenderablePlanet.", - Optional::Yes - }, - { - KeyShading, - new BoolVerifier, - "Specifies whether the planet should be rendered shaded by the Sun. If " - "this value is 'false', any existing night texture will not be used. " - "This value defaults to 'true'.", - Optional::Yes - } - } - }; -} - -RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _colorTexturePath("colorTexture", "Color Texture") - , _nightTexturePath("nightTexture", "Night Texture") - , _heightMapTexturePath("heightMap", "Heightmap Texture") - , _programObject(nullptr) - , _texture(nullptr) - , _nightTexture(nullptr) - , _heightExaggeration("heightExaggeration", "Height Exaggeration", 1.f, 0.f, 10.f) - , _geometry(nullptr) - , _performShading("performShading", "Perform Shading", true) - , _alpha(1.f) - , _planetRadius(0.f) - , _hasNightTexture(false) - , _hasHeightTexture(false) - , _shadowEnabled(false) -{ - ghoul_precondition( - dictionary.hasKeyAndValue(SceneGraphNode::KeyName), - "RenderablePlanet needs the name to be specified" - ); - - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlanet" - ); - - const std::string name = dictionary.value(SceneGraphNode::KeyName); - - ghoul::Dictionary geomDict = dictionary.value(KeyGeometry); - - if (dictionary.hasKey(KeyRadius)) { - // If the user specified a radius, we want to use this - _planetRadius = dictionary.value(KeyRadius); - } - else if (SpiceManager::ref().hasValue(name, "RADII") ) { - // If the user didn't specfify a radius, but Spice has a radius, we can use this - glm::dvec3 radius; - SpiceManager::ref().getValue(name, "RADII", radius); - radius *= 1000.0; // Spice gives radii in KM. - std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system - geomDict.setValue(KeyRadius, radius); - - _planetRadius = (radius.x + radius.y + radius.z) / 3.0; - } - else { - LERRORC("RenderablePlanet", "Missing radius specification"); - } - - _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geomDict); - - if (dictionary.hasKey(KeyColorTexture)) { - _colorTexturePath = absPath(dictionary.value(KeyColorTexture)); - } - - if (dictionary.hasKey(KeyNightTexture)) { - _hasNightTexture = true; - _nightTexturePath = absPath(dictionary.value(KeyNightTexture)); - } - - if (dictionary.hasKey(KeyHeightTexture)) { - _hasHeightTexture = true; - _heightMapTexturePath = absPath(dictionary.value(KeyHeightTexture)); - } - - if (dictionary.hasKey(KeyShading)) { - _performShading = dictionary.value(KeyShading); - } - - addPropertySubOwner(_geometry.get()); - - auto loadTextureCallback = [this]() {loadTexture(); }; - addProperty(_colorTexturePath); - _colorTexturePath.onChange(loadTextureCallback); - - addProperty(_nightTexturePath); - _nightTexturePath.onChange(loadTextureCallback); - - addProperty(_heightMapTexturePath); - _heightMapTexturePath.onChange(loadTextureCallback); - - addProperty(_heightExaggeration); - addProperty(_performShading); - - // Shadow data: - ghoul::Dictionary shadowDictionary; - bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); - bool disableShadows = false; - if (success) { - std::vector< std::pair > sourceArray; - unsigned int sourceCounter = 1; - while (success) { - std::string sourceName; - std::stringstream ss; - ss << keyShadowSource << sourceCounter << ".Name"; - success = shadowDictionary.getValue(ss.str(), sourceName); - if (success) { - float sourceRadius; - ss.str(std::string()); - ss << keyShadowSource << sourceCounter << ".Radius"; - success = shadowDictionary.getValue(ss.str(), sourceRadius); - if (success) { - sourceArray.push_back(std::pair< std::string, float>( - sourceName, sourceRadius)); - } - else { - LWARNING("No Radius value expecified for Shadow Source Name " - << sourceName << " from " << name - << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - sourceCounter++; - } - - if (!disableShadows && !sourceArray.empty()) { - success = true; - std::vector< std::pair > casterArray; - unsigned int casterCounter = 1; - while (success) { - std::string casterName; - std::stringstream ss; - ss << keyShadowCaster << casterCounter << ".Name"; - success = shadowDictionary.getValue(ss.str(), casterName); - if (success) { - float casterRadius; - ss.str(std::string()); - ss << keyShadowCaster << casterCounter << ".Radius"; - success = shadowDictionary.getValue(ss.str(), casterRadius); - if (success) { - casterArray.push_back(std::pair< std::string, float>( - casterName, casterRadius)); - } - else { - LWARNING("No Radius value expecified for Shadow Caster Name " - << casterName << " from " << name - << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - - casterCounter++; - } - - if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { - for (const auto & source : sourceArray) - for (const auto & caster : casterArray) { - ShadowConf sc; - sc.source = source; - sc.caster = caster; - _shadowConfArray.push_back(sc); - } - _shadowEnabled = true; - } - } - } -} - -bool RenderablePlanet::initialize() { - RenderEngine& renderEngine = OsEng.renderEngine(); - - if (_programObject == nullptr && _shadowEnabled && _hasNightTexture) { - // shadow program - _programObject = renderEngine.buildRenderProgram( - "shadowNightProgram", - "${MODULE_SPACE}/shaders/shadow_nighttexture_vs.glsl", - "${MODULE_SPACE}/shaders/shadow_nighttexture_fs.glsl"); - } - else if (_programObject == nullptr && _shadowEnabled) { - // shadow program - _programObject = renderEngine.buildRenderProgram( - "shadowProgram", - "${MODULE_SPACE}/shaders/shadow_vs.glsl", - "${MODULE_SPACE}/shaders/shadow_fs.glsl"); - } - else if (_programObject == nullptr && _hasNightTexture) { - // Night texture program - _programObject = renderEngine.buildRenderProgram( - "nightTextureProgram", - "${MODULE_SPACE}/shaders/nighttexture_vs.glsl", - "${MODULE_SPACE}/shaders/nighttexture_fs.glsl"); - } - else if (_programObject == nullptr) { - // pscstandard - _programObject = renderEngine.buildRenderProgram( - "pscstandard", - "${MODULE_SPACE}/shaders/renderableplanet_vs.glsl", - "${MODULE_SPACE}/shaders/renderableplanet_fs.glsl"); - } - using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; - _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); - _programObject->setIgnoreUniformLocationError(IgnoreError::Yes); - - _geometry->initialize(this); - - _programObject->deactivate(); - - loadTexture(); - - return isReady(); -} - -bool RenderablePlanet::deinitialize() { - if (_geometry) { - _geometry->deinitialize(); - _geometry = nullptr; - } - - RenderEngine& renderEngine = OsEng.renderEngine(); - if (_programObject) { - renderEngine.removeRenderProgram(_programObject); - _programObject = nullptr; - } - - _geometry = nullptr; - _texture = nullptr; - _nightTexture = nullptr; - - return true; -} - -bool RenderablePlanet::isReady() const { - bool ready = true; - ready &= (_programObject != nullptr); - ready &= (_texture != nullptr); - ready &= (_geometry != nullptr); - return ready; -} - -void RenderablePlanet::render(const RenderData& data) { - // activate shader - _programObject->activate(); - - glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation - glm::dmat4(data.modelTransform.rotation) * // Spice rotation - glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); - - // scale the planet to appropriate size since the planet is a unit sphere - //glm::mat4 transform = glm::mat4(1); - - //earth needs to be rotated for that to work. - glm::dmat4 rot = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(1, 0, 0)); - glm::dmat4 roty = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(0, -1, 0)); - //glm::dmat4 rotProp = glm::rotate(glm::dmat4(1.0), glm::radians(static_cast(_rotation)), glm::dvec3(0, 1, 0)); - modelTransform = modelTransform * rot * roty /** rotProp*/; - - glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; - - _programObject->setUniform("transparency", _alpha); - _programObject->setUniform( - "modelViewProjectionTransform", - data.camera.projectionMatrix() * glm::mat4(modelViewTransform) - ); - _programObject->setUniform("ModelTransform", glm::mat4(modelTransform)); - - // Normal Transformation - glm::mat4 translateObjTrans = glm::translate(glm::mat4(1.0), data.position.vec3()); - glm::mat4 translateCamTrans = glm::translate(glm::mat4(1.0), -data.camera.position().vec3()); - float scaleFactor = data.camera.scaling().x * powf(10.0, data.camera.scaling().y); - glm::mat4 scaleCamTrans = glm::scale(glm::mat4(1.0), glm::vec3(scaleFactor)); - -// glm::mat4 ModelViewTrans = data.camera.viewMatrix() * scaleCamTrans * -// translateCamTrans * translateObjTrans * glm::mat4(modelTransform); - - setPscUniforms(*_programObject.get(), data.camera, data.position); - - _programObject->setUniform("_performShading", _performShading); - - _programObject->setUniform("_hasHeightMap", _hasHeightTexture); - _programObject->setUniform("_heightExaggeration", _heightExaggeration); - - // Bind texture - ghoul::opengl::TextureUnit dayUnit; - ghoul::opengl::TextureUnit nightUnit; - ghoul::opengl::TextureUnit heightUnit; - - - dayUnit.activate(); - _texture->bind(); - _programObject->setUniform("texture1", dayUnit); - - // Bind possible night texture - if (_hasNightTexture && _nightTexture) { - nightUnit.activate(); - _nightTexture->bind(); - _programObject->setUniform("nightTex", nightUnit); - } - - if (_hasHeightTexture && _heightMapTexture) { - heightUnit.activate(); - _heightMapTexture->bind(); - _programObject->setUniform("heightTex", heightUnit); - } - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - // TODO: Move Calculations to VIEW SPACE (precision problems avoidance...) - - double lt; - // Shadow calculations.. - if (!_shadowConfArray.empty()) { - std::vector shadowDataArray; - shadowDataArray.reserve(_shadowConfArray.size()); - - for (const auto & shadowConf : _shadowConfArray) { - // TO REMEMBER: all distances and lengths in world coordinates are in meters!!! We need to move this to view space... - // Getting source and caster: - glm::dvec3 sourcePos = SpiceManager::ref().targetPosition(shadowConf.source.first, "SUN", "GALACTIC", {}, _time, lt); - sourcePos *= 1000.0; // converting to meters - glm::dvec3 casterPos = SpiceManager::ref().targetPosition(shadowConf.caster.first, "SUN", "GALACTIC", {}, _time, lt); - casterPos *= 1000.0; // converting to meters - psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(casterPos.x, casterPos.y, casterPos.z); - - - // First we determine if the caster is shadowing the current planet (all calculations in World Coordinates): - glm::vec3 planetCasterVec = (caster_pos - data.position).vec3(); - glm::vec3 sourceCasterVec = glm::vec3(casterPos - sourcePos); - float sc_length = glm::length(sourceCasterVec); - glm::vec3 planetCaster_proj = (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * sourceCasterVec; - float d_test = glm::length(planetCasterVec - planetCaster_proj); - float xp_test = shadowConf.caster.second * sc_length / (shadowConf.source.second + shadowConf.caster.second); - float rp_test = shadowConf.caster.second * (glm::length(planetCaster_proj) + xp_test) / xp_test; - - double casterDistSun = glm::length(casterPos); - float planetDistSun = glm::length(data.position.vec3()); - - ShadowRenderingStruct shadowData; - shadowData.isShadowing = false; - - if (((d_test - rp_test) < _planetRadius) && - (casterDistSun < planetDistSun) ) { - // The current caster is shadowing the current planet - shadowData.isShadowing = true; - shadowData.rs = shadowConf.source.second; - shadowData.rc = shadowConf.caster.second; - shadowData.sourceCasterVec = sourceCasterVec; - shadowData.xp = xp_test; - shadowData.xu = shadowData.rc * sc_length / (shadowData.rs - shadowData.rc); - shadowData.casterPositionVec = glm::vec3(casterPos); - } - shadowDataArray.push_back(shadowData); - } - - const std::string uniformVarName("shadowDataArray["); - unsigned int counter = 0; - for (const auto & sd : shadowDataArray) { - std::stringstream ss; - ss << uniformVarName << counter << "].isShadowing"; - _programObject->setUniform(ss.str(), sd.isShadowing); - if (sd.isShadowing) { - ss.str(std::string()); - ss << uniformVarName << counter << "].xp"; - _programObject->setUniform(ss.str(), sd.xp); - ss.str(std::string()); - ss << uniformVarName << counter << "].xu"; - _programObject->setUniform(ss.str(), sd.xu); - /*ss.str(std::string()); - ss << uniformVarName << counter << "].rs"; - _programObject->setUniform(ss.str(), sd.rs);*/ - ss.str(std::string()); - ss << uniformVarName << counter << "].rc"; - _programObject->setUniform(ss.str(), sd.rc); - ss.str(std::string()); - ss << uniformVarName << counter << "].sourceCasterVec"; - _programObject->setUniform(ss.str(), sd.sourceCasterVec); - ss.str(std::string()); - ss << uniformVarName << counter << "].casterPositionVec"; - _programObject->setUniform(ss.str(), sd.casterPositionVec); - } - counter++; - } - } - - // render - _geometry->render(); - - // disable shader - _programObject->deactivate(); - -} - -void RenderablePlanet::update(const UpdateData& data) { - // set spice-orientation in accordance to timestamp - _stateMatrix = data.modelTransform.rotation; - //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); - _time = data.time.j2000Seconds(); -} - -void RenderablePlanet::loadTexture() { - _texture = nullptr; - if (_colorTexturePath.value() != "") { - _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)); - if (_texture) { - if (_texture->numberOfChannels() == 1) { - _texture->setSwizzleMask({ GL_RED, GL_RED, GL_RED, GL_RED }); - } - - LDEBUG("Loaded texture from '" << _colorTexturePath << "'"); - _texture->uploadTexture(); - - // Textures of planets looks much smoother with AnisotropicMipMap rather than linear - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - } - } - - if (_hasNightTexture) { - _nightTexture = nullptr; - if (_nightTexturePath.value() != "") { - _nightTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_nightTexturePath)); - if (_nightTexture) { - LDEBUG("Loaded texture from '" << _nightTexturePath << "'"); - _nightTexture->uploadTexture(); - _nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - } - - if (_hasHeightTexture) { - _heightMapTexture = nullptr; - if (_heightMapTexturePath.value() != "") { - _heightMapTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_heightMapTexturePath)); - if (_heightMapTexture) { - LDEBUG("Loaded texture from '" << _heightMapTexturePath << "'"); - _heightMapTexture->uploadTexture(); - _heightMapTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - } -} - -} // namespace openspace +/***************************************************************************************** + * * + * 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _USE_MATH_DEFINES +#include + + +namespace { + const char* KeyGeometry = "Geometry"; + const char* KeyRadius = "Radius"; + const char* KeyColorTexture = "Textures.Color"; + const char* KeyNightTexture = "Textures.Night"; + const char* KeyHeightTexture = "Textures.Height"; + const char* KeyShading = "PerformShading"; + + + + static const std::string _loggerCat = "RenderablePlanet"; + + const char* keyFrame = "Frame"; + const char* keyShadowGroup = "Shadow_Group"; + const char* keyShadowSource = "Source"; + const char* keyShadowCaster = "Caster"; + const char* keyBody = "Body"; +} // namespace + +namespace openspace { + +documentation::Documentation RenderablePlanet::Documentation() { + using namespace documentation; + return { + "RenderablePlanet", + "space_renderable_planet", + { + { + KeyGeometry, + new ReferencingVerifier("space_geometry_planet"), + "Specifies the planet geometry that is used for this RenderablePlanet.", + Optional::No + }, + { + KeyRadius, + new DoubleVerifier, + "Specifies the radius of the planet. If this value is not specified, it " + "will try to query the SPICE library for radius values.", + Optional::Yes + }, + { + KeyColorTexture, + new StringVerifier, + "Specifies the color texture that is used for this RenderablePlanet.", + Optional::Yes + }, + { + KeyHeightTexture, + new StringVerifier, + "Specifies the height texture that is used for this RenderablePlanet.", + Optional::Yes + }, + { + KeyNightTexture, + new StringVerifier, + "Specifies the texture that is used for the night side of this " + "RenderablePlanet.", + Optional::Yes + }, + { + KeyShading, + new BoolVerifier, + "Specifies whether the planet should be rendered shaded by the Sun. If " + "this value is 'false', any existing night texture will not be used. " + "This value defaults to 'true'.", + Optional::Yes + } + } + }; +} + +RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _colorTexturePath("colorTexture", "Color Texture") + , _nightTexturePath("nightTexture", "Night Texture") + , _heightMapTexturePath("heightMap", "Heightmap Texture") + , _programObject(nullptr) + , _texture(nullptr) + , _nightTexture(nullptr) + , _heightExaggeration("heightExaggeration", "Height Exaggeration", 1.f, 0.f, 10.f) + , _geometry(nullptr) + , _performShading("performShading", "Perform Shading", true) + , _alpha(1.f) + , _planetRadius(0.f) + , _hasNightTexture(false) + , _hasHeightTexture(false) + , _shadowEnabled(false) +{ + ghoul_precondition( + dictionary.hasKeyAndValue(SceneGraphNode::KeyName), + "RenderablePlanet needs the name to be specified" + ); + + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderablePlanet" + ); + + const std::string name = dictionary.value(SceneGraphNode::KeyName); + + ghoul::Dictionary geomDict = dictionary.value(KeyGeometry); + + if (dictionary.hasKey(KeyRadius)) { + // If the user specified a radius, we want to use this + _planetRadius = dictionary.value(KeyRadius); + } + else if (SpiceManager::ref().hasValue(name, "RADII") ) { + // If the user didn't specfify a radius, but Spice has a radius, we can use this + glm::dvec3 radius; + SpiceManager::ref().getValue(name, "RADII", radius); + radius *= 1000.0; // Spice gives radii in KM. + std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system + geomDict.setValue(KeyRadius, radius); + + _planetRadius = (radius.x + radius.y + radius.z) / 3.0; + } + else { + LERRORC("RenderablePlanet", "Missing radius specification"); + } + + _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geomDict); + + if (dictionary.hasKey(KeyColorTexture)) { + _colorTexturePath = absPath(dictionary.value(KeyColorTexture)); + } + + if (dictionary.hasKey(KeyNightTexture)) { + _hasNightTexture = true; + _nightTexturePath = absPath(dictionary.value(KeyNightTexture)); + } + + if (dictionary.hasKey(KeyHeightTexture)) { + _hasHeightTexture = true; + _heightMapTexturePath = absPath(dictionary.value(KeyHeightTexture)); + } + + if (dictionary.hasKey(KeyShading)) { + _performShading = dictionary.value(KeyShading); + } + + addPropertySubOwner(_geometry.get()); + + auto loadTextureCallback = [this]() {loadTexture(); }; + addProperty(_colorTexturePath); + _colorTexturePath.onChange(loadTextureCallback); + + addProperty(_nightTexturePath); + _nightTexturePath.onChange(loadTextureCallback); + + addProperty(_heightMapTexturePath); + _heightMapTexturePath.onChange(loadTextureCallback); + + addProperty(_heightExaggeration); + addProperty(_performShading); + + // Shadow data: + ghoul::Dictionary shadowDictionary; + bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); + bool disableShadows = false; + if (success) { + std::vector< std::pair > sourceArray; + unsigned int sourceCounter = 1; + while (success) { + std::string sourceName; + std::stringstream ss; + ss << keyShadowSource << sourceCounter << ".Name"; + success = shadowDictionary.getValue(ss.str(), sourceName); + if (success) { + float sourceRadius; + ss.str(std::string()); + ss << keyShadowSource << sourceCounter << ".Radius"; + success = shadowDictionary.getValue(ss.str(), sourceRadius); + if (success) { + sourceArray.push_back(std::pair< std::string, float>( + sourceName, sourceRadius)); + } + else { + LWARNING("No Radius value expecified for Shadow Source Name " + << sourceName << " from " << name + << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + sourceCounter++; + } + + if (!disableShadows && !sourceArray.empty()) { + success = true; + std::vector< std::pair > casterArray; + unsigned int casterCounter = 1; + while (success) { + std::string casterName; + std::stringstream ss; + ss << keyShadowCaster << casterCounter << ".Name"; + success = shadowDictionary.getValue(ss.str(), casterName); + if (success) { + float casterRadius; + ss.str(std::string()); + ss << keyShadowCaster << casterCounter << ".Radius"; + success = shadowDictionary.getValue(ss.str(), casterRadius); + if (success) { + casterArray.push_back(std::pair< std::string, float>( + casterName, casterRadius)); + } + else { + LWARNING("No Radius value expecified for Shadow Caster Name " + << casterName << " from " << name + << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + + casterCounter++; + } + + if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { + for (const auto & source : sourceArray) + for (const auto & caster : casterArray) { + ShadowConf sc; + sc.source = source; + sc.caster = caster; + _shadowConfArray.push_back(sc); + } + _shadowEnabled = true; + } + } + } +} + +bool RenderablePlanet::initialize() { + RenderEngine& renderEngine = OsEng.renderEngine(); + + if (_programObject == nullptr && _shadowEnabled && _hasNightTexture) { + // shadow program + _programObject = renderEngine.buildRenderProgram( + "shadowNightProgram", + "${MODULE_SPACE}/shaders/shadow_nighttexture_vs.glsl", + "${MODULE_SPACE}/shaders/shadow_nighttexture_fs.glsl"); + } + else if (_programObject == nullptr && _shadowEnabled) { + // shadow program + _programObject = renderEngine.buildRenderProgram( + "shadowProgram", + "${MODULE_SPACE}/shaders/shadow_vs.glsl", + "${MODULE_SPACE}/shaders/shadow_fs.glsl"); + } + else if (_programObject == nullptr && _hasNightTexture) { + // Night texture program + _programObject = renderEngine.buildRenderProgram( + "nightTextureProgram", + "${MODULE_SPACE}/shaders/nighttexture_vs.glsl", + "${MODULE_SPACE}/shaders/nighttexture_fs.glsl"); + } + else if (_programObject == nullptr) { + // pscstandard + _programObject = renderEngine.buildRenderProgram( + "pscstandard", + "${MODULE_SPACE}/shaders/renderableplanet_vs.glsl", + "${MODULE_SPACE}/shaders/renderableplanet_fs.glsl"); + } + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + _programObject->setIgnoreUniformLocationError(IgnoreError::Yes); + + _geometry->initialize(this); + + _programObject->deactivate(); + + loadTexture(); + + return isReady(); +} + +bool RenderablePlanet::deinitialize() { + if (_geometry) { + _geometry->deinitialize(); + _geometry = nullptr; + } + + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_programObject) { + renderEngine.removeRenderProgram(_programObject); + _programObject = nullptr; + } + + _geometry = nullptr; + _texture = nullptr; + _nightTexture = nullptr; + + return true; +} + +bool RenderablePlanet::isReady() const { + bool ready = true; + ready &= (_programObject != nullptr); + ready &= (_texture != nullptr); + ready &= (_geometry != nullptr); + return ready; +} + +void RenderablePlanet::render(const RenderData& data) { + // activate shader + _programObject->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation + glm::dmat4(data.modelTransform.rotation) * // Spice rotation + glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); + + // scale the planet to appropriate size since the planet is a unit sphere + //glm::mat4 transform = glm::mat4(1); + + //earth needs to be rotated for that to work. + glm::dmat4 rot = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(1, 0, 0)); + glm::dmat4 roty = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(0, -1, 0)); + //glm::dmat4 rotProp = glm::rotate(glm::dmat4(1.0), glm::radians(static_cast(_rotation)), glm::dvec3(0, 1, 0)); + modelTransform = modelTransform * rot * roty /** rotProp*/; + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _programObject->setUniform("transparency", _alpha); + _programObject->setUniform( + "modelViewProjectionTransform", + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _programObject->setUniform("ModelTransform", glm::mat4(modelTransform)); + + // Normal Transformation + glm::mat4 translateObjTrans = glm::translate(glm::mat4(1.0), data.position.vec3()); + glm::mat4 translateCamTrans = glm::translate(glm::mat4(1.0), -data.camera.position().vec3()); + float scaleFactor = data.camera.scaling().x * powf(10.0, data.camera.scaling().y); + glm::mat4 scaleCamTrans = glm::scale(glm::mat4(1.0), glm::vec3(scaleFactor)); + +// glm::mat4 ModelViewTrans = data.camera.viewMatrix() * scaleCamTrans * +// translateCamTrans * translateObjTrans * glm::mat4(modelTransform); + + setPscUniforms(*_programObject.get(), data.camera, data.position); + + _programObject->setUniform("_performShading", _performShading); + + _programObject->setUniform("_hasHeightMap", _hasHeightTexture); + _programObject->setUniform("_heightExaggeration", _heightExaggeration); + + // Bind texture + ghoul::opengl::TextureUnit dayUnit; + ghoul::opengl::TextureUnit nightUnit; + ghoul::opengl::TextureUnit heightUnit; + + + dayUnit.activate(); + _texture->bind(); + _programObject->setUniform("texture1", dayUnit); + + // Bind possible night texture + if (_hasNightTexture && _nightTexture) { + nightUnit.activate(); + _nightTexture->bind(); + _programObject->setUniform("nightTex", nightUnit); + } + + if (_hasHeightTexture && _heightMapTexture) { + heightUnit.activate(); + _heightMapTexture->bind(); + _programObject->setUniform("heightTex", heightUnit); + } + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // TODO: Move Calculations to VIEW SPACE (precision problems avoidance...) + + double lt; + // Shadow calculations.. + if (!_shadowConfArray.empty()) { + std::vector shadowDataArray; + shadowDataArray.reserve(_shadowConfArray.size()); + + for (const auto & shadowConf : _shadowConfArray) { + // TO REMEMBER: all distances and lengths in world coordinates are in meters!!! We need to move this to view space... + // Getting source and caster: + glm::dvec3 sourcePos = SpiceManager::ref().targetPosition(shadowConf.source.first, "SUN", "GALACTIC", {}, _time, lt); + sourcePos *= 1000.0; // converting to meters + glm::dvec3 casterPos = SpiceManager::ref().targetPosition(shadowConf.caster.first, "SUN", "GALACTIC", {}, _time, lt); + casterPos *= 1000.0; // converting to meters + psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(casterPos.x, casterPos.y, casterPos.z); + + + // First we determine if the caster is shadowing the current planet (all calculations in World Coordinates): + glm::vec3 planetCasterVec = (caster_pos - data.position).vec3(); + glm::vec3 sourceCasterVec = glm::vec3(casterPos - sourcePos); + float sc_length = glm::length(sourceCasterVec); + glm::vec3 planetCaster_proj = (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * sourceCasterVec; + float d_test = glm::length(planetCasterVec - planetCaster_proj); + float xp_test = shadowConf.caster.second * sc_length / (shadowConf.source.second + shadowConf.caster.second); + float rp_test = shadowConf.caster.second * (glm::length(planetCaster_proj) + xp_test) / xp_test; + + double casterDistSun = glm::length(casterPos); + float planetDistSun = glm::length(data.position.vec3()); + + ShadowRenderingStruct shadowData; + shadowData.isShadowing = false; + + if (((d_test - rp_test) < _planetRadius) && + (casterDistSun < planetDistSun) ) { + // The current caster is shadowing the current planet + shadowData.isShadowing = true; + shadowData.rs = shadowConf.source.second; + shadowData.rc = shadowConf.caster.second; + shadowData.sourceCasterVec = sourceCasterVec; + shadowData.xp = xp_test; + shadowData.xu = shadowData.rc * sc_length / (shadowData.rs - shadowData.rc); + shadowData.casterPositionVec = glm::vec3(casterPos); + } + shadowDataArray.push_back(shadowData); + } + + const std::string uniformVarName("shadowDataArray["); + unsigned int counter = 0; + for (const auto & sd : shadowDataArray) { + std::stringstream ss; + ss << uniformVarName << counter << "].isShadowing"; + _programObject->setUniform(ss.str(), sd.isShadowing); + if (sd.isShadowing) { + ss.str(std::string()); + ss << uniformVarName << counter << "].xp"; + _programObject->setUniform(ss.str(), sd.xp); + ss.str(std::string()); + ss << uniformVarName << counter << "].xu"; + _programObject->setUniform(ss.str(), sd.xu); + /*ss.str(std::string()); + ss << uniformVarName << counter << "].rs"; + _programObject->setUniform(ss.str(), sd.rs);*/ + ss.str(std::string()); + ss << uniformVarName << counter << "].rc"; + _programObject->setUniform(ss.str(), sd.rc); + ss.str(std::string()); + ss << uniformVarName << counter << "].sourceCasterVec"; + _programObject->setUniform(ss.str(), sd.sourceCasterVec); + ss.str(std::string()); + ss << uniformVarName << counter << "].casterPositionVec"; + _programObject->setUniform(ss.str(), sd.casterPositionVec); + } + counter++; + } + } + + // render + _geometry->render(); + + // disable shader + _programObject->deactivate(); + +} + +void RenderablePlanet::update(const UpdateData& data) { + // set spice-orientation in accordance to timestamp + _stateMatrix = data.modelTransform.rotation; + //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); + _time = data.time.j2000Seconds(); +} + +void RenderablePlanet::loadTexture() { + _texture = nullptr; + if (_colorTexturePath.value() != "") { + _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)); + if (_texture) { + if (_texture->numberOfChannels() == 1) { + _texture->setSwizzleMask({ GL_RED, GL_RED, GL_RED, GL_RED }); + } + + LDEBUG("Loaded texture from '" << _colorTexturePath << "'"); + _texture->uploadTexture(); + + // Textures of planets looks much smoother with AnisotropicMipMap rather than linear + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + } + } + + if (_hasNightTexture) { + _nightTexture = nullptr; + if (_nightTexturePath.value() != "") { + _nightTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_nightTexturePath)); + if (_nightTexture) { + LDEBUG("Loaded texture from '" << _nightTexturePath << "'"); + _nightTexture->uploadTexture(); + _nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + } + + if (_hasHeightTexture) { + _heightMapTexture = nullptr; + if (_heightMapTexturePath.value() != "") { + _heightMapTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_heightMapTexturePath)); + if (_heightMapTexture) { + LDEBUG("Loaded texture from '" << _heightMapTexturePath << "'"); + _heightMapTexture->uploadTexture(); + _heightMapTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + } +} + +} // namespace openspace diff --git a/modules/volume/rawvolumewriter.h b/modules/volume/rawvolumewriter.h index 2dd3b19012..a5c07a3986 100644 --- a/modules/volume/rawvolumewriter.h +++ b/modules/volume/rawvolumewriter.h @@ -1,57 +1,57 @@ -/***************************************************************************************** - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ -#define __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ - -#include -#include -#include - -namespace openspace { - -template -class RawVolumeWriter { -public: - RawVolumeWriter(std::string path, size_t bufferSize = 1024); - void setPath(const std::string& path); - glm::uvec3 dimensions() const; - void setDimensions(const glm::uvec3& dimensions); - void write(const std::function& fn, - const std::function& onProgress = [](float t) {}); - void write(const RawVolume& volume); - - size_t coordsToIndex(const glm::uvec3& coords) const; - glm::ivec3 indexToCoords(size_t linear) const; -private: - glm::ivec3 _dimensions; - std::string _path; - size_t _bufferSize; -}; - -} // namespace openspace - -#include "rawvolumewriter.inl" - -#endif // __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ +#define __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ + +#include +#include +#include + +namespace openspace { + +template +class RawVolumeWriter { +public: + RawVolumeWriter(std::string path, size_t bufferSize = 1024); + void setPath(const std::string& path); + glm::uvec3 dimensions() const; + void setDimensions(const glm::uvec3& dimensions); + void write(const std::function& fn, + const std::function& onProgress = [](float t) {}); + void write(const RawVolume& volume); + + size_t coordsToIndex(const glm::uvec3& coords) const; + glm::ivec3 indexToCoords(size_t linear) const; +private: + glm::ivec3 _dimensions; + std::string _path; + size_t _bufferSize; +}; + +} // namespace openspace + +#include "rawvolumewriter.inl" + +#endif // __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ diff --git a/openspace.cfg b/openspace.cfg index 526eaec369..aea8c89557 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -1,95 +1,95 @@ --- The configuration has an implict --- require('scripts/configuration_helper.lua') --- which defines helper functions useful to customize the configuration - -return { - -- Determines which SGCT configuration file is loaded, that is, if there rendering - -- occurs in a single window, a fisheye projection, or a dome cluster system - - -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, - - -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080}, - - -- A 1k fisheye rendering - -- SGCTConfig = sgct.config.fisheye{1024, 1024}, - - -- A 4k fisheye rendering in a 1024x1024 window - -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, - - -- Streaming OpenSpace via Spout to OBS - -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, - - - --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", - --SGCTConfig = "${CONFIG}/openvr_htcVive.xml", - - -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description - -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", - -- Scene = "${SCENE}/globebrowsing.scene", - -- Scene = "${SCENE}/rosetta.scene", - -- Scene = "${SCENE}/dawn.scene", - -- Scene = "${SCENE}/newhorizons.scene", - -- Scene = "${SCENE}/osirisrex.scene", - - Task = "${TASKS}/default.task", - - Paths = { - SCRIPTS = "${BASE_PATH}/scripts", - SHADERS = "${BASE_PATH}/shaders", - OPENSPACE_DATA = "${BASE_PATH}/data", - SCENE = "${OPENSPACE_DATA}/scene", - TASKS = "${OPENSPACE_DATA}/tasks", - SPICE = "${OPENSPACE_DATA}/spice", - MODULES = "${BASE_PATH}/modules", - TESTDIR = "${BASE_PATH}/tests", - CONFIG = "${BASE_PATH}/config", - CACHE = "${BASE_PATH}/cache", - FONTS = "${OPENSPACE_DATA}/fonts", - DOCUMENTATION = "${BASE_PATH}/documentation" - }, - Fonts = { - Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", - Light = "${FONTS}/Roboto/Roboto-Regular.ttf", - Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf" - }, - Logging = { - -- LogLevel = "Trace", - LogLevel = "Debug", - ImmediateFlush = true, - Logs = { - { Type = "html", File = "${BASE_PATH}/log.html", Append = false } - }, - CapabilitiesVerbosity = "Full" - }, - Launcher = { - LogLevel = "None" - }, - LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", - PropertyDocumentation = "${DOCUMENTATION}/Properties.html", - ScriptLog = "${BASE_PATH}/ScriptLog.txt", - KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", - Documentation = "${DOCUMENTATION}/Documentation.html", - FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", - - ShutdownCountdown = 3, - -- OnScreenTextScaling = "framebuffer", - -- PerSceneCache = true, - -- DisableRenderingOnMaster = true, - -- DisableSceneOnMaster = true, - DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", - RenderingMethod = "Framebuffer", - OpenGLDebugContext = { - Activate = true, - FilterIdentifier = { - { Type = "Other", Source = "API", Identifier = 131185 }, - { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" - { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated - }, --- FilterSeverity = { } - - } - --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" -} +-- The configuration has an implict +-- require('scripts/configuration_helper.lua') +-- which defines helper functions useful to customize the configuration + +return { + -- Determines which SGCT configuration file is loaded, that is, if there rendering + -- occurs in a single window, a fisheye projection, or a dome cluster system + + -- A regular 1280x720 window + SGCTConfig = sgct.config.single{}, + + -- A regular 1920x1080 window + -- SGCTConfig = sgct.config.single{1920, 1080}, + + -- A 1k fisheye rendering + -- SGCTConfig = sgct.config.fisheye{1024, 1024}, + + -- A 4k fisheye rendering in a 1024x1024 window + -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, + + -- Streaming OpenSpace via Spout to OBS + -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, + + + --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", + --SGCTConfig = "${CONFIG}/openvr_htcVive.xml", + + -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description + -- of all entities that will be visible during an instance of OpenSpace + Scene = "${SCENE}/default.scene", + -- Scene = "${SCENE}/globebrowsing.scene", + -- Scene = "${SCENE}/rosetta.scene", + -- Scene = "${SCENE}/dawn.scene", + -- Scene = "${SCENE}/newhorizons.scene", + -- Scene = "${SCENE}/osirisrex.scene", + + Task = "${TASKS}/default.task", + + Paths = { + SCRIPTS = "${BASE_PATH}/scripts", + SHADERS = "${BASE_PATH}/shaders", + OPENSPACE_DATA = "${BASE_PATH}/data", + SCENE = "${OPENSPACE_DATA}/scene", + TASKS = "${OPENSPACE_DATA}/tasks", + SPICE = "${OPENSPACE_DATA}/spice", + MODULES = "${BASE_PATH}/modules", + TESTDIR = "${BASE_PATH}/tests", + CONFIG = "${BASE_PATH}/config", + CACHE = "${BASE_PATH}/cache", + FONTS = "${OPENSPACE_DATA}/fonts", + DOCUMENTATION = "${BASE_PATH}/documentation" + }, + Fonts = { + Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", + Light = "${FONTS}/Roboto/Roboto-Regular.ttf", + Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf" + }, + Logging = { + -- LogLevel = "Trace", + LogLevel = "Debug", + ImmediateFlush = true, + Logs = { + { Type = "html", File = "${BASE_PATH}/log.html", Append = false } + }, + CapabilitiesVerbosity = "Full" + }, + Launcher = { + LogLevel = "None" + }, + LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", + PropertyDocumentation = "${DOCUMENTATION}/Properties.html", + ScriptLog = "${BASE_PATH}/ScriptLog.txt", + KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", + Documentation = "${DOCUMENTATION}/Documentation.html", + FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", + + ShutdownCountdown = 3, + -- OnScreenTextScaling = "framebuffer", + -- PerSceneCache = true, + -- DisableRenderingOnMaster = true, + -- DisableSceneOnMaster = true, + DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", + RenderingMethod = "Framebuffer", + OpenGLDebugContext = { + Activate = true, + FilterIdentifier = { + { Type = "Other", Source = "API", Identifier = 131185 }, + { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" + { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated + }, +-- FilterSeverity = { } + + } + --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" +} diff --git a/src/engine/wrapper/sgctwindowwrapper.cpp b/src/engine/wrapper/sgctwindowwrapper.cpp index ef8f297808..c772b7863f 100644 --- a/src/engine/wrapper/sgctwindowwrapper.cpp +++ b/src/engine/wrapper/sgctwindowwrapper.cpp @@ -1,248 +1,248 @@ -/***************************************************************************************** - * * - * 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 - -#include "sgct.h" - -#undef near -#undef far - -namespace { - const char* GuiWindowTag = "GUI"; -} // namespace - -namespace openspace { - -SGCTWindowWrapper::SGCTWindowWrapper() - : _eyeSeparation("eyeSeparation", "Eye Separation", 0.f, 0.f, 10.f) - , _showStatsGraph("showStatsGraph", "Show Stats Graph", false) -{ - _showStatsGraph.onChange([this](){ - sgct::Engine::instance()->setStatsGraphVisibility(_showStatsGraph); - }); - addProperty(_showStatsGraph); - - addProperty(_eyeSeparation); - _eyeSeparation.onChange([this](){ - setEyeSeparationDistance(_eyeSeparation); - }); -} - -void SGCTWindowWrapper::terminate() { - sgct::Engine::instance()->terminate(); -} - -void SGCTWindowWrapper::setBarrier(bool enabled) { - sgct::SGCTWindow::setBarrier(enabled); -} - -void SGCTWindowWrapper::setSynchronization(bool enabled) { - sgct_core::ClusterManager::instance()->setUseIgnoreSync(enabled); -} - -void SGCTWindowWrapper::clearAllWindows(const glm::vec4& clearColor) { - size_t n = sgct::Engine::instance()->getNumberOfWindows(); - for (size_t i = 0; i < n; ++i) { - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLFWwindow* win = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); - glfwSwapBuffers(win); - } -} - -bool SGCTWindowWrapper::windowHasResized() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isWindowResized(); -} - -double SGCTWindowWrapper::averageDeltaTime() const { - return sgct::Engine::instance()->getAvgDt(); -} - -double SGCTWindowWrapper::deltaTime() const { - return sgct::Engine::instance()->getDt(); -} - -glm::vec2 SGCTWindowWrapper::mousePosition() const { - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - double posX, posY; - sgct::Engine::instance()->getMousePos(id, &posX, &posY); - return glm::vec2(posX, posY); -} - -uint32_t SGCTWindowWrapper::mouseButtons(int maxNumber) const { - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - uint32_t result = 0; - for (int i = 0; i < maxNumber; ++i) { - bool button = (sgct::Engine::instance()->getMouseButton(id, i) != 0); - if (button) - result |= (1 << i); - - } - return result; -} - -glm::ivec2 SGCTWindowWrapper::currentWindowSize() const { - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - switch (window->getStereoMode()) { - case sgct::SGCTWindow::Side_By_Side_Stereo: - case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo: - return glm::ivec2( - window->getXResolution() / 2, - window->getYResolution()); - case sgct::SGCTWindow::Top_Bottom_Stereo: - case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo: - return glm::ivec2( - window->getXResolution(), - window->getYResolution() / 2); - default: - return glm::ivec2( - window->getXResolution(), - window->getYResolution()); - } -} - -glm::ivec2 SGCTWindowWrapper::currentWindowResolution() const { - int x, y; - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - window->getFinalFBODimensions(x, y); - return glm::ivec2(x, y); -} - -glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const { - sgct_core::Viewport* viewport = sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); - if (viewport != nullptr){ - if (viewport->hasSubViewports() && viewport->getNonLinearProjectionPtr()) { - int res = viewport->getNonLinearProjectionPtr()->getCubemapResolution(); - return glm::ivec2(res, res); - } else { - return currentWindowResolution(); - } - } - throw WindowWrapperException("No viewport available"); -} - -glm::vec2 SGCTWindowWrapper::dpiScaling() const { - return glm::vec2( - sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(), - sgct::Engine::instance()->getCurrentWindowPtr()->getYScale() - ); -} - -int SGCTWindowWrapper::currentNumberOfAaSamples() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples(); -} - -bool SGCTWindowWrapper::isRegularRendering() const { - sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr(); - std::size_t nViewports = w->getNumberOfViewports(); - (void)nViewports; // Unused in Release mode - ghoul_assert(nViewports > 0, "At least one viewport must exist at this time"); - sgct_core::Viewport* vp = w->getViewport(0); - sgct_core::NonLinearProjection* nlp = vp->getNonLinearProjectionPtr(); - return nlp == nullptr; -} - -bool SGCTWindowWrapper::hasGuiWindow() const { - auto engine = sgct::Engine::instance(); - for (size_t i = 0; i < engine->getNumberOfWindows(); ++i) { - if (engine->getWindowPtr(i)->checkIfTagExists(GuiWindowTag)) { - return true; - } - } - return false; -} - -bool SGCTWindowWrapper::isGuiWindow() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->checkIfTagExists( - GuiWindowTag - ); -} - -bool SGCTWindowWrapper::isMaster() const { - return sgct::Engine::instance()->isMaster(); -} - -bool SGCTWindowWrapper::isSwapGroupMaster() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isSwapGroupMaster(); -} - -bool SGCTWindowWrapper::isUsingSwapGroups() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isUsingSwapGroups(); -} - -glm::mat4 SGCTWindowWrapper::viewProjectionMatrix() const { - return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix(); -} - -glm::mat4 SGCTWindowWrapper::modelMatrix() const { - return sgct::Engine::instance()->getModelMatrix(); -} - -void SGCTWindowWrapper::setNearFarClippingPlane(float nearPlane, float farPlane) { - sgct::Engine::instance()->setNearAndFarClippingPlanes(nearPlane, farPlane); -} - -void SGCTWindowWrapper::setEyeSeparationDistance(float distance) { - sgct::Engine::instance()->setEyeSeparation(distance); -} - -glm::ivec4 SGCTWindowWrapper::viewportPixelCoordinates() const { - int x1, xSize, y1, ySize; - sgct::Engine::instance()->getCurrentWindowPtr()->getCurrentViewportPixelCoords(x1, - y1, - xSize, - ySize); - return glm::ivec4(x1, xSize, y1, ySize); -} - -bool SGCTWindowWrapper::isExternalControlConnected() const { - return sgct::Engine::instance()->isExternalControlConnected(); -} - -void SGCTWindowWrapper::sendMessageToExternalControl(const std::vector& message) const { - sgct::Engine::instance()->sendMessageToExternalControl( - message.data(), - static_cast(message.size()) - ); -} - -bool SGCTWindowWrapper::isSimpleRendering() const { - return (sgct::Engine::instance()->getCurrentRenderTarget() != sgct::Engine::NonLinearBuffer); - -} - -void SGCTWindowWrapper::takeScreenshot(bool applyWarping) const { - sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping); - sgct::Engine::instance()->takeScreenshot(); -} - -//void forEachWindow(std::function function) { -// size_t n = sgct::Engine::instance()->getNumberOfWindows(); -// for (size_t i = 0; i < n; ++i) -// function(); -//} - -} // namespace openspace - +/***************************************************************************************** + * * + * 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 + +#include "sgct.h" + +#undef near +#undef far + +namespace { + const char* GuiWindowTag = "GUI"; +} // namespace + +namespace openspace { + +SGCTWindowWrapper::SGCTWindowWrapper() + : _eyeSeparation("eyeSeparation", "Eye Separation", 0.f, 0.f, 10.f) + , _showStatsGraph("showStatsGraph", "Show Stats Graph", false) +{ + _showStatsGraph.onChange([this](){ + sgct::Engine::instance()->setStatsGraphVisibility(_showStatsGraph); + }); + addProperty(_showStatsGraph); + + addProperty(_eyeSeparation); + _eyeSeparation.onChange([this](){ + setEyeSeparationDistance(_eyeSeparation); + }); +} + +void SGCTWindowWrapper::terminate() { + sgct::Engine::instance()->terminate(); +} + +void SGCTWindowWrapper::setBarrier(bool enabled) { + sgct::SGCTWindow::setBarrier(enabled); +} + +void SGCTWindowWrapper::setSynchronization(bool enabled) { + sgct_core::ClusterManager::instance()->setUseIgnoreSync(enabled); +} + +void SGCTWindowWrapper::clearAllWindows(const glm::vec4& clearColor) { + size_t n = sgct::Engine::instance()->getNumberOfWindows(); + for (size_t i = 0; i < n; ++i) { + glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GLFWwindow* win = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); + glfwSwapBuffers(win); + } +} + +bool SGCTWindowWrapper::windowHasResized() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isWindowResized(); +} + +double SGCTWindowWrapper::averageDeltaTime() const { + return sgct::Engine::instance()->getAvgDt(); +} + +double SGCTWindowWrapper::deltaTime() const { + return sgct::Engine::instance()->getDt(); +} + +glm::vec2 SGCTWindowWrapper::mousePosition() const { + int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); + double posX, posY; + sgct::Engine::instance()->getMousePos(id, &posX, &posY); + return glm::vec2(posX, posY); +} + +uint32_t SGCTWindowWrapper::mouseButtons(int maxNumber) const { + int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); + uint32_t result = 0; + for (int i = 0; i < maxNumber; ++i) { + bool button = (sgct::Engine::instance()->getMouseButton(id, i) != 0); + if (button) + result |= (1 << i); + + } + return result; +} + +glm::ivec2 SGCTWindowWrapper::currentWindowSize() const { + auto window = sgct::Engine::instance()->getCurrentWindowPtr(); + switch (window->getStereoMode()) { + case sgct::SGCTWindow::Side_By_Side_Stereo: + case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo: + return glm::ivec2( + window->getXResolution() / 2, + window->getYResolution()); + case sgct::SGCTWindow::Top_Bottom_Stereo: + case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo: + return glm::ivec2( + window->getXResolution(), + window->getYResolution() / 2); + default: + return glm::ivec2( + window->getXResolution(), + window->getYResolution()); + } +} + +glm::ivec2 SGCTWindowWrapper::currentWindowResolution() const { + int x, y; + auto window = sgct::Engine::instance()->getCurrentWindowPtr(); + window->getFinalFBODimensions(x, y); + return glm::ivec2(x, y); +} + +glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const { + sgct_core::Viewport* viewport = sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); + if (viewport != nullptr){ + if (viewport->hasSubViewports() && viewport->getNonLinearProjectionPtr()) { + int res = viewport->getNonLinearProjectionPtr()->getCubemapResolution(); + return glm::ivec2(res, res); + } else { + return currentWindowResolution(); + } + } + throw WindowWrapperException("No viewport available"); +} + +glm::vec2 SGCTWindowWrapper::dpiScaling() const { + return glm::vec2( + sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(), + sgct::Engine::instance()->getCurrentWindowPtr()->getYScale() + ); +} + +int SGCTWindowWrapper::currentNumberOfAaSamples() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples(); +} + +bool SGCTWindowWrapper::isRegularRendering() const { + sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr(); + std::size_t nViewports = w->getNumberOfViewports(); + (void)nViewports; // Unused in Release mode + ghoul_assert(nViewports > 0, "At least one viewport must exist at this time"); + sgct_core::Viewport* vp = w->getViewport(0); + sgct_core::NonLinearProjection* nlp = vp->getNonLinearProjectionPtr(); + return nlp == nullptr; +} + +bool SGCTWindowWrapper::hasGuiWindow() const { + auto engine = sgct::Engine::instance(); + for (size_t i = 0; i < engine->getNumberOfWindows(); ++i) { + if (engine->getWindowPtr(i)->checkIfTagExists(GuiWindowTag)) { + return true; + } + } + return false; +} + +bool SGCTWindowWrapper::isGuiWindow() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->checkIfTagExists( + GuiWindowTag + ); +} + +bool SGCTWindowWrapper::isMaster() const { + return sgct::Engine::instance()->isMaster(); +} + +bool SGCTWindowWrapper::isSwapGroupMaster() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isSwapGroupMaster(); +} + +bool SGCTWindowWrapper::isUsingSwapGroups() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isUsingSwapGroups(); +} + +glm::mat4 SGCTWindowWrapper::viewProjectionMatrix() const { + return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix(); +} + +glm::mat4 SGCTWindowWrapper::modelMatrix() const { + return sgct::Engine::instance()->getModelMatrix(); +} + +void SGCTWindowWrapper::setNearFarClippingPlane(float nearPlane, float farPlane) { + sgct::Engine::instance()->setNearAndFarClippingPlanes(nearPlane, farPlane); +} + +void SGCTWindowWrapper::setEyeSeparationDistance(float distance) { + sgct::Engine::instance()->setEyeSeparation(distance); +} + +glm::ivec4 SGCTWindowWrapper::viewportPixelCoordinates() const { + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getCurrentWindowPtr()->getCurrentViewportPixelCoords(x1, + y1, + xSize, + ySize); + return glm::ivec4(x1, xSize, y1, ySize); +} + +bool SGCTWindowWrapper::isExternalControlConnected() const { + return sgct::Engine::instance()->isExternalControlConnected(); +} + +void SGCTWindowWrapper::sendMessageToExternalControl(const std::vector& message) const { + sgct::Engine::instance()->sendMessageToExternalControl( + message.data(), + static_cast(message.size()) + ); +} + +bool SGCTWindowWrapper::isSimpleRendering() const { + return (sgct::Engine::instance()->getCurrentRenderTarget() != sgct::Engine::NonLinearBuffer); + +} + +void SGCTWindowWrapper::takeScreenshot(bool applyWarping) const { + sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping); + sgct::Engine::instance()->takeScreenshot(); +} + +//void forEachWindow(std::function function) { +// size_t n = sgct::Engine::instance()->getNumberOfWindows(); +// for (size_t i = 0; i < n; ++i) +// function(); +//} + +} // namespace openspace + diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 6acfcb5c32..4802b6f892 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -1,528 +1,528 @@ -/***************************************************************************************** - * * - * 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace { - const char* _loggerCat = "FramebufferRenderer"; - const char* ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; - const char* RaycastFragmentShaderPath = "${SHADERS}/framebuffer/raycastframebuffer.frag"; - const char* GetEntryInsidePath = "${SHADERS}/framebuffer/inside.glsl"; - const char* GetEntryOutsidePath = "${SHADERS}/framebuffer/outside.glsl"; - const char* RenderFragmentShaderPath = "${SHADERS}/framebuffer/renderframebuffer.frag"; -} // namespace - -namespace openspace { - -FramebufferRenderer::FramebufferRenderer() - : _camera(nullptr) - , _scene(nullptr) - , _resolution(glm::vec2(0)) -{} - -FramebufferRenderer::~FramebufferRenderer() {} - -void FramebufferRenderer::initialize() { - LINFO("Initializing FramebufferRenderer"); - - const GLfloat size = 1.0f; - const GLfloat vertex_data[] = { - // x y s t - -size, -size, 0.0f, 1.0f, - size, size, 0.0f, 1.0f, - -size, size, 0.0f, 1.0f, - -size, -size, 0.0f, 1.0f, - size, -size, 0.0f, 1.0f, - size, size, 0.0f, 1.0f - }; - - glGenVertexArrays(1, &_screenQuad); - glBindVertexArray(_screenQuad); - - glGenBuffers(1, &_vertexPositionBuffer); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glVertexAttribPointer( - 0, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(GLfloat) * 4, - reinterpret_cast(0) - ); - glEnableVertexAttribArray(0); - - GLint defaultFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); - - // Main framebuffer - glGenTextures(1, &_mainColorTexture); - glGenTextures(1, &_mainDepthTexture); - glGenFramebuffers(1, &_mainFramebuffer); - - // Exit framebuffer - glGenTextures(1, &_exitColorTexture); - glGenTextures(1, &_exitDepthTexture); - glGenFramebuffers(1, &_exitFramebuffer); - - updateResolution(); - updateRendererData(); - updateRaycastData(); - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D_MULTISAMPLE, - _mainColorTexture, - 0 - ); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D_MULTISAMPLE, - _mainDepthTexture, - 0 - ); - - glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - _exitColorTexture, - 0 - ); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - _exitDepthTexture, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main framebuffer is not complete"); - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - - try { - _resolveProgram = ghoul::opengl::ProgramObject::Build( - "Framebuffer Resolve", - "${SHADERS}/framebuffer/resolveframebuffer.vert", - "${SHADERS}/framebuffer/resolveframebuffer.frag" - ); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - - OsEng.renderEngine().raycasterManager().addListener(*this); -} - -void FramebufferRenderer::deinitialize() { - LINFO("Deinitializing FramebufferRenderer"); - - glDeleteFramebuffers(1, &_mainFramebuffer); - glDeleteFramebuffers(1, &_exitFramebuffer); - - glDeleteTextures(1, &_mainColorTexture); - glDeleteTextures(1, &_mainDepthTexture); - glDeleteTextures(1, &_exitColorTexture); - glDeleteTextures(1, &_exitDepthTexture); - - glDeleteBuffers(1, &_vertexPositionBuffer); - glDeleteVertexArrays(1, &_screenQuad); - - OsEng.renderEngine().raycasterManager().removeListener(*this); -} - -void FramebufferRenderer::raycastersChanged(VolumeRaycaster&, bool) { - _dirtyRaycastData = true; -} - -void FramebufferRenderer::update() { - if (_dirtyResolution) { - updateResolution(); - } - - if (_dirtyRaycastData) { - updateRaycastData(); - } - - // If the resolve dictionary changed (or a file changed on disk) - // then rebuild the resolve program. - if (_resolveProgram->isDirty()) { - try { - _resolveProgram->rebuildFromFile(); - } catch (const ghoul::RuntimeError& error) { - LERRORC(error.component, error.message); - } - } - - for (auto& program : _exitPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } - - for (auto& program : _raycastPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } - - for (auto& program : _insideRaycastPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } -} - -void FramebufferRenderer::updateResolution() { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); - - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE, - _nAaSamples, - GL_RGBA, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - true - ); - - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE, - _nAaSamples, - GL_DEPTH_COMPONENT32F, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - true - ); - - glBindTexture(GL_TEXTURE_2D, _exitColorTexture); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA16, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - 0, - GL_RGBA, - GL_UNSIGNED_SHORT, - nullptr - ); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_DEPTH_COMPONENT32F, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - 0, - GL_DEPTH_COMPONENT, - GL_FLOAT, - nullptr - ); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - _dirtyResolution = false; -} - -void FramebufferRenderer::updateRaycastData() { - _raycastData.clear(); - _exitPrograms.clear(); - _raycastPrograms.clear(); - _insideRaycastPrograms.clear(); - - const std::vector& raycasters = - OsEng.renderEngine().raycasterManager().raycasters(); - int nextId = 0; - for (auto& raycaster : raycasters) { - RaycastData data; - data.id = nextId++; - data.namespaceName = "HELPER"; - - std::string vsPath = raycaster->getBoundsVsPath(); - std::string fsPath = raycaster->getBoundsFsPath(); - - ghoul::Dictionary dict; - dict.setValue("rendererData", _rendererData); - dict.setValue("fragmentPath", fsPath); - dict.setValue("id", data.id); - std::string helperPath = raycaster->getHelperPath(); - ghoul::Dictionary helpersDict; - if (!helperPath.empty()) { - helpersDict.setValue("0", helperPath); - } - dict.setValue("helperPaths", helpersDict); - dict.setValue("raycastPath", raycaster->getRaycastPath()); - - _raycastData[raycaster] = data; - - try { - _exitPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " exit", - vsPath, - ExitFragmentShaderPath, - dict - ); - } catch (ghoul::RuntimeError e) { - LERROR(e.message); - } - try { - ghoul::Dictionary outsideDict = dict; - outsideDict.setValue("getEntryPath", GetEntryOutsidePath); - _raycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " raycast", - vsPath, - RaycastFragmentShaderPath, - outsideDict - ); - } catch (ghoul::RuntimeError e) { - LERROR(e.message); - } - try { - ghoul::Dictionary insideDict = dict; - insideDict.setValue("getEntryPath", GetEntryInsidePath); - _insideRaycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " inside raycast", - "${SHADERS}/framebuffer/resolveframebuffer.vert", - RaycastFragmentShaderPath, - insideDict - ); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - _dirtyRaycastData = false; -} - -void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { - std::unique_ptr perf; - if (doPerformanceMeasurements) { - perf = std::make_unique( - "FramebufferRenderer::render", - OsEng.renderEngine().performanceManager() - ); - } - - if (!_scene || !_camera) { - return; - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Time time = OsEng.timeManager().time(); - - RenderData data = { *_camera, psc(), time, doPerformanceMeasurements, 0 }; - RendererTasks tasks; - - // Capture standard fbo - GLint defaultFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - data.renderBinMask = static_cast(Renderable::RenderBin::Background); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Transparent); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); - _scene->render(data, tasks); - - for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { - VolumeRaycaster* raycaster = raycasterTask.raycaster; - - glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - ghoul::opengl::ProgramObject* exitProgram = _exitPrograms[raycaster].get(); - if (exitProgram) { - exitProgram->activate(); - raycaster->renderExitPoints(raycasterTask.renderData, *exitProgram); - exitProgram->deactivate(); - } - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glm::vec3 cameraPosition; - bool cameraIsInside = raycaster->cameraIsInside( - raycasterTask.renderData, - cameraPosition - ); - ghoul::opengl::ProgramObject* raycastProgram = nullptr; - - if (cameraIsInside) { - raycastProgram = _insideRaycastPrograms[raycaster].get(); - if (raycastProgram) { - raycastProgram->activate(); - raycastProgram->setUniform("cameraPosInRaycaster", cameraPosition); - } - } else { - raycastProgram = _raycastPrograms[raycaster].get(); - if (raycastProgram) { - raycastProgram->activate(); - } - } - - if (raycastProgram) { - raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); - - ghoul::opengl::TextureUnit exitColorTextureUnit; - exitColorTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D, _exitColorTexture); - raycastProgram->setUniform("exitColorTexture", exitColorTextureUnit); - - ghoul::opengl::TextureUnit exitDepthTextureUnit; - exitDepthTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); - raycastProgram->setUniform("exitDepthTexture", exitDepthTextureUnit); - - ghoul::opengl::TextureUnit mainDepthTextureUnit; - mainDepthTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); - raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit); - - raycastProgram->setUniform("nAaSamples", _nAaSamples); - raycastProgram->setUniform("windowSize", glm::vec2(_resolution)); - - - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - if (cameraIsInside) { - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - } else { - raycaster->renderEntryPoints(raycasterTask.renderData, *raycastProgram); - } - glDepthMask(true); - glEnable(GL_DEPTH_TEST); - - raycaster->postRaycast(_raycastData[raycaster], *raycastProgram); - raycastProgram->deactivate(); - } else { - LWARNING("Raycaster is not attached when trying to perform raycaster task"); - } - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - _resolveProgram->activate(); - - ghoul::opengl::TextureUnit mainColorTextureUnit; - mainColorTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); - - _resolveProgram->setUniform("mainColorTexture", mainColorTextureUnit); - _resolveProgram->setUniform("blackoutFactor", blackoutFactor); - _resolveProgram->setUniform("nAaSamples", _nAaSamples); - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - _resolveProgram->deactivate(); -} - -void FramebufferRenderer::setScene(Scene* scene) { - _scene = scene; -} - -void FramebufferRenderer::setCamera(Camera* camera) { - _camera = camera; -} - -void FramebufferRenderer::setResolution(glm::ivec2 res) { - _resolution = res; - _dirtyResolution = true; -} - -void FramebufferRenderer::setNAaSamples(int nAaSamples) { - _nAaSamples = nAaSamples; - if (_nAaSamples == 0) { - _nAaSamples = 1; - } - if (_nAaSamples > 8) { - LERROR("Framebuffer renderer does not support more than 8 MSAA samples."); - _nAaSamples = 8; - } - _dirtyResolution = true; -} - -void FramebufferRenderer::updateRendererData() { - ghoul::Dictionary dict; - dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); - - _rendererData = dict; - - OsEng.renderEngine().setRendererData(dict); -} - -} // namespace openspace +/***************************************************************************************** + * * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + const char* _loggerCat = "FramebufferRenderer"; + const char* ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; + const char* RaycastFragmentShaderPath = "${SHADERS}/framebuffer/raycastframebuffer.frag"; + const char* GetEntryInsidePath = "${SHADERS}/framebuffer/inside.glsl"; + const char* GetEntryOutsidePath = "${SHADERS}/framebuffer/outside.glsl"; + const char* RenderFragmentShaderPath = "${SHADERS}/framebuffer/renderframebuffer.frag"; +} // namespace + +namespace openspace { + +FramebufferRenderer::FramebufferRenderer() + : _camera(nullptr) + , _scene(nullptr) + , _resolution(glm::vec2(0)) +{} + +FramebufferRenderer::~FramebufferRenderer() {} + +void FramebufferRenderer::initialize() { + LINFO("Initializing FramebufferRenderer"); + + const GLfloat size = 1.0f; + const GLfloat vertex_data[] = { + // x y s t + -size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f, + -size, size, 0.0f, 1.0f, + -size, -size, 0.0f, 1.0f, + size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f + }; + + glGenVertexArrays(1, &_screenQuad); + glBindVertexArray(_screenQuad); + + glGenBuffers(1, &_vertexPositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glVertexAttribPointer( + 0, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(GLfloat) * 4, + reinterpret_cast(0) + ); + glEnableVertexAttribArray(0); + + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + // Main framebuffer + glGenTextures(1, &_mainColorTexture); + glGenTextures(1, &_mainDepthTexture); + glGenFramebuffers(1, &_mainFramebuffer); + + // Exit framebuffer + glGenTextures(1, &_exitColorTexture); + glGenTextures(1, &_exitDepthTexture); + glGenFramebuffers(1, &_exitFramebuffer); + + updateResolution(); + updateRendererData(); + updateRaycastData(); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D_MULTISAMPLE, + _mainColorTexture, + 0 + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D_MULTISAMPLE, + _mainDepthTexture, + 0 + ); + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + _exitColorTexture, + 0 + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + _exitDepthTexture, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main framebuffer is not complete"); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + + try { + _resolveProgram = ghoul::opengl::ProgramObject::Build( + "Framebuffer Resolve", + "${SHADERS}/framebuffer/resolveframebuffer.vert", + "${SHADERS}/framebuffer/resolveframebuffer.frag" + ); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + + OsEng.renderEngine().raycasterManager().addListener(*this); +} + +void FramebufferRenderer::deinitialize() { + LINFO("Deinitializing FramebufferRenderer"); + + glDeleteFramebuffers(1, &_mainFramebuffer); + glDeleteFramebuffers(1, &_exitFramebuffer); + + glDeleteTextures(1, &_mainColorTexture); + glDeleteTextures(1, &_mainDepthTexture); + glDeleteTextures(1, &_exitColorTexture); + glDeleteTextures(1, &_exitDepthTexture); + + glDeleteBuffers(1, &_vertexPositionBuffer); + glDeleteVertexArrays(1, &_screenQuad); + + OsEng.renderEngine().raycasterManager().removeListener(*this); +} + +void FramebufferRenderer::raycastersChanged(VolumeRaycaster&, bool) { + _dirtyRaycastData = true; +} + +void FramebufferRenderer::update() { + if (_dirtyResolution) { + updateResolution(); + } + + if (_dirtyRaycastData) { + updateRaycastData(); + } + + // If the resolve dictionary changed (or a file changed on disk) + // then rebuild the resolve program. + if (_resolveProgram->isDirty()) { + try { + _resolveProgram->rebuildFromFile(); + } catch (const ghoul::RuntimeError& error) { + LERRORC(error.component, error.message); + } + } + + for (auto& program : _exitPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } + + for (auto& program : _raycastPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } + + for (auto& program : _insideRaycastPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } +} + +void FramebufferRenderer::updateResolution() { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + _nAaSamples, + GL_RGBA, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true + ); + + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + _nAaSamples, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true + ); + + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA16, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_RGBA, + GL_UNSIGNED_SHORT, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + _dirtyResolution = false; +} + +void FramebufferRenderer::updateRaycastData() { + _raycastData.clear(); + _exitPrograms.clear(); + _raycastPrograms.clear(); + _insideRaycastPrograms.clear(); + + const std::vector& raycasters = + OsEng.renderEngine().raycasterManager().raycasters(); + int nextId = 0; + for (auto& raycaster : raycasters) { + RaycastData data; + data.id = nextId++; + data.namespaceName = "HELPER"; + + std::string vsPath = raycaster->getBoundsVsPath(); + std::string fsPath = raycaster->getBoundsFsPath(); + + ghoul::Dictionary dict; + dict.setValue("rendererData", _rendererData); + dict.setValue("fragmentPath", fsPath); + dict.setValue("id", data.id); + std::string helperPath = raycaster->getHelperPath(); + ghoul::Dictionary helpersDict; + if (!helperPath.empty()) { + helpersDict.setValue("0", helperPath); + } + dict.setValue("helperPaths", helpersDict); + dict.setValue("raycastPath", raycaster->getRaycastPath()); + + _raycastData[raycaster] = data; + + try { + _exitPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " exit", + vsPath, + ExitFragmentShaderPath, + dict + ); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + try { + ghoul::Dictionary outsideDict = dict; + outsideDict.setValue("getEntryPath", GetEntryOutsidePath); + _raycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " raycast", + vsPath, + RaycastFragmentShaderPath, + outsideDict + ); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + try { + ghoul::Dictionary insideDict = dict; + insideDict.setValue("getEntryPath", GetEntryInsidePath); + _insideRaycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " inside raycast", + "${SHADERS}/framebuffer/resolveframebuffer.vert", + RaycastFragmentShaderPath, + insideDict + ); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + _dirtyRaycastData = false; +} + +void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { + std::unique_ptr perf; + if (doPerformanceMeasurements) { + perf = std::make_unique( + "FramebufferRenderer::render", + OsEng.renderEngine().performanceManager() + ); + } + + if (!_scene || !_camera) { + return; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Time time = OsEng.timeManager().time(); + + RenderData data = { *_camera, psc(), time, doPerformanceMeasurements, 0 }; + RendererTasks tasks; + + // Capture standard fbo + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + data.renderBinMask = static_cast(Renderable::RenderBin::Background); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Transparent); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); + _scene->render(data, tasks); + + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ghoul::opengl::ProgramObject* exitProgram = _exitPrograms[raycaster].get(); + if (exitProgram) { + exitProgram->activate(); + raycaster->renderExitPoints(raycasterTask.renderData, *exitProgram); + exitProgram->deactivate(); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glm::vec3 cameraPosition; + bool cameraIsInside = raycaster->cameraIsInside( + raycasterTask.renderData, + cameraPosition + ); + ghoul::opengl::ProgramObject* raycastProgram = nullptr; + + if (cameraIsInside) { + raycastProgram = _insideRaycastPrograms[raycaster].get(); + if (raycastProgram) { + raycastProgram->activate(); + raycastProgram->setUniform("cameraPosInRaycaster", cameraPosition); + } + } else { + raycastProgram = _raycastPrograms[raycaster].get(); + if (raycastProgram) { + raycastProgram->activate(); + } + } + + if (raycastProgram) { + raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); + + ghoul::opengl::TextureUnit exitColorTextureUnit; + exitColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + raycastProgram->setUniform("exitColorTexture", exitColorTextureUnit); + + ghoul::opengl::TextureUnit exitDepthTextureUnit; + exitDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + raycastProgram->setUniform("exitDepthTexture", exitDepthTextureUnit); + + ghoul::opengl::TextureUnit mainDepthTextureUnit; + mainDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit); + + raycastProgram->setUniform("nAaSamples", _nAaSamples); + raycastProgram->setUniform("windowSize", glm::vec2(_resolution)); + + + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + if (cameraIsInside) { + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + } else { + raycaster->renderEntryPoints(raycasterTask.renderData, *raycastProgram); + } + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + + raycaster->postRaycast(_raycastData[raycaster], *raycastProgram); + raycastProgram->deactivate(); + } else { + LWARNING("Raycaster is not attached when trying to perform raycaster task"); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + _resolveProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + _resolveProgram->setUniform("mainColorTexture", mainColorTextureUnit); + _resolveProgram->setUniform("blackoutFactor", blackoutFactor); + _resolveProgram->setUniform("nAaSamples", _nAaSamples); + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _resolveProgram->deactivate(); +} + +void FramebufferRenderer::setScene(Scene* scene) { + _scene = scene; +} + +void FramebufferRenderer::setCamera(Camera* camera) { + _camera = camera; +} + +void FramebufferRenderer::setResolution(glm::ivec2 res) { + _resolution = res; + _dirtyResolution = true; +} + +void FramebufferRenderer::setNAaSamples(int nAaSamples) { + _nAaSamples = nAaSamples; + if (_nAaSamples == 0) { + _nAaSamples = 1; + } + if (_nAaSamples > 8) { + LERROR("Framebuffer renderer does not support more than 8 MSAA samples."); + _nAaSamples = 8; + } + _dirtyResolution = true; +} + +void FramebufferRenderer::updateRendererData() { + ghoul::Dictionary dict; + dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); + + _rendererData = dict; + + OsEng.renderEngine().setRendererData(dict); +} + +} // namespace openspace diff --git a/src/util/syncbuffer.cpp b/src/util/syncbuffer.cpp index 3e2499ab81..593012be92 100644 --- a/src/util/syncbuffer.cpp +++ b/src/util/syncbuffer.cpp @@ -1,62 +1,62 @@ -/***************************************************************************************** - * * - * 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 - -#include - -namespace openspace { - -SyncBuffer::SyncBuffer(size_t n) - : _n(n) - , _encodeOffset(0) - , _decodeOffset(0) - , _synchronizationBuffer(new sgct::SharedVector()) -{ - _dataStream.resize(_n); -} - -SyncBuffer::~SyncBuffer() { - // The destructor is defined here, so that the otherwise default inlined destructor is - // not created (which would make it impossible to use a forward declaration with - // unique_ptr -} - -void SyncBuffer::write() { - _dataStream.resize(_encodeOffset); - _synchronizationBuffer->setVal(_dataStream); - sgct::SharedData::instance()->writeVector(_synchronizationBuffer.get()); - _dataStream.resize(_n); - _encodeOffset = 0; - _decodeOffset = 0; -} - -void SyncBuffer::read() { - sgct::SharedData::instance()->readVector(_synchronizationBuffer.get()); - _dataStream = _synchronizationBuffer->getVal(); - _encodeOffset = 0; - _decodeOffset = 0; -} - -} // namespace openspace +/***************************************************************************************** + * * + * 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 + +#include + +namespace openspace { + +SyncBuffer::SyncBuffer(size_t n) + : _n(n) + , _encodeOffset(0) + , _decodeOffset(0) + , _synchronizationBuffer(new sgct::SharedVector()) +{ + _dataStream.resize(_n); +} + +SyncBuffer::~SyncBuffer() { + // The destructor is defined here, so that the otherwise default inlined destructor is + // not created (which would make it impossible to use a forward declaration with + // unique_ptr +} + +void SyncBuffer::write() { + _dataStream.resize(_encodeOffset); + _synchronizationBuffer->setVal(_dataStream); + sgct::SharedData::instance()->writeVector(_synchronizationBuffer.get()); + _dataStream.resize(_n); + _encodeOffset = 0; + _decodeOffset = 0; +} + +void SyncBuffer::read() { + sgct::SharedData::instance()->readVector(_synchronizationBuffer.get()); + _dataStream = _synchronizationBuffer->getVal(); + _encodeOffset = 0; + _decodeOffset = 0; +} + +} // namespace openspace diff --git a/support/cmake/support_macros.cmake b/support/cmake/support_macros.cmake index 84ea5c5877..28273f7724 100644 --- a/support/cmake/support_macros.cmake +++ b/support/cmake/support_macros.cmake @@ -1,582 +1,582 @@ -######################################################################################### -# # -# 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. # -######################################################################################### - -function (test_compiler_compatibility) - if (MSVC) - if (MSVC_VERSION LESS 1900) - message(FATAL_ERROR "OpenSpace requires at least Visual Studio 2015") - endif () - endif () -endfunction () - - - -macro (cleanup_project) - # Remove MinSizeRel build option - set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE TYPE INTERNAL FORCE) - mark_as_advanced(CMAKE_CONFIGURATION_TYPES) - mark_as_advanced(CMAKE_INSTALL_PREFIX) - - set_property(GLOBAL PROPERTY USE_FOLDERS On) - set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMake) -endmacro () - - -macro (set_build_output_directories) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_CMAKE_EXT_DIR}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/openspace) -endmacro () - - - -function (create_openspace_target) - add_library(libOpenSpace STATIC ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}/include) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}) - target_include_directories(libOpenSpace PUBLIC ${CMAKE_BINARY_DIR}/_generated/include) - - configure_file( - ${OPENSPACE_CMAKE_EXT_DIR}/openspace_header.template - ${CMAKE_BINARY_DIR}/_generated/include/openspace/openspace.h - @ONLY IMMEDIATE - ) - - set_compile_settings(libOpenSpace) -endfunction () - - - -function (set_compile_settings project) - set_property(TARGET ${project} PROPERTY CXX_STANDARD 17) - set_property(TARGET ${project} PROPERTY CXX_STANDARD_REQUIRED On) - - if (MSVC) - target_compile_options(${project} PRIVATE - "/ZI" # Edit and continue support - "/MP" # Multi-threading support - "/W4" # Highest warning level - "/w44062" # enumerator 'identifier' in a switch of enum 'enumeration' is not handled - "/wd4127" # conditional expression is constant - "/wd4201" # nonstandard extension used : nameless struct/union - "/w44255" # 'function': no function prototype given: converting '()' to '(void)' - "/w44263" # 'function': member function does not override any base class virtual member function - "/w44264" # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden - "/w44265" # 'class': class has virtual functions, but destructor is not virtual - "/w44266" # 'function': no override available for virtual member function from base 'type'; function is hidden - "/w44289" # nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope - "/w44296" # 'operator': expression is always false - "/w44311" # 'variable' : pointer truncation from 'type' to 'type' - "/w44339" # 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception - "/w44342" # behavior change: 'function' called, but a member operator was called in previous versions - "/w44350" # behavior change: 'member1' called instead of 'member2' - "/w44431" # missing type specifier - int assumed. Note: C no longer supports default-int - "/w44471" # a forward declaration of an unscoped enumeration must have an underlying type (int assumed) - "/w44545" # expression before comma evaluates to a function which is missing an argument list - "/w44546" # function call before comma missing argument list - "/w44547" # 'operator': operator before comma has no effect; expected operator with side-effect - "/w44548" # expression before comma has no effect; expected expression with side-effect - "/w44549" # 'operator': operator before comma has no effect; did you intend 'operator'? - "/w44555" # expression has no effect; expected expression with side-effect - "/w44574" # 'identifier' is defined to be '0': did you mean to use '#if identifier'? - "/w44608" # 'symbol1' has already been initialized by another union member in the initializer list, 'symbol2' - "/w44619" # #pragma warning: there is no warning number 'number' - "/w44628" # digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' - "/w44640" # 'instance': construction of local static object is not thread-safe - "/w44905" # wide string literal cast to 'LPSTR' - "/w44906" # string literal cast to 'LPWSTR' - "/w44946" # reinterpret_cast used between related classes: 'class1' and 'class2' - "/w44986" # 'symbol': exception specification does not match previous declaration - "/w44988" # 'symbol': variable declared outside class/function scope - # "/std:c++latest" # Boost as of 1.64 still uses unary_function - "/permissive-" - "/Zc:strictStrings-" # Windows header don't adhere to this - ) - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "/WX") - endif () - elseif (APPLE) - target_compile_definitions(${project} PRIVATE "__APPLE__") - - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "-Werror") - endif () - - target_compile_options(${project} PRIVATE "-stdlib=libc++") - - target_include_directories(${project} PUBLIC "/Developer/Headers/FlatCarbon") - find_library(COREFOUNDATION_LIBRARY CoreFoundation) - find_library(CARBON_LIBRARY Carbon) - find_library(COCOA_LIBRARY Carbon) - find_library(APP_SERVICES_LIBRARY ApplicationServices) - mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY) - target_link_libraries(${project} - ${CARBON_LIBRARY} - ${COREFOUNDATION_LIBRARY} - ${COCOA_LIBRARY} - ${APP_SERVICES_LIBRARY} - ) - elseif (UNIX) - target_compile_options(${project} PRIVATE "-ggdb" "-Wall" "-Wno-long-long" "-pedantic" "-Wextra") - - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "-Werror") - endif () - endif () -endfunction () - - - -function (add_external_dependencies) - # Ghoul - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul) - target_link_libraries(libOpenSpace Ghoul) - get_property(GHOUL_INCLUDE_DIR TARGET Ghoul PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories(libOpenSpace PUBLIC ${GHOUL_INCLUDE_DIR}) - get_property(GHOUL_DEFINITIONS TARGET Ghoul PROPERTY INTERFACE_COMPILE_DEFINITIONS) - target_compile_definitions(libOpenSpace PUBLIC ${GHOUL_DEFINITIONS}) - set_property(TARGET Lua PROPERTY FOLDER "External") - set_property(TARGET lz4 PROPERTY FOLDER "External") - - # SGCT - set(SGCT_TEXT OFF CACHE BOOL "" FORCE) - set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) - set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) - set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) - set(JPEG_TURBO_WITH_SIMD OFF CACHE BOOL "" FORCE) - - add_subdirectory(${OPENSPACE_EXT_DIR}/sgct) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${OPENSPACE_EXT_DIR}/sgct/include) - target_link_libraries( - libOpenSpace - sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static - vrpn - ${GLFW_LIBRARIES} - ) - - set_property(TARGET sgct_light PROPERTY FOLDER "External") - if (TARGET glew) - set_property(TARGET glew PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET glfw) - set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET png16_static) - set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET quat) - set_property(TARGET quat PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET simd) - set_property(TARGET simd PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET tinyxml2static) - set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET turbojpeg-static) - set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET vrpn) - set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") - endif () - if (TARGET zlibstatic) - set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") - endif () - - if (UNIX AND (NOT APPLE)) - target_link_libraries(libOpenSpace Xcursor Xinerama X11) - endif () - - # Spice - add_subdirectory(${OPENSPACE_EXT_DIR}/spice) - target_link_libraries(libOpenSpace Spice) - get_property(SPICE_INCLUDE_DIR TARGET Spice PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories(libOpenSpace PUBLIC ${SPICE_INCLUDE_DIR}) - set_property(TARGET Spice PROPERTY FOLDER "External") - - # Curl - if (WIN32) - set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl") - set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl" PARENT_SCOPE) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_ROOT_DIR}/include) - target_link_libraries(libOpenSpace ${CURL_ROOT_DIR}/lib/libcurl_imp.lib) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED" "CURL_STATICLIB") - else () - find_package(CURL) - if (CURL_FOUND) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_INCLUDE_DIRS}) - target_link_libraries(libOpenSpace ${CURL_LIBRARIES}) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED") - endif () - endif() - - # Qt - # Unfortunately, we have to set this value manually; sigh - # In the future, if the Qt version is updated, just add to this variable ---abock - if (APPLE) - set(CMAKE_PREFIX_PATH - "~/Qt/5.6/clang_64/lib/cmake" - "~/Qt/5.7/clang_64/lib/cmake" - PARENT_SCOPE - ) - endif () -endfunction () - - - -function (handle_applications) - set(applications "") - set(applications_link_to_openspace "") - - file(GLOB appDirs RELATIVE ${OPENSPACE_APPS_DIR} ${OPENSPACE_APPS_DIR}/*) - list(REMOVE_ITEM appDirs ".DS_Store") # Removing the .DS_Store present on Mac - - set(DEFAULT_APPLICATIONS - "OpenSpace" - "Launcher" - ) - mark_as_advanced(DEFAULT_APPLICATIONS) - - foreach (app ${appDirs}) - string(TOUPPER ${app} upper_app) - list (FIND DEFAULT_APPLICATIONS "${app}" _index) - if (${_index} GREATER -1) - # App is a default application - option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" ON) - else () - option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" OFF) - endif() - if (OPENSPACE_APPLICATION_${upper_app}) - unset(APPLICATION_NAME) - unset(APPLICATION_LINK_TO_OPENSPACE) - include(${OPENSPACE_APPS_DIR}/${app}/CMakeLists.txt) - set_compile_settings(${APPLICATION_NAME}) - - if (APPLICATION_LINK_TO_OPENSPACE) - get_property( - OPENSPACE_INCLUDE_DIR - TARGET libOpenSpace - PROPERTY INTERFACE_INCLUDE_DIRECTORIES - ) - target_include_directories(${APPLICATION_NAME} PUBLIC - "${OPENSPACE_BASE_DIR}" - ${OPENSPACE_INCLUDE_DIR} - ) - - get_property( - OPENSPACE_DEFINES - TARGET libOpenSpace - PROPERTY INTERFACE_COMPILE_DEFINITIONS - ) - target_compile_definitions(${APPLICATION_NAME} PUBLIC ${OPENSPACE_DEFINES}) - - target_link_libraries(${APPLICATION_NAME} Ghoul) - target_link_libraries(${APPLICATION_NAME} libOpenSpace) - - if (MSVC) - set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS - "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" - ) - endif () - - - if (WIN32) - ghl_copy_files( - ${APPLICATION_NAME} - "${CURL_ROOT_DIR}/lib/libcurl.dll" - "${CURL_ROOT_DIR}/lib/libeay32.dll" - "${CURL_ROOT_DIR}/lib/ssleay32.dll" - - ) - ghl_copy_shared_libraries(${APPLICATION_NAME} ${OPENSPACE_EXT_DIR}/ghoul) - endif () - endif () - - list(APPEND applications ${APPLICATION_NAME}) - list(APPEND applications_link_to_openspace ${APPLICATION_LINK_TO_OPENSPACE}) - unset(APPLICATION_NAME) - unset(APPLICATION_LINK_TO_OPENSPACE) - endif () - endforeach () - - - # option(OPENSPACE_APPLICATION_OPENSPACE "Main OpenSpace Application" ON) - # if (OPENSPACE_APPLICATION_OPENSPACE) - # include(${OPENSPACE_APPS_DIR}/OpenSpace/CMakeLists.txt) - # list(APPEND applications "OpenSpace") - # endif () - set(OPENSPACE_APPLICATIONS ${applications} PARENT_SCOPE) - set(OPENSPACE_APPLICATIONS_LINK_REQUEST ${applications_link_to_openspace} PARENT_SCOPE) - - message(STATUS "Applications:") - list(LENGTH applications len1) - math(EXPR len2 "${len1} - 1") - - foreach(val RANGE ${len2}) - list(GET applications ${val} val1) - list(GET applications_link_to_openspace ${val} val2) - message(STATUS "\t${val1} (Link: ${val2})") - endforeach() -endfunction() - - -function (handle_option_vld) - if (OPENSPACE_ENABLE_VLD) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_ENABLE_VLD") - target_link_libraries(libOpenSpace ${OPENSPACE_EXT_DIR}/vld/lib/vld.lib) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_EXT_DIR}/vld) - - foreach (app ${OPENSPACE_APPLCATIONS}) - ghl_copy_files(${app} "${OPENSPACE_EXT_DIR}/vld/bin/vld_x64.dll") - endforeach () - endif () -endfunction () - - - -function (handle_option_tests) - if (OPENSPACE_HAVE_TESTS) - if (NOT TARGET gtest) - set(BUILD_GTEST ON CACHE BOOL "") - set(BUILD_GMOCK OFF CACHE BOOL "") - set(gtest_force_shared_crt ON CACHE BOOL "") - # set(BUILD_GMOCK OFF CACHE BOOL "") - # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) - # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) - # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) - # add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/gtest) - set_property(TARGET gtest PROPERTY FOLDER "External") - set_property(TARGET gtest_main PROPERTY FOLDER "External") - endif () - - file(GLOB_RECURSE OPENSPACE_TEST_FILES ${OPENSPACE_BASE_DIR}/tests/*.inl) - - add_executable(OpenSpaceTest ${OPENSPACE_BASE_DIR}/tests/main.cpp ${OPENSPACE_TEST_FILES}) - target_include_directories(OpenSpaceTest PUBLIC - "${OPENSPACE_BASE_DIR}/include" - "${OPENSPACE_BASE_DIR}/tests" - "${OPENSPACE_EXT_DIR}/ghoul/ext/googletest/googletest/include" - ) - target_compile_definitions(OpenSpaceTest PUBLIC - "GHL_THROW_ON_ASSERT" - "GTEST_HAS_TR1_TUPLE=0" - ) - target_link_libraries(OpenSpaceTest gtest libOpenSpace) - - if (MSVC) - set_target_properties(OpenSpaceTest PROPERTIES LINK_FLAGS - "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" - ) - endif () - set_property(TARGET OpenSpaceTest PROPERTY FOLDER "Unit Tests") - set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD 14) - set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD_REQUIRED On) - endif (OPENSPACE_HAVE_TESTS) - if (TARGET GhoulTest) - if (NOT TARGET gtest) - set(BUILD_GTEST ON CACHE BOOL "") - set(BUILD_GMOCK OFF CACHE BOOL "") - set(gtest_force_shared_crt ON CACHE BOOL "") - # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) - # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) - # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) - endif () - - set_property(TARGET gtest PROPERTY FOLDER "External") - set_property(TARGET GhoulTest PROPERTY FOLDER "Unit Tests") - endif () -endfunction () - - - -function (handle_internal_modules) -# Get all modules in the correct order based on their dependencies - file(GLOB moduleDirs RELATIVE ${OPENSPACE_MODULE_DIR} ${OPENSPACE_MODULE_DIR}/*) - set(sortedModules ${moduleDirs}) - foreach (dir ${moduleDirs}) - if (IS_DIRECTORY ${OPENSPACE_MODULE_DIR}/${dir}) - set(defaultModule OFF) - if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") - unset(OPENSPACE_DEPENDENCIES) - unset(EXTERNAL_LIBRAY) - unset(DEFAULT_MODULE) - include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) - - if (DEFINED DEFAULT_MODULE) - set(defaultModule ${DEFAULT_MODULE}) - endif () - if (OPENSPACE_DEPENDENCIES) - foreach (dependency ${OPENSPACE_DEPENDENCIES}) - create_library_name(${dependency} library) - if (TARGET ${library}) - # already registered - list(REMOVE_ITEM OPENSPACE_DEPENDENCIES ${dependency}) - endif () - endforeach () - - list(APPEND OPENSPACE_DEPENDENCIES ${dir}) - list(FIND sortedModules ${dir} dir_index) - # if (NOT dir STREQUAL "base") - # list(INSERT OPENSPACE_DEPENDENCIES 0 "base") - # endif () - list(INSERT sortedModules ${dir_index} ${OPENSPACE_DEPENDENCIES}) - list(REMOVE_DUPLICATES sortedModules) - endif () - endif () - create_option_name(${dir} optionName) - option(${optionName} "Build ${dir} Module" ${defaultModule}) - # create_library_name(${module} ${library}) - else () - list(REMOVE_ITEM sortedModules ${dir}) - endif () - endforeach () - - # Automatically set dependent modules to ON - set(dir_list ${sortedModules}) - set(dll_list "") - list(REVERSE dir_list) - foreach (dir ${dir_list}) - create_option_name(${dir} optionName) - if (${optionName}) - if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") - unset(OPENSPACE_DEPENDENCIES) - unset(EXTERNAL_LIBRAY) - unset(DEFAULT_MODULE) - include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) - - if (OPENSPACE_DEPENDENCIES) - foreach (dependency ${OPENSPACE_DEPENDENCIES}) - create_option_name(${dependency} dependencyOptionName) - if (NOT ${dependencyOptionName}) - set(${dependencyOptionName} ON CACHE BOOL "ff" FORCE) - message(STATUS "${dependencyOptionName} was set to build, due to dependency towards ${optionName}") - endif () - endforeach () - endif () - endif () - endif () - endforeach () - - set(MODULE_HEADERS "") - set(MODULE_CLASSES "") - - message(STATUS "Included modules:") - foreach (module ${sortedModules}) - create_option_name(${module} optionName) - if (${optionName}) - message(STATUS "\t${module}") - endif () - endforeach () - - # Add subdirectories in the correct order - foreach (module ${sortedModules}) - create_option_name(${module} optionName) - if (${optionName}) - create_library_name(${module} libraryName) - add_subdirectory(${OPENSPACE_MODULE_DIR}/${module}) - - list(LENGTH OPENSPACE_APPLICATIONS len1) - math(EXPR len2 "${len1} - 1") - - foreach(val RANGE ${len2}) - list(GET OPENSPACE_APPLICATIONS ${val} val1) - list(GET OPENSPACE_APPLICATIONS_LINK_REQUEST ${val} val2) - if (${val2}) - target_link_libraries(${app} ${libraryName}) - endif () - endforeach() - - # Only link libOpenSpace against the library if it has been set STATIC - get_target_property(libType ${libraryName} TYPE) - if (NOT ${libType} STREQUAL "SHARED_LIBRARY") - target_link_libraries(libOpenSpace ${libraryName}) - endif() - - create_define_name(${module} defineName) - target_compile_definitions(libOpenSpace PUBLIC "${defineName}") - - # Create registration file - string(TOUPPER ${module} module_upper) - string(TOLOWER ${module} module_lower) - unset(MODULE_NAME) - unset(MODULE_PATH) - include(${CMAKE_BINARY_DIR}/modules/${module_lower}/modulename.cmake) - - list(APPEND MODULE_HEADERS - #"#ifdef REGISTRATION_OPENSPACE${module_upper}MODULE\n" - "#include <${MODULE_PATH}>\n" - #"#endif\n\n" - ) - list(APPEND MODULE_CLASSES " new ${MODULE_NAME},\n") - - if (EXTERNAL_LIBRARY) - foreach (library ${EXTERNAL_LIBRARY}) - get_filename_component(lib ${library} ABSOLUTE) - list(APPEND dll_list ${lib}) - endforeach() - endif () - endif () - endforeach () - - if (NOT "${MODULE_HEADERS}" STREQUAL "") - string(REPLACE ";" "" MODULE_HEADERS ${MODULE_HEADERS}) - endif () - - if (NOT "${MODULE_CLASSES}" STREQUAL "") - string(REPLACE ";" "" MODULE_CLASSES ${MODULE_CLASSES}) - endif () - - configure_file( - ${OPENSPACE_CMAKE_EXT_DIR}/module_registration.template - ${CMAKE_BINARY_DIR}/_generated/include/openspace/moduleregistration.h - ) - - list(REMOVE_DUPLICATES dll_list) - - if (WIN32) - foreach (application ${OPENSPACE_APPLICATIONS}) - foreach (dll ${dll_list}) - ghl_copy_files(${application} ${dll}) - endforeach () - endforeach () - endif () -endfunction () - - - -function (copy_dynamic_libraries) - if (WIN32) - ghl_copy_files(OpenSpace "${CURL_ROOT_DIR}/lib/libcurl.dll") - - # Copy DLLs needed by Ghoul into the executable directory - ghl_copy_shared_libraries(OpenSpace ${OPENSPACE_EXT_DIR}/ghoul) - - if (TARGET OpenSpaceTest) - ghl_copy_shared_libraries(OpenSpaceTest ${OPENSPACE_EXT_DIR}/ghoul) - endif () - endif () -endfunction () +######################################################################################### +# # +# 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. # +######################################################################################### + +function (test_compiler_compatibility) + if (MSVC) + if (MSVC_VERSION LESS 1900) + message(FATAL_ERROR "OpenSpace requires at least Visual Studio 2015") + endif () + endif () +endfunction () + + + +macro (cleanup_project) + # Remove MinSizeRel build option + set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE TYPE INTERNAL FORCE) + mark_as_advanced(CMAKE_CONFIGURATION_TYPES) + mark_as_advanced(CMAKE_INSTALL_PREFIX) + + set_property(GLOBAL PROPERTY USE_FOLDERS On) + set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMake) +endmacro () + + +macro (set_build_output_directories) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_CMAKE_EXT_DIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/openspace) +endmacro () + + + +function (create_openspace_target) + add_library(libOpenSpace STATIC ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}/include) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}) + target_include_directories(libOpenSpace PUBLIC ${CMAKE_BINARY_DIR}/_generated/include) + + configure_file( + ${OPENSPACE_CMAKE_EXT_DIR}/openspace_header.template + ${CMAKE_BINARY_DIR}/_generated/include/openspace/openspace.h + @ONLY IMMEDIATE + ) + + set_compile_settings(libOpenSpace) +endfunction () + + + +function (set_compile_settings project) + set_property(TARGET ${project} PROPERTY CXX_STANDARD 17) + set_property(TARGET ${project} PROPERTY CXX_STANDARD_REQUIRED On) + + if (MSVC) + target_compile_options(${project} PRIVATE + "/ZI" # Edit and continue support + "/MP" # Multi-threading support + "/W4" # Highest warning level + "/w44062" # enumerator 'identifier' in a switch of enum 'enumeration' is not handled + "/wd4127" # conditional expression is constant + "/wd4201" # nonstandard extension used : nameless struct/union + "/w44255" # 'function': no function prototype given: converting '()' to '(void)' + "/w44263" # 'function': member function does not override any base class virtual member function + "/w44264" # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden + "/w44265" # 'class': class has virtual functions, but destructor is not virtual + "/w44266" # 'function': no override available for virtual member function from base 'type'; function is hidden + "/w44289" # nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope + "/w44296" # 'operator': expression is always false + "/w44311" # 'variable' : pointer truncation from 'type' to 'type' + "/w44339" # 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception + "/w44342" # behavior change: 'function' called, but a member operator was called in previous versions + "/w44350" # behavior change: 'member1' called instead of 'member2' + "/w44431" # missing type specifier - int assumed. Note: C no longer supports default-int + "/w44471" # a forward declaration of an unscoped enumeration must have an underlying type (int assumed) + "/w44545" # expression before comma evaluates to a function which is missing an argument list + "/w44546" # function call before comma missing argument list + "/w44547" # 'operator': operator before comma has no effect; expected operator with side-effect + "/w44548" # expression before comma has no effect; expected expression with side-effect + "/w44549" # 'operator': operator before comma has no effect; did you intend 'operator'? + "/w44555" # expression has no effect; expected expression with side-effect + "/w44574" # 'identifier' is defined to be '0': did you mean to use '#if identifier'? + "/w44608" # 'symbol1' has already been initialized by another union member in the initializer list, 'symbol2' + "/w44619" # #pragma warning: there is no warning number 'number' + "/w44628" # digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' + "/w44640" # 'instance': construction of local static object is not thread-safe + "/w44905" # wide string literal cast to 'LPSTR' + "/w44906" # string literal cast to 'LPWSTR' + "/w44946" # reinterpret_cast used between related classes: 'class1' and 'class2' + "/w44986" # 'symbol': exception specification does not match previous declaration + "/w44988" # 'symbol': variable declared outside class/function scope + # "/std:c++latest" # Boost as of 1.64 still uses unary_function + "/permissive-" + "/Zc:strictStrings-" # Windows header don't adhere to this + ) + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "/WX") + endif () + elseif (APPLE) + target_compile_definitions(${project} PRIVATE "__APPLE__") + + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "-Werror") + endif () + + target_compile_options(${project} PRIVATE "-stdlib=libc++") + + target_include_directories(${project} PUBLIC "/Developer/Headers/FlatCarbon") + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + find_library(CARBON_LIBRARY Carbon) + find_library(COCOA_LIBRARY Carbon) + find_library(APP_SERVICES_LIBRARY ApplicationServices) + mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY) + target_link_libraries(${project} + ${CARBON_LIBRARY} + ${COREFOUNDATION_LIBRARY} + ${COCOA_LIBRARY} + ${APP_SERVICES_LIBRARY} + ) + elseif (UNIX) + target_compile_options(${project} PRIVATE "-ggdb" "-Wall" "-Wno-long-long" "-pedantic" "-Wextra") + + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "-Werror") + endif () + endif () +endfunction () + + + +function (add_external_dependencies) + # Ghoul + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul) + target_link_libraries(libOpenSpace Ghoul) + get_property(GHOUL_INCLUDE_DIR TARGET Ghoul PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(libOpenSpace PUBLIC ${GHOUL_INCLUDE_DIR}) + get_property(GHOUL_DEFINITIONS TARGET Ghoul PROPERTY INTERFACE_COMPILE_DEFINITIONS) + target_compile_definitions(libOpenSpace PUBLIC ${GHOUL_DEFINITIONS}) + set_property(TARGET Lua PROPERTY FOLDER "External") + set_property(TARGET lz4 PROPERTY FOLDER "External") + + # SGCT + set(SGCT_TEXT OFF CACHE BOOL "" FORCE) + set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) + set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) + set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) + set(JPEG_TURBO_WITH_SIMD OFF CACHE BOOL "" FORCE) + + add_subdirectory(${OPENSPACE_EXT_DIR}/sgct) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${OPENSPACE_EXT_DIR}/sgct/include) + target_link_libraries( + libOpenSpace + sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static + vrpn + ${GLFW_LIBRARIES} + ) + + set_property(TARGET sgct_light PROPERTY FOLDER "External") + if (TARGET glew) + set_property(TARGET glew PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET glfw) + set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET png16_static) + set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET quat) + set_property(TARGET quat PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET simd) + set_property(TARGET simd PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET tinyxml2static) + set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET turbojpeg-static) + set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET vrpn) + set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET zlibstatic) + set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") + endif () + + if (UNIX AND (NOT APPLE)) + target_link_libraries(libOpenSpace Xcursor Xinerama X11) + endif () + + # Spice + add_subdirectory(${OPENSPACE_EXT_DIR}/spice) + target_link_libraries(libOpenSpace Spice) + get_property(SPICE_INCLUDE_DIR TARGET Spice PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(libOpenSpace PUBLIC ${SPICE_INCLUDE_DIR}) + set_property(TARGET Spice PROPERTY FOLDER "External") + + # Curl + if (WIN32) + set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl") + set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl" PARENT_SCOPE) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_ROOT_DIR}/include) + target_link_libraries(libOpenSpace ${CURL_ROOT_DIR}/lib/libcurl_imp.lib) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED" "CURL_STATICLIB") + else () + find_package(CURL) + if (CURL_FOUND) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_INCLUDE_DIRS}) + target_link_libraries(libOpenSpace ${CURL_LIBRARIES}) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED") + endif () + endif() + + # Qt + # Unfortunately, we have to set this value manually; sigh + # In the future, if the Qt version is updated, just add to this variable ---abock + if (APPLE) + set(CMAKE_PREFIX_PATH + "~/Qt/5.6/clang_64/lib/cmake" + "~/Qt/5.7/clang_64/lib/cmake" + PARENT_SCOPE + ) + endif () +endfunction () + + + +function (handle_applications) + set(applications "") + set(applications_link_to_openspace "") + + file(GLOB appDirs RELATIVE ${OPENSPACE_APPS_DIR} ${OPENSPACE_APPS_DIR}/*) + list(REMOVE_ITEM appDirs ".DS_Store") # Removing the .DS_Store present on Mac + + set(DEFAULT_APPLICATIONS + "OpenSpace" + "Launcher" + ) + mark_as_advanced(DEFAULT_APPLICATIONS) + + foreach (app ${appDirs}) + string(TOUPPER ${app} upper_app) + list (FIND DEFAULT_APPLICATIONS "${app}" _index) + if (${_index} GREATER -1) + # App is a default application + option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" ON) + else () + option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" OFF) + endif() + if (OPENSPACE_APPLICATION_${upper_app}) + unset(APPLICATION_NAME) + unset(APPLICATION_LINK_TO_OPENSPACE) + include(${OPENSPACE_APPS_DIR}/${app}/CMakeLists.txt) + set_compile_settings(${APPLICATION_NAME}) + + if (APPLICATION_LINK_TO_OPENSPACE) + get_property( + OPENSPACE_INCLUDE_DIR + TARGET libOpenSpace + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ) + target_include_directories(${APPLICATION_NAME} PUBLIC + "${OPENSPACE_BASE_DIR}" + ${OPENSPACE_INCLUDE_DIR} + ) + + get_property( + OPENSPACE_DEFINES + TARGET libOpenSpace + PROPERTY INTERFACE_COMPILE_DEFINITIONS + ) + target_compile_definitions(${APPLICATION_NAME} PUBLIC ${OPENSPACE_DEFINES}) + + target_link_libraries(${APPLICATION_NAME} Ghoul) + target_link_libraries(${APPLICATION_NAME} libOpenSpace) + + if (MSVC) + set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS + "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" + ) + endif () + + + if (WIN32) + ghl_copy_files( + ${APPLICATION_NAME} + "${CURL_ROOT_DIR}/lib/libcurl.dll" + "${CURL_ROOT_DIR}/lib/libeay32.dll" + "${CURL_ROOT_DIR}/lib/ssleay32.dll" + + ) + ghl_copy_shared_libraries(${APPLICATION_NAME} ${OPENSPACE_EXT_DIR}/ghoul) + endif () + endif () + + list(APPEND applications ${APPLICATION_NAME}) + list(APPEND applications_link_to_openspace ${APPLICATION_LINK_TO_OPENSPACE}) + unset(APPLICATION_NAME) + unset(APPLICATION_LINK_TO_OPENSPACE) + endif () + endforeach () + + + # option(OPENSPACE_APPLICATION_OPENSPACE "Main OpenSpace Application" ON) + # if (OPENSPACE_APPLICATION_OPENSPACE) + # include(${OPENSPACE_APPS_DIR}/OpenSpace/CMakeLists.txt) + # list(APPEND applications "OpenSpace") + # endif () + set(OPENSPACE_APPLICATIONS ${applications} PARENT_SCOPE) + set(OPENSPACE_APPLICATIONS_LINK_REQUEST ${applications_link_to_openspace} PARENT_SCOPE) + + message(STATUS "Applications:") + list(LENGTH applications len1) + math(EXPR len2 "${len1} - 1") + + foreach(val RANGE ${len2}) + list(GET applications ${val} val1) + list(GET applications_link_to_openspace ${val} val2) + message(STATUS "\t${val1} (Link: ${val2})") + endforeach() +endfunction() + + +function (handle_option_vld) + if (OPENSPACE_ENABLE_VLD) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_ENABLE_VLD") + target_link_libraries(libOpenSpace ${OPENSPACE_EXT_DIR}/vld/lib/vld.lib) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_EXT_DIR}/vld) + + foreach (app ${OPENSPACE_APPLCATIONS}) + ghl_copy_files(${app} "${OPENSPACE_EXT_DIR}/vld/bin/vld_x64.dll") + endforeach () + endif () +endfunction () + + + +function (handle_option_tests) + if (OPENSPACE_HAVE_TESTS) + if (NOT TARGET gtest) + set(BUILD_GTEST ON CACHE BOOL "") + set(BUILD_GMOCK OFF CACHE BOOL "") + set(gtest_force_shared_crt ON CACHE BOOL "") + # set(BUILD_GMOCK OFF CACHE BOOL "") + # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) + # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) + # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) + # add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/gtest) + set_property(TARGET gtest PROPERTY FOLDER "External") + set_property(TARGET gtest_main PROPERTY FOLDER "External") + endif () + + file(GLOB_RECURSE OPENSPACE_TEST_FILES ${OPENSPACE_BASE_DIR}/tests/*.inl) + + add_executable(OpenSpaceTest ${OPENSPACE_BASE_DIR}/tests/main.cpp ${OPENSPACE_TEST_FILES}) + target_include_directories(OpenSpaceTest PUBLIC + "${OPENSPACE_BASE_DIR}/include" + "${OPENSPACE_BASE_DIR}/tests" + "${OPENSPACE_EXT_DIR}/ghoul/ext/googletest/googletest/include" + ) + target_compile_definitions(OpenSpaceTest PUBLIC + "GHL_THROW_ON_ASSERT" + "GTEST_HAS_TR1_TUPLE=0" + ) + target_link_libraries(OpenSpaceTest gtest libOpenSpace) + + if (MSVC) + set_target_properties(OpenSpaceTest PROPERTIES LINK_FLAGS + "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" + ) + endif () + set_property(TARGET OpenSpaceTest PROPERTY FOLDER "Unit Tests") + set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD 14) + set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD_REQUIRED On) + endif (OPENSPACE_HAVE_TESTS) + if (TARGET GhoulTest) + if (NOT TARGET gtest) + set(BUILD_GTEST ON CACHE BOOL "") + set(BUILD_GMOCK OFF CACHE BOOL "") + set(gtest_force_shared_crt ON CACHE BOOL "") + # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) + # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) + # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) + endif () + + set_property(TARGET gtest PROPERTY FOLDER "External") + set_property(TARGET GhoulTest PROPERTY FOLDER "Unit Tests") + endif () +endfunction () + + + +function (handle_internal_modules) +# Get all modules in the correct order based on their dependencies + file(GLOB moduleDirs RELATIVE ${OPENSPACE_MODULE_DIR} ${OPENSPACE_MODULE_DIR}/*) + set(sortedModules ${moduleDirs}) + foreach (dir ${moduleDirs}) + if (IS_DIRECTORY ${OPENSPACE_MODULE_DIR}/${dir}) + set(defaultModule OFF) + if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") + unset(OPENSPACE_DEPENDENCIES) + unset(EXTERNAL_LIBRAY) + unset(DEFAULT_MODULE) + include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) + + if (DEFINED DEFAULT_MODULE) + set(defaultModule ${DEFAULT_MODULE}) + endif () + if (OPENSPACE_DEPENDENCIES) + foreach (dependency ${OPENSPACE_DEPENDENCIES}) + create_library_name(${dependency} library) + if (TARGET ${library}) + # already registered + list(REMOVE_ITEM OPENSPACE_DEPENDENCIES ${dependency}) + endif () + endforeach () + + list(APPEND OPENSPACE_DEPENDENCIES ${dir}) + list(FIND sortedModules ${dir} dir_index) + # if (NOT dir STREQUAL "base") + # list(INSERT OPENSPACE_DEPENDENCIES 0 "base") + # endif () + list(INSERT sortedModules ${dir_index} ${OPENSPACE_DEPENDENCIES}) + list(REMOVE_DUPLICATES sortedModules) + endif () + endif () + create_option_name(${dir} optionName) + option(${optionName} "Build ${dir} Module" ${defaultModule}) + # create_library_name(${module} ${library}) + else () + list(REMOVE_ITEM sortedModules ${dir}) + endif () + endforeach () + + # Automatically set dependent modules to ON + set(dir_list ${sortedModules}) + set(dll_list "") + list(REVERSE dir_list) + foreach (dir ${dir_list}) + create_option_name(${dir} optionName) + if (${optionName}) + if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") + unset(OPENSPACE_DEPENDENCIES) + unset(EXTERNAL_LIBRAY) + unset(DEFAULT_MODULE) + include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) + + if (OPENSPACE_DEPENDENCIES) + foreach (dependency ${OPENSPACE_DEPENDENCIES}) + create_option_name(${dependency} dependencyOptionName) + if (NOT ${dependencyOptionName}) + set(${dependencyOptionName} ON CACHE BOOL "ff" FORCE) + message(STATUS "${dependencyOptionName} was set to build, due to dependency towards ${optionName}") + endif () + endforeach () + endif () + endif () + endif () + endforeach () + + set(MODULE_HEADERS "") + set(MODULE_CLASSES "") + + message(STATUS "Included modules:") + foreach (module ${sortedModules}) + create_option_name(${module} optionName) + if (${optionName}) + message(STATUS "\t${module}") + endif () + endforeach () + + # Add subdirectories in the correct order + foreach (module ${sortedModules}) + create_option_name(${module} optionName) + if (${optionName}) + create_library_name(${module} libraryName) + add_subdirectory(${OPENSPACE_MODULE_DIR}/${module}) + + list(LENGTH OPENSPACE_APPLICATIONS len1) + math(EXPR len2 "${len1} - 1") + + foreach(val RANGE ${len2}) + list(GET OPENSPACE_APPLICATIONS ${val} val1) + list(GET OPENSPACE_APPLICATIONS_LINK_REQUEST ${val} val2) + if (${val2}) + target_link_libraries(${app} ${libraryName}) + endif () + endforeach() + + # Only link libOpenSpace against the library if it has been set STATIC + get_target_property(libType ${libraryName} TYPE) + if (NOT ${libType} STREQUAL "SHARED_LIBRARY") + target_link_libraries(libOpenSpace ${libraryName}) + endif() + + create_define_name(${module} defineName) + target_compile_definitions(libOpenSpace PUBLIC "${defineName}") + + # Create registration file + string(TOUPPER ${module} module_upper) + string(TOLOWER ${module} module_lower) + unset(MODULE_NAME) + unset(MODULE_PATH) + include(${CMAKE_BINARY_DIR}/modules/${module_lower}/modulename.cmake) + + list(APPEND MODULE_HEADERS + #"#ifdef REGISTRATION_OPENSPACE${module_upper}MODULE\n" + "#include <${MODULE_PATH}>\n" + #"#endif\n\n" + ) + list(APPEND MODULE_CLASSES " new ${MODULE_NAME},\n") + + if (EXTERNAL_LIBRARY) + foreach (library ${EXTERNAL_LIBRARY}) + get_filename_component(lib ${library} ABSOLUTE) + list(APPEND dll_list ${lib}) + endforeach() + endif () + endif () + endforeach () + + if (NOT "${MODULE_HEADERS}" STREQUAL "") + string(REPLACE ";" "" MODULE_HEADERS ${MODULE_HEADERS}) + endif () + + if (NOT "${MODULE_CLASSES}" STREQUAL "") + string(REPLACE ";" "" MODULE_CLASSES ${MODULE_CLASSES}) + endif () + + configure_file( + ${OPENSPACE_CMAKE_EXT_DIR}/module_registration.template + ${CMAKE_BINARY_DIR}/_generated/include/openspace/moduleregistration.h + ) + + list(REMOVE_DUPLICATES dll_list) + + if (WIN32) + foreach (application ${OPENSPACE_APPLICATIONS}) + foreach (dll ${dll_list}) + ghl_copy_files(${application} ${dll}) + endforeach () + endforeach () + endif () +endfunction () + + + +function (copy_dynamic_libraries) + if (WIN32) + ghl_copy_files(OpenSpace "${CURL_ROOT_DIR}/lib/libcurl.dll") + + # Copy DLLs needed by Ghoul into the executable directory + ghl_copy_shared_libraries(OpenSpace ${OPENSPACE_EXT_DIR}/ghoul) + + if (TARGET OpenSpaceTest) + ghl_copy_shared_libraries(OpenSpaceTest ${OPENSPACE_EXT_DIR}/ghoul) + endif () + endif () +endfunction ()