Skip to content
Commits on Source (83)
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Windows-style newlines with a newline ending every file
[*]
end_of_line = crlf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
# Files generated by CMake # Files generated by CMake
CMakeCache.txt CMakeCache.txt
CMakeLists.txt.user
CMakeFiles CMakeFiles
cmake_install.cmake cmake_install.cmake
Makefile Makefile
/core/gen_converterregistration.h /core/gen_converterregistration.h
/modules/gen_pipelineregistration.h /modules/gen_pipelineregistration.h
FailedShader.vert
FailedShader.geom
FailedShader.frag
FailedShader.comp
# Files generated by Qt's moc and uic # Files generated by Qt's moc and uic
moc_*.cxx moc_*.cxx
...@@ -48,3 +53,12 @@ ext/tbb ...@@ -48,3 +53,12 @@ ext/tbb
# SWIG wrapper code # SWIG wrapper code
*LUA_wrap.cxx *LUA_wrap.cxx
# CMake build folders and IDE folders
build*/
.vs/
.vscode/
# Mac specific
.DS_Store
# = CAMPVis - Yet another medical visualization framework ===================== # = CAMPVis - Yet another medical visualization framework =====================
CMAKE_MINIMUM_REQUIRED(VERSION 3.0.2 FATAL_ERROR)
cmake_policy(SET CMP0020 NEW)
PROJECT(CAMPVis) PROJECT(CAMPVis)
CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0 FATAL_ERROR)
SET(CAMPVIS_VERSION 1.0.0) SET(CAMPVIS_VERSION 1.0.0)
# = Global Build Options ====================================================== # = Global Build Options ======================================================
OPTION(BUILD_SHARED_LIBS "Build shared libraries (strongly recommended!)" ON) OPTION(BUILD_SHARED_LIBS "Build shared libraries (strongly recommended!)" ON)
OPTION(CAMPVIS_DEBUG "Activate debug code?" ON) OPTION(CAMPVIS_DEBUG "Activate debug code?" ON)
OPTION(CAMPVIS_BUILD_LIB_CGT "Build CGT Library" ON)
OPTION(CAMPVIS_BUILD_APPLICATION "Build CAMPVis Application" ON) OPTION(CAMPVIS_BUILD_APPLICATION "Build CAMPVis Application" ON)
OPTION(CAMPVIS_BUILD_MODULES "Build CAMPVis Modules" ON) OPTION(CAMPVIS_BUILD_MODULES "Build CAMPVis Modules" ON)
OPTION(CAMPVIS_ENABLE_SCRIPTING "Add support for scripting CAMPVis using Lua" OFF) OPTION(CAMPVIS_ENABLE_SCRIPTING "Add support for scripting CAMPVis using Lua" OFF)
...@@ -27,6 +30,10 @@ ENDIF() ...@@ -27,6 +30,10 @@ ENDIF()
SET(CAMPVIS_DEFAULT_ENABLED_MODULES "STABLE_NO_DEPENDENCIES" CACHE STRING "Default CAMPVis modules to activate") SET(CAMPVIS_DEFAULT_ENABLED_MODULES "STABLE_NO_DEPENDENCIES" CACHE STRING "Default CAMPVis modules to activate")
SET_PROPERTY(CACHE CAMPVIS_DEFAULT_ENABLED_MODULES PROPERTY STRINGS "NONE" "STABLE_NO_DEPENDENCIES" "STABLE_WITH_EXTERNAL_DEPENDENCIES" "TESTING" "ALL") SET_PROPERTY(CACHE CAMPVIS_DEFAULT_ENABLED_MODULES PROPERTY STRINGS "NONE" "STABLE_NO_DEPENDENCIES" "STABLE_WITH_EXTERNAL_DEPENDENCIES" "TESTING" "ALL")
IF(NOT BUILD_SHARED_LIBS)
MESSAGE(WARNING "Building shared libraries is turned off. Thus, CAMPVis will most probably not work as intended!\nPlease turn BUILD_SHARED_LIBS on unless you know what you're doing!")
ENDIF(NOT BUILD_SHARED_LIBS)
# propagate CAMPVIS_ENABLE_SCRIPTING to CAMPVIS_BUILD_LIB_LUA to support deprecated code # propagate CAMPVIS_ENABLE_SCRIPTING to CAMPVIS_BUILD_LIB_LUA to support deprecated code
IF (CAMPVIS_ENABLE_SCRIPTING) IF (CAMPVIS_ENABLE_SCRIPTING)
SET(CAMPVIS_BUILD_LIB_LUA ON) SET(CAMPVIS_BUILD_LIB_LUA ON)
...@@ -68,7 +75,7 @@ ENDIF() ...@@ -68,7 +75,7 @@ ENDIF()
# build campvis-test when enabled # build campvis-test when enabled
IF(CAMPVIS_ENABLE_TESTING) IF(CAMPVIS_ENABLE_TESTING)
ADD_SUBDIRECTORY(ext/gtest-1.7.0) ADD_SUBDIRECTORY(ext/googletest-release-1.8.0)
ADD_SUBDIRECTORY(test) ADD_SUBDIRECTORY(test)
ENDIF() ENDIF()
...@@ -105,15 +112,9 @@ EXPORT(PACKAGE CAMPVis) ...@@ -105,15 +112,9 @@ EXPORT(PACKAGE CAMPVis)
# = Copy Windows DLLs to binary dir for improved development experience ======= # = Copy Windows DLLs to binary dir for improved development experience =======
IF(WIN32) IF(WIN32)
# gather Qt4 DLLs - TODO: remove redundant naming of required components IF(CAMPVIS_COPY_EXTERNAL_DLLS)
FIND_PACKAGE(Qt4DLLs COMPONENTS QtCore QtGui QtOpenGL QtNetwork QtXmlPatterns)
LIST(APPEND CampvisExternalDllsDebug ${QT_DEBUG_DLLS})
LIST(APPEND CampvisExternalDllsRelease ${QT_RELEASE_DLLS})
LIST(REMOVE_DUPLICATES CampvisExternalDllsDebug) LIST(REMOVE_DUPLICATES CampvisExternalDllsDebug)
LIST(REMOVE_DUPLICATES CampvisExternalDllsRelease) LIST(REMOVE_DUPLICATES CampvisExternalDllsRelease)
IF(CAMPVIS_COPY_EXTERNAL_DLLS)
COPY_EXTERNAL_DLLS(CampvisExternalDllsDebug CampvisExternalDllsRelease false) COPY_EXTERNAL_DLLS(CampvisExternalDllsDebug CampvisExternalDllsRelease false)
ENDIF() ENDIF()
ENDIF() ENDIF()
......
PROJECT(campvis-application) PROJECT(campvis-application)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
INCLUDE(../cmake/commonconf.cmake) INCLUDE(../cmake/commonconf.cmake)
MESSAGE(STATUS "Configuring CAMPVis-Application") MESSAGE(STATUS "Configuring CAMPVis-Application")
...@@ -106,13 +105,7 @@ FOREACH(ModFile ${CampvisModulesApplicationToBeMocced}) ...@@ -106,13 +105,7 @@ FOREACH(ModFile ${CampvisModulesApplicationToBeMocced})
LIST(APPEND CampvisApplicationToBeMocced ${ModFileRelative}) LIST(APPEND CampvisApplicationToBeMocced ${ModFileRelative})
ENDFOREACH() ENDFOREACH()
# QT5_WRAP_UI(CampvisApplicationFormsHeaders ${CampvisApplicationForms})
# Qt related stuff:
#
QT4_WRAP_CPP(CampvisApplicationMoc ${CampvisApplicationToBeMocced})
LIST(APPEND CampvisApplicationSources ${CampvisApplicationMoc})
QT4_WRAP_UI(CampvisApplicationFormsHeaders ${CampvisApplicationForms})
LIST(APPEND CampvisApplicationSources ${CampvisApplicationFormsHeaders}) LIST(APPEND CampvisApplicationSources ${CampvisApplicationFormsHeaders})
LINK_DIRECTORIES(${CampvisGlobalLinkDirectories} ${CampvisModulesLinkDirectories}) LINK_DIRECTORIES(${CampvisGlobalLinkDirectories} ${CampvisModulesLinkDirectories})
...@@ -127,14 +120,15 @@ ADD_LIBRARY(campvis-application-lib ...@@ -127,14 +120,15 @@ ADD_LIBRARY(campvis-application-lib
${CampvisApplicationSources} ${CampvisApplicationHeaders} ${CampvisApplicationSources} ${CampvisApplicationHeaders}
${CampvisApplicationMoc} ${CampvisApplicationMoc}
) )
ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions} ${QT_DEFINITIONS}) ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions})
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs}) INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs})
TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES}) TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} Qt5::Widgets Qt5::OpenGL)
# if campvis-core is built as a shared library, CMake will define the following flag to instruct # if campvis-core is built as a shared library, CMake will define the following flag to instruct
# the code to export DLL symbols # the code to export DLL symbols
SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL") SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL")
IF(CAMPVIS_GROUP_SOURCE_FILES) IF(CAMPVIS_GROUP_SOURCE_FILES)
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "") DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "")
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationHeaders ${CampvisHome} "") DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationHeaders ${CampvisHome} "")
...@@ -144,9 +138,7 @@ INSTALL(TARGETS campvis-application-lib DESTINATION exports EXPORT campvis-targe ...@@ -144,9 +138,7 @@ INSTALL(TARGETS campvis-application-lib DESTINATION exports EXPORT campvis-targe
ADD_EXECUTABLE(campvis-application "campvis.cpp") ADD_EXECUTABLE(campvis-application "campvis.cpp")
TARGET_LINK_LIBRARIES(campvis-application campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES}) TARGET_LINK_LIBRARIES(campvis-application campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} Qt5::Widgets Qt5::OpenGL)
IF(CAMPVIS_DEPLOY_SHADERS) IF(CAMPVIS_DEPLOY_SHADERS)
LIST(APPEND CampvisShaderDirectories "application/data") LIST(APPEND CampvisShaderDirectories "application/data")
......
...@@ -46,12 +46,15 @@ ...@@ -46,12 +46,15 @@
#include "core/pipeline/abstractworkflow.h" #include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/pipelinefactory.h" #include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/pipelinepainter.h" #include "core/pipeline/pipelinepainter.h"
#include "core/pipeline/visualizationprocessor.h"
#include "core/datastructures/imagerepresentationconverter.h" #include "core/datastructures/imagerepresentationconverter.h"
#include "core/pipeline/visualizationprocessor.h" #include "core/pipeline/visualizationprocessor.h"
#include "tools/qtjobprocessor.h" #include "tools/qtjobprocessor.h"
#include <QApplication> #include <QApplication>
#include <QThread>
#include <QStyleFactory>
#ifdef CAMPVIS_HAS_SCRIPTING #ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h" #include "scripting/glue/luavmstate.h"
...@@ -93,12 +96,11 @@ namespace campvis { ...@@ -93,12 +96,11 @@ namespace campvis {
#endif #endif
} }
_localContext = new QtThreadedCanvas("", cgt::ivec2(16, 16)); _localContext = new cgt::QtThreadedCanvas("", cgt::ivec2(16, 16));
campvis::init(_localContext, searchPaths); campvis::init(_localContext, searchPaths);
_mainWindow = new MainWindow(this); _mainWindow = new MainWindow(this);
cgt::GLContextScopedLock lock(_localContext); GLJobProc.enqueueJobBlocking([&]() {
{
_mainWindow->init(); _mainWindow->init();
// load textureData from file // load textureData from file
...@@ -133,7 +135,7 @@ namespace campvis { ...@@ -133,7 +135,7 @@ namespace campvis {
if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application")) if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application"))
LERROR("Could not inject the pipeline into the Lua VM."); LERROR("Could not inject the pipeline into the Lua VM.");
#endif #endif
} });
// parse argument list and create pipelines // parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments(); QStringList pipelinesToAdd = this->arguments();
...@@ -171,6 +173,27 @@ namespace campvis { ...@@ -171,6 +173,27 @@ namespace campvis {
} }
} }
// Set Qt color palette to dark - adapted from https://gist.github.com/QuantumCD/6245215
QApplication::setStyle(QStyleFactory::create("Fusion"));
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor(53, 53, 53));
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, QColor(25, 25, 25));
darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, QColor(53, 53, 53));
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::BrightText, Qt::red);
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
setPalette(darkPalette);
setStyleSheet("QMainWindow * {font: 12pt;} QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
_initialized = true; _initialized = true;
} }
...@@ -185,10 +208,7 @@ namespace campvis { ...@@ -185,10 +208,7 @@ namespace campvis {
for (auto it = _workflows.begin(); it != _workflows.end(); ++it) for (auto it = _workflows.begin(); it != _workflows.end(); ++it)
(*it)->deinit(); (*it)->deinit();
{ GLJobProc.enqueueJobBlocking([&]() {
// Deinit everything OpenGL related using the local context.
cgt::GLContextScopedLock lock(_localContext);
delete _errorTexture; delete _errorTexture;
// Deinit pipeline and painter first // Deinit pipeline and painter first
...@@ -197,7 +217,9 @@ namespace campvis { ...@@ -197,7 +217,9 @@ namespace campvis {
} }
_mainWindow->deinit(); _mainWindow->deinit();
} });
delete _mainWindow;
// now delete everything in the right order: // now delete everything in the right order:
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) { for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
...@@ -254,8 +276,10 @@ namespace campvis { ...@@ -254,8 +276,10 @@ namespace campvis {
#endif #endif
GLCtxtMgr.releaseContext(canvas, false); GLCtxtMgr.releaseContext(canvas, false);
s_PipelinesChanged.emitSignal(); s_PipelinesChanged.emitSignal();
pipeline->start();
startOpenGlThreadAndMoveQtThreadAffinity(pipeline, canvas);
} }
void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) { void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) {
...@@ -286,7 +310,7 @@ namespace campvis { ...@@ -286,7 +310,7 @@ namespace campvis {
void CampVisApplication::rebuildAllShadersFromFiles() { void CampVisApplication::rebuildAllShadersFromFiles() {
// rebuilding all shaders has to be done from OpenGL context, use the local one. // rebuilding all shaders has to be done from OpenGL context, use the local one.
GLJobProc.enqueueJob(makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild)); GLJobProc.enqueueJob(cgt::makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild));
} }
void CampVisApplication::triggerShaderRebuild() { void CampVisApplication::triggerShaderRebuild() {
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
namespace cgt { namespace cgt {
class GLCanvas; class GLCanvas;
class QtCanvas;
class QtThreadedCanvas; class QtThreadedCanvas;
class Texture; class Texture;
} }
...@@ -170,7 +171,7 @@ namespace campvis { ...@@ -170,7 +171,7 @@ namespace campvis {
void triggerShaderRebuild(); void triggerShaderRebuild();
/// A local OpenGL context used for initialization /// A local OpenGL context used for initialization
cgt::GLCanvas* _localContext; cgt::QtCanvas* _localContext;
/// Main window hosting GUI stuff /// Main window hosting GUI stuff
MainWindow* _mainWindow; MainWindow* _mainWindow;
......
...@@ -101,12 +101,17 @@ void main() { ...@@ -101,12 +101,17 @@ void main() {
if (! _renderRChannel) if (! _renderRChannel)
out_Color.r = 0.0; out_Color.r = 0.0;
if (! _renderGChannel) if (! _renderGChannel)
out_Color.g = 0.0; out_Color.g = 0.0;
if (! _renderBChannel) if (! _renderBChannel)
out_Color.b = 0.0; out_Color.b = 0.0;
if (! _renderAChannel) if (! _renderAChannel)
out_Color.a = 1.0; out_Color.a = 1.0;
else if(! _renderRChannel && ! _renderGChannel && ! _renderBChannel)
out_Color = vec4(vec3((abs(out_Color.a) - vec3(_transferFunctionParams._intensityDomain.x)) / (_transferFunctionParams._intensityDomain.y - _transferFunctionParams._intensityDomain.x)), 1);
// mix with fancy checkerboard pattern: // mix with fancy checkerboard pattern:
if ((mod(ex_TexCoord.x * 10.0, 2.0) > 1.0) ^^ (mod(ex_TexCoord.y * 10.0, 2.0) > 1.0)) if ((mod(ex_TexCoord.x * 10.0, 2.0) > 1.0) ^^ (mod(ex_TexCoord.y * 10.0, 2.0) > 1.0))
......
...@@ -45,6 +45,9 @@ namespace campvis { ...@@ -45,6 +45,9 @@ namespace campvis {
} }
DataContainerFileLoaderWidget::~DataContainerFileLoaderWidget() { DataContainerFileLoaderWidget::~DataContainerFileLoaderWidget() {
delete _imgReader;
_imgReader = nullptr;
if (_dataContainer != 0) { if (_dataContainer != 0) {
_dataContainer->s_dataAdded.disconnect(this); _dataContainer->s_dataAdded.disconnect(this);
} }
...@@ -97,14 +100,6 @@ namespace campvis { ...@@ -97,14 +100,6 @@ namespace campvis {
return false; return false;
} }
void DataContainerFileLoaderWidget::init() {
}
void DataContainerFileLoaderWidget::deinit() {
delete _imgReader;
_imgReader = nullptr;
}
void DataContainerFileLoaderWidget::onBtnCancelClicked() { void DataContainerFileLoaderWidget::onBtnCancelClicked() {
delete _imgReader; delete _imgReader;
_imgReader = nullptr; _imgReader = nullptr;
......
...@@ -67,17 +67,6 @@ namespace campvis { ...@@ -67,17 +67,6 @@ namespace campvis {
*/ */
QSize sizeHint() const; QSize sizeHint() const;
/**
* Initializes the OpenGL stuff (e.g. shaders).
* Must be called with a valid and locked OpenGL context.
*/
virtual void init();
/**
* Deinitializes the OpenGL stuff (e.g. shaders).
* Must be called with a valid and locked OpenGL context.
*/
void deinit();
private slots: private slots:
/** /**
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "ext/cgt/navigation/trackball.h" #include "ext/cgt/navigation/trackball.h"
#include <QWindow>
namespace campvis { namespace campvis {
...@@ -70,7 +71,6 @@ namespace campvis { ...@@ -70,7 +71,6 @@ namespace campvis {
static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(cgt::vec2(0.f, 1.f), cgt::col4(0, 0, 0, 255), cgt::col4(255, 255, 255, 255))); static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(cgt::vec2(0.f, 1.f), cgt::col4(0, 0, 0, 255), cgt::col4(255, 255, 255, 255)));
GLCtxtMgr.registerContextAndInitGlew(this, "DataContainerInspector"); GLCtxtMgr.registerContextAndInitGlew(this, "DataContainerInspector");
GLCtxtMgr.releaseContext(this, false);
addProperty(p_currentSlice); addProperty(p_currentSlice);
addProperty(p_transferFunction); addProperty(p_transferFunction);
...@@ -103,10 +103,13 @@ namespace campvis { ...@@ -103,10 +103,13 @@ namespace campvis {
p_renderGChannel.setVisible(false); p_renderGChannel.setVisible(false);
p_renderBChannel.setVisible(false); p_renderBChannel.setVisible(false);
p_renderAChannel.setVisible(false); p_renderAChannel.setVisible(false);
connect(this, &DataContainerInspectorCanvas::s_invalidated, this, &DataContainerInspectorCanvas::onInvalidated);
init();
} }
DataContainerInspectorCanvas::~DataContainerInspectorCanvas() { DataContainerInspectorCanvas::~DataContainerInspectorCanvas() {
} }
void DataContainerInspectorCanvas::init() { void DataContainerInspectorCanvas::init() {
...@@ -120,6 +123,7 @@ namespace campvis { ...@@ -120,6 +123,7 @@ namespace campvis {
getEventHandler()->addEventListenerToFront(this); getEventHandler()->addEventListenerToFront(this);
_geometryRenderer.init(); _geometryRenderer.init();
_tcp.init();
} }
void DataContainerInspectorCanvas::deinit() { void DataContainerInspectorCanvas::deinit() {
...@@ -130,6 +134,7 @@ namespace campvis { ...@@ -130,6 +134,7 @@ namespace campvis {
} }
_geometryRenderer.deinit(); _geometryRenderer.deinit();
_tcp.deinit();
_handles.clear(); _handles.clear();
_localDataContainer.clear(); _localDataContainer.clear();
...@@ -157,16 +162,17 @@ namespace campvis { ...@@ -157,16 +162,17 @@ namespace campvis {
_geometriesDirty = false; _geometriesDirty = false;
} }
if (_textures.empty()) {
return;
}
glPushAttrib(GL_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS);
glViewport(0, 0, size_.x, size_.y); glViewport(0, 0, size_.x, size_.y);
glClearColor(0.7f, 0.7f, 0.7f, 1.f); glClearColor(0.7f, 0.7f, 0.7f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
LGL_ERROR; LGL_ERROR;
if (_textures.empty()) {
glPopAttrib();
return;
}
// update layout dimensions // update layout dimensions
_numTiles.x = ceil(sqrt(static_cast<float>(_textures.size()))); _numTiles.x = ceil(sqrt(static_cast<float>(_textures.size())));
_numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x); _numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x);
...@@ -194,8 +200,8 @@ namespace campvis { ...@@ -194,8 +200,8 @@ namespace campvis {
break; break;
// gather image // gather image
cgtAssert(dynamic_cast<const ImageData*>(_textures[index].getData()), "Found sth. else than ImageData in render texture vector. This should not happen!"); cgtAssert(_textures[index].getData<ImageData>(), "Found sth. else than ImageData in render texture vector. This should not happen!");
const ImageData* id = static_cast<const ImageData*>(_textures[index].getData()); auto id = _textures[index].getData<ImageData>();
// compute transformation matrices // compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y); float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
...@@ -249,16 +255,26 @@ namespace campvis { ...@@ -249,16 +255,26 @@ namespace campvis {
LGL_ERROR; LGL_ERROR;
} }
void DataContainerInspectorCanvas::invalidate() { void DataContainerInspectorCanvas::onInvalidated() {
// Prevent drawing when the window is not yet exposed to the window manager
QWindow* wnd = dynamic_cast<QWindow*>(window()->windowHandle());
if (!wnd || !wnd->isExposed()) return;
// only if inited // only if inited
if (_quad != 0 && _paintShader != 0) { if (_quad != 0 && _paintShader != 0 && this->isVisible()) {
// avoid recursive paints.
if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) { this->makeCurrent();
SimpleJobProc.enqueueJob([this] () {
cgt::GLContextScopedLock lock(this);
paint(); paint();
}); this->swap();
} // avoid recursive paints.
// if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) {
// SimpleJobProc.enqueueJob(
// [this] () {
// cgt::GLContextScopedLock lock(this);
// paint();
// });
// }
} }
} }
...@@ -267,11 +283,11 @@ namespace campvis { ...@@ -267,11 +283,11 @@ namespace campvis {
} }
void DataContainerInspectorCanvas::repaint() { void DataContainerInspectorCanvas::repaint() {
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::sizeChanged(const cgt::ivec2& size) { void DataContainerInspectorCanvas::sizeChanged(const cgt::ivec2& size) {
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::mouseMoveEvent(cgt::MouseEvent* e) void DataContainerInspectorCanvas::mouseMoveEvent(cgt::MouseEvent* e)
...@@ -281,7 +297,7 @@ namespace campvis { ...@@ -281,7 +297,7 @@ namespace campvis {
if (texIndx < 0 || texIndx >= static_cast<int>(_textures.size())) if (texIndx < 0 || texIndx >= static_cast<int>(_textures.size()))
return; return;
const ImageData* id = static_cast<const ImageData*>(_textures[texIndx].getData()); auto id = _textures[texIndx].getData<ImageData>();
const cgt::Texture* tex = id->getRepresentation<ImageRepresentationGL>()->getTexture(); const cgt::Texture* tex = id->getRepresentation<ImageRepresentationGL>()->getTexture();
const ImageRepresentationLocal* localRep = id->getRepresentation<ImageRepresentationLocal>(); const ImageRepresentationLocal* localRep = id->getRepresentation<ImageRepresentationLocal>();
cgt::svec2 imageSize = id->getSize().xy(); cgt::svec2 imageSize = id->getSize().xy();
...@@ -297,7 +313,7 @@ namespace campvis { ...@@ -297,7 +313,7 @@ namespace campvis {
lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f); lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f);
cgt::svec3 lookupTexel(lookupTexelFloat.x, imageSize.y - lookupTexelFloat.y, 0); cgt::svec3 lookupTexel(lookupTexelFloat.x, imageSize.y - lookupTexelFloat.y, 0);
if (lookupTexel.x >= 0 && lookupTexel.y >= 0 && lookupTexel.x < imageSize.x && lookupTexel.y < imageSize.y) { if (lookupTexel.x < imageSize.x && lookupTexel.y < imageSize.y) {
if (tex->isDepthTexture()) { if (tex->isDepthTexture()) {
emit s_depthChanged(lookupTexel, localRep->getElementNormalized(lookupTexel, 0)); emit s_depthChanged(lookupTexel, localRep->getElementNormalized(lookupTexel, 0));
} }
...@@ -335,7 +351,7 @@ namespace campvis { ...@@ -335,7 +351,7 @@ namespace campvis {
_tcp.process(_localDataContainer); _tcp.process(_localDataContainer);
e->accept(); e->accept();
_geometriesDirty = true; _geometriesDirty = true;
invalidate(); emit s_invalidated();
} }
} }
...@@ -357,7 +373,7 @@ namespace campvis { ...@@ -357,7 +373,7 @@ namespace campvis {
} }
if (_texturesDirty) if (_texturesDirty)
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::setDataHandles(const std::vector< std::pair<QString, QtDataHandle> >& handles) { void DataContainerInspectorCanvas::setDataHandles(const std::vector< std::pair<QString, QtDataHandle> >& handles) {
...@@ -384,7 +400,7 @@ namespace campvis { ...@@ -384,7 +400,7 @@ namespace campvis {
_texturesDirty = true; _texturesDirty = true;
} }
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::updateTextures() { void DataContainerInspectorCanvas::updateTextures() {
...@@ -394,13 +410,13 @@ namespace campvis { ...@@ -394,13 +410,13 @@ namespace campvis {
p_viewportSize.setValue(cgt::ivec2(width(), height())); p_viewportSize.setValue(cgt::ivec2(width(), height()));
for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) { for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
if (const ImageData* img = dynamic_cast<const ImageData*>(it->second.getData())) { if (auto img = it->second.getData<ImageData>()) {
if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) { if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) {
_textures.push_back(it->second); _textures.push_back(it->second);
maxSlices = std::max(maxSlices, imgGL->getTexture()->getDimensions().z); maxSlices = std::max(maxSlices, imgGL->getTexture()->getDimensions().z);
} }
} }
else if (const RenderData* rd = dynamic_cast<const RenderData*>(it->second.getData())) { else if (auto rd = it->second.getData<RenderData>()) {
for (size_t i = 0; i < rd->getNumColorTextures(); ++i) { for (size_t i = 0; i < rd->getNumColorTextures(); ++i) {
const ImageRepresentationGL* imgGL = rd->getColorTexture(i)->getRepresentation<ImageRepresentationGL>(); const ImageRepresentationGL* imgGL = rd->getColorTexture(i)->getRepresentation<ImageRepresentationGL>();
if (imgGL) { if (imgGL) {
...@@ -415,7 +431,7 @@ namespace campvis { ...@@ -415,7 +431,7 @@ namespace campvis {
} }
} }
else if (const GeometryData* gd = dynamic_cast<const GeometryData*>(it->second.getData())) { else if (auto gd = it->second.getData<GeometryData>()) {
std::string name = it->first.toStdString(); std::string name = it->first.toStdString();
// copy geometry over to local // copy geometry over to local
...@@ -440,12 +456,12 @@ namespace campvis { ...@@ -440,12 +456,12 @@ namespace campvis {
void DataContainerInspectorCanvas::onPropertyChanged(const AbstractProperty* prop) { void DataContainerInspectorCanvas::onPropertyChanged(const AbstractProperty* prop) {
// ignore properties of the geometry renderer // ignore properties of the geometry renderer
if (prop != &p_geometryRendererProperties) if (prop != &p_geometryRendererProperties)
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::onGeometryRendererPropertyChanged(const AbstractProperty* prop) { void DataContainerInspectorCanvas::onGeometryRendererPropertyChanged(const AbstractProperty* prop) {
_geometriesDirty = true; _geometriesDirty = true;
invalidate(); emit s_invalidated();
} }
void DataContainerInspectorCanvas::renderGeometryIntoTexture(const std::string& name, int textureIndex) { void DataContainerInspectorCanvas::renderGeometryIntoTexture(const std::string& name, int textureIndex) {
...@@ -481,7 +497,7 @@ namespace campvis { ...@@ -481,7 +497,7 @@ namespace campvis {
// check whether we have to render geometries // check whether we have to render geometries
cgt::Bounds unionBounds; cgt::Bounds unionBounds;
for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) { for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
if (const GeometryData* gd = dynamic_cast<const GeometryData*>(it->second.getData())) { if (auto gd = it->second.getData<GeometryData>()) {
unionBounds.addVolume(gd->getWorldBounds()); unionBounds.addVolume(gd->getWorldBounds());
} }
} }
......
...@@ -131,6 +131,7 @@ namespace campvis { ...@@ -131,6 +131,7 @@ namespace campvis {
signals: signals:
void s_colorChanged(const cgt::svec3& texel, const cgt::vec4&); void s_colorChanged(const cgt::svec3& texel, const cgt::vec4&);
void s_depthChanged(const cgt::svec3& texel, float depth); void s_depthChanged(const cgt::svec3& texel, float depth);
void s_invalidated(); ///< signals an invalidation event
private slots: private slots:
/** /**
...@@ -140,19 +141,16 @@ namespace campvis { ...@@ -140,19 +141,16 @@ namespace campvis {
*/ */
void onDataContainerChanged(const QString& key, QtDataHandle dh); void onDataContainerChanged(const QString& key, QtDataHandle dh);
protected:
/** /**
* Performs the painting. * To be called when the canvas is invalidated, issues new paint job.
*/ */
virtual void paint(); void onInvalidated();
protected:
/** /**
* Gets called when the data collection of this pipeline has changed and thus has notified its observers. * Performs the painting.
* If \a name equals the name of the renderTarget, the s_renderTargetChanged signal will be emitted.
* \param name Name of the added data.
* \param dh DataHandle to the newly added data.
*/ */
void onDataContainerDataAdded(const std::string& name, DataHandle dh); virtual void paint();
/** /**
* Slot getting called when one of the observed properties changed and notifies its observers. * Slot getting called when one of the observed properties changed and notifies its observers.
...@@ -172,11 +170,6 @@ namespace campvis { ...@@ -172,11 +170,6 @@ namespace campvis {
*/ */
void resetTrackball(); void resetTrackball();
/**
* To be called when the canvas is invalidated, issues new paint job.
*/
void invalidate();
/** /**
* Renders the given 2D texture. * Renders the given 2D texture.
* Binds the texture to the shader, sets the uniforms and renders the quad. * Binds the texture to the shader, sets the uniforms and renders the quad.
......
...@@ -89,10 +89,6 @@ namespace campvis { ...@@ -89,10 +89,6 @@ namespace campvis {
} }
DataContainerInspectorWidget::~DataContainerInspectorWidget() { DataContainerInspectorWidget::~DataContainerInspectorWidget() {
if (_dataContainer != 0) {
_dataContainer->s_dataAdded.disconnect(this);
}
delete _pcWidget; delete _pcWidget;
_pcWidget = nullptr; _pcWidget = nullptr;
} }
...@@ -260,7 +256,7 @@ namespace campvis { ...@@ -260,7 +256,7 @@ namespace campvis {
QModelIndex idxName = index->sibling(index->row(), 0); QModelIndex idxName = index->sibling(index->row(), 0);
// only consider non-empty DataHandles // only consider non-empty DataHandles
if (handle.getData() != 0) { if (handle) {
handles.push_back(std::make_pair(idxName.data(Qt::DisplayRole).toString(), handle)); handles.push_back(std::make_pair(idxName.data(Qt::DisplayRole).toString(), handle));
_localFootprint += handle.getData()->getLocalMemoryFootprint(); _localFootprint += handle.getData()->getLocalMemoryFootprint();
_videoFootprint += handle.getData()->getVideoMemoryFootprint(); _videoFootprint += handle.getData()->getVideoMemoryFootprint();
...@@ -272,7 +268,7 @@ namespace campvis { ...@@ -272,7 +268,7 @@ namespace campvis {
_lblName->setText("Name: " + handles.front().first); _lblName->setText("Name: " + handles.front().first);
_lblTimestamp->setText("Timestamp: " + QString::number(handles.front().second.getTimestamp())); _lblTimestamp->setText("Timestamp: " + QString::number(handles.front().second.getTimestamp()));
if (const ImageData* tester = dynamic_cast<const ImageData*>(handles.front().second.getData())) { if (auto tester = handles.front().second.getData<ImageData>()) {
_canvas->p_transferFunction.setImageHandle(handles.front().second); _canvas->p_transferFunction.setImageHandle(handles.front().second);
_lblNumChannels->setText(tr("Number of Channels: ") + QString::number(tester->getNumChannels())); _lblNumChannels->setText(tr("Number of Channels: ") + QString::number(tester->getNumChannels()));
...@@ -294,7 +290,7 @@ namespace campvis { ...@@ -294,7 +290,7 @@ namespace campvis {
_canvas->p_renderAChannel.setVisible(true); _canvas->p_renderAChannel.setVisible(true);
_canvas->p_geometryRendererProperties.setVisible(false); _canvas->p_geometryRendererProperties.setVisible(false);
} }
else if (const GeometryData* tester = dynamic_cast<const GeometryData*>(handles.front().second.getData())) { else if (auto tester = handles.front().second.getData<GeometryData>()) {
_lblSize->setText(tr("Size: n/a")); _lblSize->setText(tr("Size: n/a"));
_lblNumChannels->setText(tr("Number of Channels: n/a")); _lblNumChannels->setText(tr("Number of Channels: n/a"));
...@@ -310,7 +306,7 @@ namespace campvis { ...@@ -310,7 +306,7 @@ namespace campvis {
_canvas->p_renderAChannel.setVisible(false); _canvas->p_renderAChannel.setVisible(false);
_canvas->p_geometryRendererProperties.setVisible(true); _canvas->p_geometryRendererProperties.setVisible(true);
} }
else if (const RenderData* tester = dynamic_cast<const RenderData*>(handles.front().second.getData())) { else if (auto tester = handles.front().second.getData<RenderData>()) {
const ImageData* id = tester->getNumColorTextures() > 0 ? tester->getColorTexture() : tester->getDepthTexture(); const ImageData* id = tester->getNumColorTextures() > 0 ? tester->getColorTexture() : tester->getDepthTexture();
if (id != 0) { if (id != 0) {
_lblNumChannels->setText(tr("Number of Channels: ") + QString::number(id->getNumChannels())); _lblNumChannels->setText(tr("Number of Channels: ") + QString::number(id->getNumChannels()));
...@@ -386,28 +382,17 @@ namespace campvis { ...@@ -386,28 +382,17 @@ namespace campvis {
} }
void DataContainerInspectorWidget::init() { void DataContainerInspectorWidget::init() {
if (_canvas != 0)
_canvas->init();
_inited = true; _inited = true;
} }
void DataContainerInspectorWidget::deinit() { void DataContainerInspectorWidget::deinit() {
_inited = false;
if (_canvas != 0)
_canvas->deinit(); _canvas->deinit();
_pcWidget->updatePropCollection(0, 0);
if (_dataContainer != 0) { if (_dataContainer != 0) {
_dataContainer->s_dataAdded.disconnect(this); _dataContainer->s_dataAdded.disconnect(this);
} }
_dataContainer = 0; _inited = false;
_dctWidget->update(0);
if(_propEditorWid != nullptr)
_propEditorWid->deinit();
} }
void DataContainerInspectorWidget::onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { void DataContainerInspectorWidget::onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
...@@ -445,7 +430,7 @@ namespace campvis { ...@@ -445,7 +430,7 @@ namespace campvis {
// only consider non-empty DataHandles that are ImageData and have render target representations // only consider non-empty DataHandles that are ImageData and have render target representations
if (handle.getData() != 0) { if (handle.getData() != 0) {
if (dynamic_cast<const ImageData*>(handle.getData()) && dynamic_cast<const ImageData*>(handle.getData())->getDimensionality() == 3) { if (handle.getData<ImageData>() && handle.getData<ImageData>()->getDimensionality() == 3) {
QString dialogCaption = "Export " + name + " as MHD Image"; QString dialogCaption = "Export " + name + " as MHD Image";
QString directory = tr(""); QString directory = tr("");
const QString fileFilter = tr("*.mhd;;MHD images (*.mhd)"); const QString fileFilter = tr("*.mhd;;MHD images (*.mhd)");
...@@ -453,15 +438,17 @@ namespace campvis { ...@@ -453,15 +438,17 @@ namespace campvis {
QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter); QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);
MhdImageWriter writer; MhdImageWriter writer;
writer.init();
writer.p_fileName.setValue(filename.toStdString()); writer.p_fileName.setValue(filename.toStdString());
writer.p_inputImage.setValue(name.toStdString()); writer.p_inputImage.setValue(name.toStdString());
writer.invalidate(AbstractProcessor::INVALID_RESULT); writer.invalidate(AbstractProcessor::INVALID_RESULT | AbstractProcessor::FIRST_FREE_TO_USE_INVALIDATION_LEVEL); // needed for the save action to actually execute
writer.process(*_dataContainer); writer.process(*_dataContainer);
writer.deinit();
} }
else if (dynamic_cast<const ImageData*>(handle.getData()) || dynamic_cast<const RenderData*>(handle.getData())) { else if (handle.getData<ImageData>() || handle.getData<RenderData>()) {
QString dialogCaption = "Export " + name + " as Image"; QString dialogCaption = "Export " + name + " as Image";
QString directory = tr(""); QString directory = tr("");
const QString fileFilter = tr("*.png;;PNG images (*.png)"); const QString fileFilter = tr("Image (*.png *.bmp *.jpg *.tif);;RAW Image (*.raw);;DirectDraw Surface (*.dds);;C-style header (*.h);;Radiance High Dynamic (*.hdr)");
QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter); QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);
...@@ -484,10 +471,10 @@ namespace campvis { ...@@ -484,10 +471,10 @@ namespace campvis {
// get the ImageData object (either directly or from the RenderData) // get the ImageData object (either directly or from the RenderData)
const ImageData* id = 0; const ImageData* id = 0;
if (const RenderData* tester = dynamic_cast<const RenderData*>(handle.getData())) { if (auto tester = handle.getData<RenderData>()) {
id = tester->getColorTexture(0); id = tester->getColorTexture(0);
} }
else if (const ImageData* tester = dynamic_cast<const ImageData*>(handle.getData())) { else if (auto tester = handle.getData<ImageData>()) {
id = tester; id = tester;
} }
else { else {
...@@ -518,10 +505,13 @@ namespace campvis { ...@@ -518,10 +505,13 @@ namespace campvis {
ilEnable(IL_FILE_OVERWRITE); ilEnable(IL_FILE_OVERWRITE);
ilResetWrite(); ilResetWrite();
ILboolean success = ilSaveImage(filename.c_str()); ILboolean success = ilSaveImage(filename.c_str());
ilDeleteImages(1, &img); ilDeleteImages(1, &img);
if (!success) { if (!success) {
LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Could not save image to file: " << ilGetError()); ILenum error = ilGetError();
LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Could not save image to file: " << error << ": " << iluErrorString(error));
} }
#else #else
return; return;
...@@ -533,7 +523,7 @@ namespace campvis { ...@@ -533,7 +523,7 @@ namespace campvis {
// delete previous PropertyEditor, then create a new one // delete previous PropertyEditor, then create a new one
// the final one will be deleted with deinit() // the final one will be deleted with deinit()
if (nullptr != _propEditorWid) if (nullptr != _propEditorWid)
_propEditorWid->deinit(); delete _propEditorWid;
_propEditorWid = new DataContainerFileLoaderWidget(this, nullptr); _propEditorWid = new DataContainerFileLoaderWidget(this, nullptr);
_propEditorWid->setVisible(true); _propEditorWid->setVisible(true);
......
...@@ -363,6 +363,7 @@ namespace campvis { ...@@ -363,6 +363,7 @@ namespace campvis {
void MainWindow::onBtnShowDataContainerInspectorClicked() { void MainWindow::onBtnShowDataContainerInspectorClicked() {
if (_selectedPipeline != 0) { if (_selectedPipeline != 0) {
// if there is no existing inspector window, create one
if (_dcInspectorWindow == 0) { if (_dcInspectorWindow == 0) {
_dcInspectorWindow = _mdiArea->addWidget(_dcInspectorWidget); _dcInspectorWindow = _mdiArea->addWidget(_dcInspectorWidget);
_dcInspectorWindow->setWindowTitle(tr("Data Container Inspector")); _dcInspectorWindow->setWindowTitle(tr("Data Container Inspector"));
...@@ -371,6 +372,8 @@ namespace campvis { ...@@ -371,6 +372,8 @@ namespace campvis {
_dcInspectorWidget->setDataContainer(&(_selectedPipeline->getDataContainer())); _dcInspectorWidget->setDataContainer(&(_selectedPipeline->getDataContainer()));
_dcInspectorWindow->show(); _dcInspectorWindow->show();
_dcInspectorWindow->activateWindow(); _dcInspectorWindow->activateWindow();
//_dcInspectorWindow->detachDockedWindow();
} }
} }
...@@ -435,8 +438,6 @@ namespace campvis { ...@@ -435,8 +438,6 @@ namespace campvis {
} }
void MainWindow::onBtnProcessorFactoryClicked() { void MainWindow::onBtnProcessorFactoryClicked() {
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard;
std::string name = this->_cbProcessorFactory->currentText().toStdString(); std::string name = this->_cbProcessorFactory->currentText().toStdString();
if (_selectedPipeline == nullptr) if (_selectedPipeline == nullptr)
return; return;
...@@ -447,9 +448,11 @@ namespace campvis { ...@@ -447,9 +448,11 @@ namespace campvis {
if (p == nullptr) if (p == nullptr)
return; return;
GLJobProc.enqueueJobBlocking([&]() {
p->init(); p->init();
_selectedPipeline->addProcessor(p); });
_selectedPipeline->addProcessor(p);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines); emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
} }
...@@ -460,8 +463,9 @@ namespace campvis { ...@@ -460,8 +463,9 @@ namespace campvis {
void MainWindow::onLuaCommandExecuted(const QString& cmd) { void MainWindow::onLuaCommandExecuted(const QString& cmd) {
#ifdef CAMPVIS_HAS_SCRIPTING #ifdef CAMPVIS_HAS_SCRIPTING
if (_application->getLuaVmState() != nullptr) { if (_application->getLuaVmState() != nullptr) {
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard; GLJobProc.enqueueJobBlocking([&]() {
_application->getLuaVmState()->execString(cmd.toStdString()); _application->getLuaVmState()->execString(cmd.toStdString());
});
_application->getLuaVmState()->getGlobalTable()->updateValueMap(); _application->getLuaVmState()->getGlobalTable()->updateValueMap();
_scriptingConsoleWidget->_editCommand->setCompleter(new LuaCompleter(_application->getLuaVmState(), _scriptingConsoleWidget->_editCommand)); _scriptingConsoleWidget->_editCommand->setCompleter(new LuaCompleter(_application->getLuaVmState(), _scriptingConsoleWidget->_editCommand));
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#include "mdidockarea.h" #include "mdidockarea.h"
#include <QAction> #include <QAction>
#include <QLayout>
#include <QMainWindow>
#include <cgt/qt/qtcanvas.h>
namespace campvis { namespace campvis {
...@@ -36,14 +39,21 @@ namespace campvis { ...@@ -36,14 +39,21 @@ namespace campvis {
, _dockedWindow(0) , _dockedWindow(0)
, _floatingWindow(0) , _floatingWindow(0)
, _toggleViewAction(0) , _toggleViewAction(0)
, _widget(widget)
, _fullScreenWidget(0)
{ {
this->setWindowFlags(windowFlags); setWindowFlags(windowFlags);
_dockedWindow = this->newDockedWindow(widget); _dockedWindow = this->newDockedWindow(widget);
_toggleViewAction = new QAction(this); _toggleViewAction = new QAction(this);
_toggleViewAction->setCheckable(true); _toggleViewAction->setCheckable(true);
_toggleViewAction->setChecked(false); _toggleViewAction->setChecked(false);
this->connect(_toggleViewAction, SIGNAL(toggled(bool)), SLOT(toggleWindowVisibility(bool))); connect(_toggleViewAction, &QAction::toggled, this, &MdiDockableWindow::toggleWindowVisibility);
if (auto canvas = dynamic_cast<cgt::QtCanvas*>(widget)) {
connect(canvas, &cgt::QtCanvas::fullScreenChanged, this, &MdiDockableWindow::handleFullScreenChanged);
}
} }
void MdiDockableWindow::setWindowTitle(const QString& title) { void MdiDockableWindow::setWindowTitle(const QString& title) {
...@@ -67,6 +77,63 @@ namespace campvis { ...@@ -67,6 +77,63 @@ namespace campvis {
return _toggleViewAction; return _toggleViewAction;
} }
void MdiDockableWindow::detachDockedWindow()
{
if (!_dockedWindow) {
std::cerr << "ERROR: Tried to detach a window that is already floating!" << std::endl;
return;
}
QWidget* widget = _dockedWindow->widget();
_dockedWindow->stopWindowDrag();
_dockedWindow->setWidget(0);
_mdiArea->removeSubWindow(_dockedWindow);
_floatingWindow = new MdiFloatingWindow(widget, this);
_floatingWindow->setWindowTitle(this->windowTitle());
_dockedWindow->deleteLater();
_dockedWindow = 0;
_docked = false;
_floatingWindow->show();
_floatingWindow->activateWindow();
_floatingWindow->forceWindowDrag();
/*
* Connect signals last so that the floating window's initial move events are ignored.
* They mustn't be handled because they may contain outdated position information which
* could, in extreme cases, trigger immediate re-docking of the floating window,
* leading to all sorts of problems.
*/
this->connect(_floatingWindow, &MdiFloatingWindow::s_closed, this, &MdiDockableWindow::handleWindowClosing);
this->connect(_floatingWindow, &MdiFloatingWindow::s_positionChanged, this, &MdiDockableWindow::trackFloatingWindowPosition);
}
void MdiDockableWindow::attachFloatingWindow()
{
if (!_floatingWindow) {
std::cerr << "ERROR: Tried to attach a window that is already docked!" << std::endl;
return;
}
_floatingWindow->stopWindowDrag();
_floatingWindow->hide();
QWidget* widget = _floatingWindow->widget();
_dockedWindow = this->newDockedWindow(widget);
_dockedWindow->setWindowTitle(this->windowTitle());
_floatingWindow->deleteLater();
_floatingWindow = 0;
_docked = true;
_mdiArea->addSubWindow(_dockedWindow);
// Dragging the window doesn't make sense in tabbed mode
if (_mdiArea->viewMode() == QMdiArea::SubWindowView)
_dockedWindow->forceWindowDrag();
}
void MdiDockableWindow::setVisible(bool visible) { void MdiDockableWindow::setVisible(bool visible) {
_toggleViewAction->setChecked(visible); _toggleViewAction->setChecked(visible);
} }
...@@ -75,8 +142,8 @@ namespace campvis { ...@@ -75,8 +142,8 @@ namespace campvis {
MdiDockedWindow* dockedWindow = new MdiDockedWindow(_mdiArea, this->windowFlags()); MdiDockedWindow* dockedWindow = new MdiDockedWindow(_mdiArea, this->windowFlags());
dockedWindow->setWidget(widget); dockedWindow->setWidget(widget);
this->connect(dockedWindow, SIGNAL(s_positionChanged(const QPoint&)), SLOT(trackDockedWindowPosition(QPoint))); this->connect(dockedWindow, &MdiDockedWindow::s_positionChanged, this, &MdiDockableWindow::trackDockedWindowPosition);
this->connect(dockedWindow, SIGNAL(s_closed()), SLOT(handleWindowClosing())); this->connect(dockedWindow, &MdiDockedWindow::s_closed, this, &MdiDockableWindow::handleWindowClosing);
return dockedWindow; return dockedWindow;
} }
...@@ -110,21 +177,8 @@ namespace campvis { ...@@ -110,21 +177,8 @@ namespace campvis {
// Dock the floating window's widget if at least 60% of it is over the MDI area // Dock the floating window's widget if at least 60% of it is over the MDI area
if (widgetGeometry.width() * widgetGeometry.height() * 3 < if (widgetGeometry.width() * widgetGeometry.height() * 3 <
intersection.width() * intersection.height() * 5) { intersection.width() * intersection.height() * 5) {
_floatingWindow->stopWindowDrag(); attachFloatingWindow();
_floatingWindow->hide();
QWidget* widget = _floatingWindow->widget();
_dockedWindow = this->newDockedWindow(widget);
_dockedWindow->setWindowTitle(this->windowTitle());
_floatingWindow->deleteLater();
_floatingWindow = 0;
_docked = true;
_mdiArea->addSubWindow(_dockedWindow);
// Dragging the window doesn't make sense in tabbed mode
if (_mdiArea->viewMode() == QMdiArea::SubWindowView)
_dockedWindow->forceWindowDrag();
} }
} }
...@@ -136,32 +190,36 @@ namespace campvis { ...@@ -136,32 +190,36 @@ namespace campvis {
// Detach the docked window's widget if at least 60% of it has left the MDI area // Detach the docked window's widget if at least 60% of it has left the MDI area
if (subWindowGeometry.width() * subWindowGeometry.height() * 2 > if (subWindowGeometry.width() * subWindowGeometry.height() * 2 >
intersection.width() * intersection.height() * 5) { intersection.width() * intersection.height() * 5) {
QWidget* widget = _dockedWindow->widget(); detachDockedWindow();
_dockedWindow->stopWindowDrag(); }
_dockedWindow->setWidget(0); }
_mdiArea->removeSubWindow(_dockedWindow);
_floatingWindow = new MdiFloatingWindow(widget, this);
_floatingWindow->setWindowTitle(this->windowTitle());
_dockedWindow->deleteLater();
_dockedWindow = 0;
_docked = false;
_floatingWindow->show(); void MdiDockableWindow::handleFullScreenChanged(bool fullscreen) {
_floatingWindow->activateWindow(); if (_docked && _dockedWindow) {
_floatingWindow->forceWindowDrag(); if (fullscreen) {
_fullScreenWidget = new QMainWindow();
_fullScreenWidget->setCentralWidget(_widget);
_fullScreenWidget->showFullScreen();
}
else {
if (_dockedWindow->layout()) {
_dockedWindow->layout()->addWidget(_widget);
}
else {
setParent(_dockedWindow);
}
delete _fullScreenWidget;
_fullScreenWidget = nullptr;
}
}
/* if (!_docked && _floatingWindow) {
* Connect signals last so that the floating window's initial move events are ignored. if (fullscreen)
* They mustn't be handled because they may contain outdated position information which _floatingWindow->showFullScreen();
* could, in extreme cases, trigger immediate re-docking of the floating window, else
* leading to all sorts of problems. _floatingWindow->showNormal();
*/
this->connect(_floatingWindow, SIGNAL(s_closed()), SLOT(handleWindowClosing()));
this->connect(_floatingWindow, SIGNAL(s_positionChanged(const QPoint&)),
SLOT(trackFloatingWindowPosition(const QPoint&)));
} }
} }
} }
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "application/gui/qtcolortools.h" #include "application/gui/qtcolortools.h"
#include <QWidget> #include <QWidget>
class QMainWindow;
namespace campvis { namespace campvis {
class MdiDockArea; class MdiDockArea;
...@@ -84,6 +86,16 @@ namespace campvis { ...@@ -84,6 +86,16 @@ namespace campvis {
*/ */
QAction* toggleViewAction() const; QAction* toggleViewAction() const;
/**
* Attaches the window to the MDI area if it is floating.
*/
void attachFloatingWindow();
/**
* Detaches the window to float freely if it is docked.
*/
void detachDockedWindow();
private slots: private slots:
/** /**
* Track the position of the associated floating MDI window and dock it if necessary. * Track the position of the associated floating MDI window and dock it if necessary.
...@@ -92,6 +104,7 @@ namespace campvis { ...@@ -92,6 +104,7 @@ namespace campvis {
*/ */
void trackFloatingWindowPosition(const QPoint& newPos); void trackFloatingWindowPosition(const QPoint& newPos);
/** /**
* Track the position of the associated docked MDI window and detach it if necessary. * Track the position of the associated docked MDI window and detach it if necessary.
* *
...@@ -111,6 +124,11 @@ namespace campvis { ...@@ -111,6 +124,11 @@ namespace campvis {
*/ */
void handleWindowClosing(); void handleWindowClosing();
/**
* Handle changing fullscreen state requested by the QtCanvas widget
*/
void handleFullScreenChanged(bool fullscreen);
private: private:
/** /**
* Create and return an MdiDockedWindow wrapping the \p widget. * Create and return an MdiDockedWindow wrapping the \p widget.
...@@ -124,7 +142,8 @@ namespace campvis { ...@@ -124,7 +142,8 @@ namespace campvis {
MdiDockedWindow* _dockedWindow; ///< The window's docked representation. MdiDockedWindow* _dockedWindow; ///< The window's docked representation.
MdiFloatingWindow* _floatingWindow; ///< The window's floating representation. MdiFloatingWindow* _floatingWindow; ///< The window's floating representation.
QAction* _toggleViewAction; ///< A checkable action that can be used to show or hide this window. QAction* _toggleViewAction; ///< A checkable action that can be used to show or hide this window.
QWidget* _widget; ///< Widget that was wrapped
QMainWindow* _fullScreenWidget; ///< Container widget used to display docked canvas in fullscreen
}; };
} }
......
...@@ -133,7 +133,7 @@ namespace campvis { ...@@ -133,7 +133,7 @@ namespace campvis {
switch (role) { switch (role) {
case Qt::DisplayRole: case Qt::DisplayRole:
if (column == COLUMN_NAME) if (column == COLUMN_NAME)
return QVariant(QString::fromStdString(_processor->getName())); return QVariant(QString::fromStdString(_processor->getInstanceName()));
else else
return QVariant(); return QVariant();
case Qt::CheckStateRole: case Qt::CheckStateRole:
...@@ -146,7 +146,7 @@ namespace campvis { ...@@ -146,7 +146,7 @@ namespace campvis {
case Qt::UserRole: case Qt::UserRole:
return qVariantFromValue(static_cast<void*>(_processor)); return qVariantFromValue(static_cast<void*>(_processor));
case Qt::ToolTipRole: case Qt::ToolTipRole:
return QVariant(QString::fromStdString(_processor->getDescription())); return QVariant(QString("<b><u>%1</u></b><br/>\n%2").arg(QString::fromStdString(_processor->getName())).arg(QString::fromStdString(_processor->getDescription())));
default: default:
return QVariant(); return QVariant();
} }
......
...@@ -30,24 +30,49 @@ ...@@ -30,24 +30,49 @@
namespace campvis { namespace campvis {
AbstractPropertyWidget::AbstractPropertyWidget(AbstractProperty* property, bool displayBoxed /*= false*/, AbstractPropertyWidget::AbstractPropertyWidget(AbstractProperty* property, bool displayBoxed /*= false*/,
DataContainer* dataContainer /*= nullptr*/, QWidget* parent /*= 0*/) DataContainer* dataContainer /*= nullptr*/, QWidget* parent /*= 0*/, bool boxCheckable /*= false*/)
: QWidget(parent) : QWidget(parent)
, _property(property) , _property(property)
, _dataContainer(dataContainer) , _dataContainer(dataContainer)
, _layout(0) , _groupBox(nullptr)
, _groupBoxInner(nullptr)
, _ignorePropertyUpdates(false)
, _layout(nullptr)
, _titleLabel(nullptr)
{ {
_ignorePropertyUpdates = 0; _ignorePropertyUpdates = 0;
if (displayBoxed) { if (displayBoxed) {
// For the boxed case, we have the following qt object tree:
// [ this ]
// -- [ outerLayout ] to hold and stretch the group box
// --[ groupBox ] to get the title, border and checkbox
// -- [ innerLayout ]
// -- [ _groupBoxInner ] to show and hide all widgets at once
// -- [ _layout ]
// -- PropertyWidget 1
// -- PropertyWidget 2
// ...
QBoxLayout* outerLayout = new QBoxLayout(QBoxLayout::LeftToRight, this); QBoxLayout* outerLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
QGroupBox* groupBox = new QGroupBox(QString::fromStdString(_property->getTitle())); _groupBox = new QGroupBox(QString::fromStdString(_property->getTitle()));
outerLayout->setMargin(4); outerLayout->setMargin(4);
outerLayout->addWidget(groupBox); outerLayout->addWidget(_groupBox);
QBoxLayout* innerLayout = new QBoxLayout(QBoxLayout::LeftToRight, _groupBox);
_groupBoxInner = new QWidget();
innerLayout->addWidget(_groupBoxInner);
_layout = new QBoxLayout(QBoxLayout::TopToBottom, groupBox); _layout = new QBoxLayout(QBoxLayout::TopToBottom, _groupBoxInner);
_layout->setSpacing(1); _layout->setSpacing(1);
_layout->setMargin(3); _layout->setMargin(3);
if (boxCheckable) {
_groupBox->setCheckable(true);
_groupBox->setChecked(true);
connect(_groupBox, &QGroupBox::toggled, this, &AbstractPropertyWidget::onGroupBoxToggled);
}
} }
else { else {
_titleLabel = new QLabel(QString::fromStdString(_property->getTitle() + ":"), this); _titleLabel = new QLabel(QString::fromStdString(_property->getTitle() + ":"), this);
...@@ -59,14 +84,14 @@ namespace campvis { ...@@ -59,14 +84,14 @@ namespace campvis {
} }
_property->s_changed.connect(this, &AbstractPropertyWidget::onPropertyChanged); _property->s_changed.connect(this, &AbstractPropertyWidget::onPropertyChanged);
connect(this, SIGNAL(s_propertyChanged(const AbstractProperty*)), this, SLOT(updateWidgetFromProperty())); connect(this, &AbstractPropertyWidget::s_propertyChanged, this, &AbstractPropertyWidget::updateWidgetFromProperty);
} }
AbstractPropertyWidget::~AbstractPropertyWidget() { AbstractPropertyWidget::~AbstractPropertyWidget() {
_property->s_changed.disconnect(this); _property->s_changed.disconnect(this);
} }
void AbstractPropertyWidget::setLabelVisibile(bool isVisible) { void AbstractPropertyWidget::setLabelVisible(bool isVisible) {
if (_titleLabel) if (_titleLabel)
_titleLabel->setVisible(isVisible); _titleLabel->setVisible(isVisible);
} }
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <QLabel> #include <QLabel>
#include <QWidget> #include <QWidget>
class QGroupBox;
namespace campvis { namespace campvis {
class AbstractProperty; class AbstractProperty;
class DataContainer; class DataContainer;
...@@ -54,8 +56,10 @@ namespace campvis { ...@@ -54,8 +56,10 @@ namespace campvis {
* \param displayBoxed Should the widget be displayed in a group box? * \param displayBoxed Should the widget be displayed in a group box?
* \param dataContainer DataContainer to use (optional), defaults to nullptr. However, some derived classed might need a valid pointer here! * \param dataContainer DataContainer to use (optional), defaults to nullptr. However, some derived classed might need a valid pointer here!
* \param parent Parent Qt widget, defaults to nullptr. * \param parent Parent Qt widget, defaults to nullptr.
* \param boxCheckable If \a displayBoxed is true, indicates whether a checkbox should be displayed next to the name. If so,
* derived classes can re-implement the onGroupBoxToggled slot to get notified and react accordingly
*/ */
AbstractPropertyWidget(AbstractProperty* property, bool displayBoxed = false, DataContainer* dataContainer = nullptr, QWidget* parent = nullptr); AbstractPropertyWidget(AbstractProperty* property, bool displayBoxed = false, DataContainer* dataContainer = nullptr, QWidget* parent = nullptr, bool boxCheckable = false);
/** /**
* Destructor * Destructor
...@@ -65,9 +69,9 @@ namespace campvis { ...@@ -65,9 +69,9 @@ namespace campvis {
/** /**
* Shows or hides the label that appears on the left hand side of the widget. * Shows or hides the label that appears on the left hand side of the widget.
* *
* \param isVisible Wether the label should be shown or not * \param isVisible Whether the label should be shown or not
*/ */
void setLabelVisibile(bool isVisible); void setLabelVisible(bool isVisible);
protected: protected:
/** /**
...@@ -78,6 +82,9 @@ namespace campvis { ...@@ -78,6 +82,9 @@ namespace campvis {
AbstractProperty* _property; ///< The property this widget handles AbstractProperty* _property; ///< The property this widget handles
DataContainer* _dataContainer; ///< DataContainer to use (e.g. to populate GUI), may be 0! DataContainer* _dataContainer; ///< DataContainer to use (e.g. to populate GUI), may be 0!
QGroupBox *_groupBox; ///< The group box when \a displayBoxed was true in the constructor, otherwise this is a nullptr
QWidget *_groupBoxInner; ///< the content of the \a _groupBox
/// Semaphore acts as flag whether the widget shall ignore incoming signals from properties being updated. /// Semaphore acts as flag whether the widget shall ignore incoming signals from properties being updated.
tbb::atomic<int> _ignorePropertyUpdates; tbb::atomic<int> _ignorePropertyUpdates;
...@@ -87,6 +94,11 @@ namespace campvis { ...@@ -87,6 +94,11 @@ namespace campvis {
*/ */
virtual void updateWidgetFromProperty() {}; virtual void updateWidgetFromProperty() {};
/**
* Gets called when the widget is displayed boxed and the group checkbox has been clicked
*/
virtual void onGroupBoxToggled(bool on) {};
signals: signals:
/** /**
* Internal signal used to update the property widget in a thread-safe way. * Internal signal used to update the property widget in a thread-safe way.
......
...@@ -55,7 +55,7 @@ namespace campvis { ...@@ -55,7 +55,7 @@ namespace campvis {
/** /**
* Gets called when the property has changed, so that widget can update its state. * Gets called when the property has changed, so that widget can update its state.
*/ */
virtual void updateWidgetFromProperty(); virtual void updateWidgetFromProperty() override;
private slots: private slots:
void onStateChanged(int value); void onStateChanged(int value);
......
...@@ -31,7 +31,7 @@ namespace campvis { ...@@ -31,7 +31,7 @@ namespace campvis {
: AbstractPropertyWidget(property, false, dataContainer, parent) : AbstractPropertyWidget(property, false, dataContainer, parent)
, _button(0) , _button(0)
{ {
setLabelVisibile(false); setLabelVisible(false);
_button = new QPushButton(QString::fromStdString(property->getTitle()), this); _button = new QPushButton(QString::fromStdString(property->getTitle()), this);
connect(_button, SIGNAL(clicked(bool)), this, SLOT(onButtonClicked(bool))); connect(_button, SIGNAL(clicked(bool)), this, SLOT(onButtonClicked(bool)));
......