05.11., 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit d335d251 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge

Merge branch 'fancy-scripting' into 'development'

Fancy scripting

See merge request !118
parents 47f0f8c9 112c3559
[submodule "ext/lua"]
path = ext/lua
url = https://github.com/LuaDist/lua
ignore = dirty
# = CAMPVis - Yet another medical visualization framework =====================
PROJECT(CAMPVis)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0 FATAL_ERROR)
SET(CAMPVIS_VERSION 1.0.0)
......@@ -51,30 +51,15 @@ ENDIF()
# build scripting targets when enabled
IF(CAMPVIS_ENABLE_SCRIPTING)
# build Lua from source
IF(WIN32)
# Keep LUA_BUILD_AS_DLL in sync with BUILD_SHARED_LIBS
SET(LUA_BUILD_AS_DLL ${BUILD_SHARED_LIBS} CACHE BOOL "Build Lua library as DLL" FORCE)
ENDIF(WIN32)
ADD_SUBDIRECTORY(ext/lua EXCLUDE_FROM_ALL)
# If the above command failed, provide a hint how to fix the problem
IF(NOT TARGET liblua)
MESSAGE(SEND_ERROR "Did you forget to run `git submodule update --init`?")
ENDIF(NOT TARGET liblua)
ADD_SUBDIRECTORY(ext/lua)
SET(LUA_DIR "${CampvisHome}/ext/lua")
# First, find Lua to setup paths for all projects correctly
FIND_PACKAGE(Lua REQUIRED)
IF(LUA_FOUND)
MESSAGE(STATUS "* Found Lua")
LIST(APPEND CampvisGlobalDefinitions ${LUA_DEFINITIONS})
LIST(APPEND CampvisGlobalIncludeDirs ${LUA_INCLUDE_DIR})
LIST(APPEND CampvisGlobalExternalLibs ${LUA_LIBRARY})
ELSE(LUA_FOUND)
MESSAGE(FATAL_ERROR "Lua not found!")
ENDIF(LUA_FOUND)
LIST(APPEND CampvisGlobalIncludeDirs "${LUA_DIR}/src" "${CMAKE_BINARY_DIR}/ext/lua")
LIST(APPEND CampvisGlobalExternalLibs "liblua")
LIST(APPEND CampvisGlobalDefinitions "-DCAMPVIS_HAS_SCRIPTING")
ADD_SUBDIRECTORY(scripting)
LIST(APPEND CampvisGlobalDefinitions "-DCAMPVIS_HAS_SCRIPTING")
ENDIF()
IF(CAMPVIS_BUILD_APPLICATION)
......
......@@ -5,7 +5,7 @@ INCLUDE(../cmake/commonconf.cmake)
MESSAGE(STATUS "Configuring CAMPVis-Application")
FILE(GLOB CampvisApplicationSources
*.cpp
campvisapplication.cpp
gui/*.cpp
gui/adjusterwidgets/*.cpp
gui/mdi/*.cpp
......@@ -14,7 +14,8 @@ FILE(GLOB CampvisApplicationSources
)
FILE(GLOB CampvisApplicationHeaders
*.h
applicationapi.h
campvisapplication.h
glsl/*.frag
glsl/*.vert
gui/*.h
......@@ -28,6 +29,7 @@ FILE(GLOB CampvisApplicationForms
)
SET(CampvisApplicationToBeMocced
gui/completinglualineedit.h
gui/mainwindow.h
gui/datacontainerinspectorcanvas.h
gui/datacontainerinspectorwidget.h
......@@ -38,6 +40,7 @@ SET(CampvisApplicationToBeMocced
gui/qtdatahandle.h
gui/logviewerwidget.h
gui/loghighlighter.h
gui/luatablewidget.h
gui/scriptingwidget.h
gui/workflowcontrollerwidget.h
gui/mdi/mdidockarea.h
......@@ -64,8 +67,8 @@ SET(CampvisApplicationToBeMocced
gui/properties/statuspropertywidget.h
gui/properties/transferfunctionpropertywidget.h
tools/bufferinglog.h
tools/qtjobprocessor.h
tools/qtexteditlog.h
tools/qtjobprocessor.h
)
......@@ -103,19 +106,31 @@ IF(CAMPVIS_ENABLE_SCRIPTING)
LIST(APPEND CampvisMainLibs campvis-scripting)
ENDIF(CAMPVIS_ENABLE_SCRIPTING)
ADD_EXECUTABLE(campvis-application
ADD_LIBRARY(campvis-application-lib
${CampvisApplicationSources} ${CampvisApplicationHeaders}
${CampvisApplicationMoc}
)
ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions} ${QT_DEFINITIONS})
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs})
TARGET_LINK_LIBRARIES(campvis-application ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES})
TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES})
# if campvis-core is built as a shared library, CMake will define the following flag to instruct
# the code to export DLL symbols
SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL")
IF(CAMPVIS_GROUP_SOURCE_FILES)
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "")
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationHeaders ${CampvisHome} "")
ENDIF()
INSTALL(TARGETS campvis-application-lib DESTINATION exports EXPORT campvis-targets)
ADD_EXECUTABLE(campvis-application "campvis.cpp")
TARGET_LINK_LIBRARIES(campvis-application campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES})
IF(CAMPVIS_DEPLOY_SHADERS)
LIST(APPEND CampvisShaderDirectories "application/data")
LIST(APPEND CampvisShaderDirectories "application/glsl")
......
......@@ -2,7 +2,7 @@
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
......@@ -22,59 +22,28 @@
//
// ================================================================================================
#include "luapipeline.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
#include "glue/globalluatable.h"
#include "glue/luavmstate.h"
namespace campvis {
LuaPipeline::LuaPipeline(const std::string name, std::string scriptPath, DataContainer* dc)
: AutoEvaluationPipeline(dc)
, _name(name)
, _scriptPath(scriptPath)
, _luaVmState(new LuaVmState())
, _pipelineTable(_luaVmState->getGlobalTable()->getTable("pipeline"))
{
// Let Lua know where CAMPVis modules are located
if (!_luaVmState->execString("package.cpath = '" CAMPVIS_LUA_MODS_PATH "'"))
return;
// Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
if (!_luaVmState->execString("require(\"campvis\")"))
return;
// Make this pipeline object available to the script so that it can configure it
if (!_luaVmState->injectGlobalObjectPointer(this, "campvis::AutoEvaluationPipeline *", "instance"))
return;
// Try executing the pipeline's Lua script
if (!_luaVmState->execFile(scriptPath))
return;
if (!_pipelineTable->isValid())
std::cerr << "No valid Lua pipeline found (global variable `pipeline` is not a table)" << std::endl;
else
_pipelineTable->callInstanceMethod("ctor");
}
LuaPipeline::~LuaPipeline() {
}
void LuaPipeline::init() {
AutoEvaluationPipeline::init();
_pipelineTable->callInstanceMethod("init");
}
void LuaPipeline::deinit() {
AutoEvaluationPipeline::deinit();
_pipelineTable->callInstanceMethod("deinit");
}
}
#ifndef APPLICATIONAPI_H__
#define APPLICATIONAPI_H__
#ifdef CAMPVIS_DYNAMIC_LIBS
#ifdef CAMPVIS_APPLICATION_BUILD_DLL
// building library -> export symbols
#ifdef WIN32
#define CAMPVIS_APPLICATION_API __declspec(dllexport)
#else
#define CAMPVIS_APPLICATION_API
#endif
#else
// including library -> import symbols
#ifdef WIN32
#define CAMPVIS_APPLICATION_API __declspec(dllimport)
#else
#define CAMPVIS_APPLICATION_API
#endif
#endif
#else
// building/including static library -> do nothing
#define CAMPVIS_APPLICATION_API
#endif
#endif // APPLICATIONAPI_H__
%module application
%include factory.i
%include std_pair.i
%include std_string.i
%include std_vector.i
%import "core/bindings/campvis.i"
%{
#include "application/campvisapplication.h"
#include "core/properties/allproperties.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h"
%}
namespace campvis {
class CampVisApplication {
public:
CampVisApplication(int& argc, char** argv);
~CampVisApplication();
void init();
void deinit();
int run();
%apply SWIGTYPE *DISOWN {AbstractPipeline* pipeline};
void addPipeline(AbstractPipeline* pipeline);
DataContainer* createAndAddDataContainer(const std::string& name);
%clear AbstractPipeline* pipeline;
void rebuildAllShadersFromFiles();
void setPipelineVisibility(AbstractPipeline* pipeline, bool visibility);
/// Signal emitted when the collection of pipelines has changed.
sigslot::signal0 s_PipelinesChanged;
/// Signal emitted when the collection of DataContainers has changed.
sigslot::signal0 s_DataContainersChanged;
};
}
%luacode {
print("Module campvis-application loaded")
}
......@@ -49,12 +49,12 @@
#include "core/datastructures/imagerepresentationconverter.h"
#include "core/pipeline/visualizationprocessor.h"
#include "application/tools/qtjobprocessor.h"
#include "tools/qtjobprocessor.h"
#include <QApplication>
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/gen_pipelineregistration.h"
#include "scripting/glue/luavmstate.h"
#endif
namespace campvis {
......@@ -115,9 +115,11 @@ namespace campvis {
LERROR("Error setting up Lua VM.");
// Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
if (! _luaVmState->execString("require(\"cgt\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("require(\"campvis\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("require(\"cgt\")"))
if (! _luaVmState->execString("require(\"application\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("pipelines = {}"))
......@@ -125,6 +127,9 @@ namespace campvis {
if (! _luaVmState->execString("inspect = require 'inspect'"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application"))
LERROR("Could not inject the pipeline into the Lua VM.");
#endif
}
......@@ -142,7 +147,7 @@ namespace campvis {
std::vector<AbstractPipeline*> pipelines = w->getPipelines();
for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
addPipeline((*it)->getName(), *it);
addPipeline(*it);
}
_workflows.push_back(w);
......@@ -158,12 +163,12 @@ namespace campvis {
}
else {
DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), dc);
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), *dc);
if (p != nullptr)
addPipeline(pipelinesToAdd[i].toStdString(), p);
addPipeline(p);
}
}
_initialized = true;
}
......@@ -221,31 +226,29 @@ namespace campvis {
return toReturn;
}
void CampVisApplication::addPipeline(const std::string& name, AbstractPipeline* pipeline) {
void CampVisApplication::addPipeline(AbstractPipeline* pipeline) {
cgtAssert(pipeline != 0, "Pipeline must not be 0.");
// create canvas and painter for the pipeline and connect all together
cgt::QtThreadedCanvas* canvas = new cgt::QtThreadedCanvas("CAMPVis", cgt::ivec2(512, 512));
cgt::QtThreadedCanvas* canvas = new cgt::QtThreadedCanvas(pipeline->getName(), cgt::ivec2(512, 512));
canvas->init();
pipeline->setCanvas(canvas);
pipeline->getPipelinePainter()->setErrorTexture(_errorTexture);
_pipelines.push_back(pipeline);
_pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(name, canvas);
_pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(pipeline->getName(), canvas);
// initialize context (GLEW) and pipeline in OpenGL thread)
initGlContextAndPipeline(canvas, pipeline);
#ifdef CAMPVIS_HAS_SCRIPTING
if (! _luaVmState->injectObjectPointerToTable(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", static_cast<int>(_pipelines.size())))
//if (! _luaVmState->injectObjectPointerToTableField(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", name))
LERROR("Could not inject the pipeline into the Lua VM.");
if (! _luaVmState->injectObjectPointerToTableField(pipeline, "campvis::AutoEvaluationPipeline *", "pipelines", pipeline->getName()))
LERROR("Could not inject the pipeline into the Lua VM.");
_luaVmState->execString("inspect(pipelines)");
#endif
GLCtxtMgr.releaseContext(canvas, false);
......@@ -296,7 +299,7 @@ namespace campvis {
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
for (auto pit = (*it)->getProcessors().cbegin(); pit != (*it)->getProcessors().cend(); ++pit) {
if (VisualizationProcessor* tester = dynamic_cast<VisualizationProcessor*>(*pit)) {
tester->invalidate(AbstractProcessor::INVALID_RESULT);
tester->invalidate(AbstractProcessor::INVALID_RESULT);
}
}
}
......@@ -316,3 +319,4 @@ namespace campvis {
}
}
......@@ -34,11 +34,7 @@
#include <vector>
#include "core/datastructures/datacontainer.h"
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h"
#endif
#include "application/applicationapi.h"
namespace cgt {
class GLCanvas;
......@@ -65,7 +61,7 @@ namespace campvis {
* 5. call deinit()
* 6. You can now safely destroy your CampVisApplication
*/
class CampVisApplication : public QApplication {
class CAMPVIS_APPLICATION_API CampVisApplication : public QApplication {
friend class MainWindow;
public:
......@@ -97,10 +93,9 @@ namespace campvis {
* Each pipeline will automatically get its own OpenGL context, the corresponding CampvisPainter
* and all necessary connections will be created.
*
* \param name Name of the OpenGL context to create for the pipeline.
* \param vp AbstractPipeline to add.
*/
void addPipeline(const std::string& name, AbstractPipeline* pipeline);
void addPipeline(AbstractPipeline* pipeline);
/**
* Adds a dock widget to the main window.
......
......@@ -26,6 +26,7 @@
#define DOUBLEADJUSTERWIDGET_H__
#include "abstractadjusterwidget.h"
#include "application/applicationapi.h"
namespace campvis {
/**
......@@ -34,7 +35,7 @@ namespace campvis {
* DoubleAdjusterWidget consists of a slider, which can be used to quickly change numeric values, and a spin box,
* which is better suited for precise adjustments.
*/
class DoubleAdjusterWidget : public AbstractAdjusterWidget<double> {
class CAMPVIS_APPLICATION_API DoubleAdjusterWidget : public AbstractAdjusterWidget<double> {
Q_OBJECT
......
......@@ -26,6 +26,7 @@
#define INTADJUSTERWIDGET_H__
#include "abstractadjusterwidget.h"
#include "application/applicationapi.h"
namespace campvis {
/**
......@@ -34,7 +35,7 @@ namespace campvis {
* IntAdjusterWidget consists of a slider, which can be used to quickly change integer values, and a spin box,
* which is better suited for precise adjustments.
*/
class IntAdjusterWidget : public AbstractAdjusterWidget<int> {
class CAMPVIS_APPLICATION_API IntAdjusterWidget : public AbstractAdjusterWidget<int> {
Q_OBJECT
public:
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "completinglualineedit.h"
#include "application/gui/luatablewidget.h"
#include <QAbstractItemModel>
#include <QAbstractItemView>
#include <QKeyEvent>
#include <QDirModel>
#include <QScrollBar>
namespace campvis {
LuaCompleter::LuaCompleter(LuaVmState* luaVmState, QWidget* parent)
: QCompleter(parent)
, _luaVmState(luaVmState)
{
auto luaTreeModel = new LuaTableTreeModel(this);
luaTreeModel->setData(_luaVmState, LuaTreeItem::COMPLETER_MODEL);
setModel(luaTreeModel);
}
LuaCompleter::~LuaCompleter() {
}
QStringList LuaCompleter::splitPath(const QString& path) const {
QStringList toReturn;
toReturn.push_back("[Global Variables]");
int start = 0;
for (int end = start; end < path.length(); ++end) {
if (path[end] == '.') {
toReturn.push_back(path.mid(start, end-start));
start = end+1;
}
if (path[end] == ':') {
toReturn.push_back(path.mid(start, end-start));
toReturn.push_back("[Methods]");
start = end+1;
}
}
toReturn.push_back(path.right(path.length() - start));
return toReturn;
}
// ================================================================================================
CompletingLuaLineEdit::CompletingLuaLineEdit(LuaVmState* luaVmState, QWidget* parent)
: QLineEdit(parent)
, _completer(nullptr)
{
setCompleter(new LuaCompleter(luaVmState, this));
}
CompletingLuaLineEdit::~CompletingLuaLineEdit() {
}
void CompletingLuaLineEdit::setCompleter(LuaCompleter* completer) {
if (_completer)
QObject::disconnect(_completer, 0, this, 0);
_completer = completer;
if (! _completer)
return;
_completer->setWidget(this);
_completer->setCompletionMode(QCompleter::PopupCompletion);
_completer->setCaseSensitivity(Qt::CaseInsensitive);
connect(_completer, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString)));
}