Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

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

Commit a33ee468 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Started implementation of a Lua console in campvis-application.

With scripting enabled, the main window now has an additional scripting widget that allows to interact with a Lua VM. The current proof-of-concept implementation creates a Lua VM for every instantiated CAMPVis pipeline while the console just interacts with the first pipeline's one.
However, the Lua VM concept has to be reiterated later anyway. It may make more sense to have just a single central Lua VM for the entire application, which is shared by each pipeline.
parent 9538173f
......@@ -69,6 +69,17 @@ ENDIF()
IF(CAMPVIS_ENABLE_SCRIPTING)
# 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)
ADD_SUBDIRECTORY(scripting)
LIST(APPEND CampvisGlobalDefinitions "-DCAMPVIS_HAS_SCRIPTING")
ENDIF()
......
......@@ -38,6 +38,7 @@ SET(CampvisApplicationToBeMocced
gui/qtdatahandle.h
gui/logviewerwidget.h
gui/loghighlighter.h
gui/scriptingwidget.h
gui/mdi/mdidockarea.h
gui/mdi/mdidockablewindow.h
gui/mdi/mdidockedwindow.h
......
......@@ -77,11 +77,9 @@ namespace campvis {
tgtAssert(_initialized == false, "Destructing initialized CampVisApplication, deinitialize first!");
// delete everything in the right order:
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
delete it->second;
}
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete *it;
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete it->_painter;
delete it->_pipeline;
}
for (std::vector<DataContainer*>::iterator it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
delete *it;
......@@ -170,14 +168,10 @@ namespace campvis {
delete _errorTexture;
// Deinit pipeline first
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
(*it)->deinit();
}
// Now deinit painters:
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->deinit();
// Deinit pipeline and painter first
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
it->_pipeline->deinit();
it->_painter->deinit();
}
_mainWindow->deinit();
......@@ -227,8 +221,8 @@ namespace campvis {
pipeline->setCanvas(canvas);
painter->setErrorTexture(_errorTexture);
_visualizations.push_back(std::make_pair(pipeline, painter));
_pipelines.push_back(pipeline);
PipelineRecord pr = { pipeline, painter, nullptr };
_pipelines.push_back(pr);
_mainWindow->addVisualizationPipelineWidget(name, canvas);
......@@ -238,6 +232,30 @@ namespace campvis {
makeJobOnHeap<CampVisApplication, tgt::GLCanvas*, AbstractPipeline*>(this, &CampVisApplication::initGlContextAndPipeline, canvas, pipeline),
OpenGLJobProcessor::SerialJob);
// create and store Lua VM for this very pipeline
#ifdef CAMPVIS_HAS_SCRIPTING
LuaVmState* lvs = new LuaVmState();
// Let Lua know where CAMPVis modules are located
if (!lvs->execString("package.cpath = '" CAMPVIS_LUA_MODS_PATH "'"))
LERROR("Error setting up Lua VM.");
// Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
if (!lvs->execString("require(\"campvis\")"))
LERROR("Error setting up Lua VM.");
if (!lvs->execString("require(\"tgt\")"))
LERROR("Error setting up Lua VM.");
// if (!lvs->execFile(CAMPVIS_SOURCE_DIR "/application/scripting/inspect.lua"))
// LERROR("Error setting up Lua VM.");
if (!lvs->injectObjectPointer(pipeline, "campvis::AutoEvaluationPipeline *", "pipeline")) {
LERROR("Could not inject the pipeline into the Lua VM.");
}
_pipelines.back()._luaVmState = std::shared_ptr<LuaVmState>(lvs);
#endif
s_PipelinesChanged();
}
......@@ -284,8 +302,8 @@ namespace campvis {
LINFO("Rebuilding shaders from file successful.");
}
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
for (std::vector<AbstractProcessor*>::const_iterator pit = (*it)->getProcessors().begin(); pit != (*it)->getProcessors().end(); ++pit) {
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
for (std::vector<AbstractProcessor*>::const_iterator pit = it->_pipeline->getProcessors().begin(); pit != it->_pipeline->getProcessors().end(); ++pit) {
if (VisualizationProcessor* tester = dynamic_cast<VisualizationProcessor*>(*pit)) {
tester->invalidate(AbstractProcessor::INVALID_RESULT);
}
......
......@@ -35,6 +35,10 @@
#include "core/datastructures/datacontainer.h"
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h"
#endif
namespace tgt {
class GLCanvas;
class QtThreadedCanvas;
......@@ -45,6 +49,7 @@ namespace campvis {
class AbstractPipeline;
class MainWindow;
class CampVisPainter;
class LuaVmState;
/**
* The CampVisApplication class wraps Pipelines, Evaluators and Painters all together and takes
......@@ -62,6 +67,15 @@ namespace campvis {
friend class MainWindow;
public:
/// Record storing a pipeline together with its painter and Lua VM state.
struct PipelineRecord {
AbstractPipeline* _pipeline;
CampVisPainter* _painter;
#ifdef CAMPVIS_HAS_SCRIPTING
std::shared_ptr<LuaVmState> _luaVmState;
#endif
};
/**
* Creates a new CampVisApplication.
* \param argc number of passed arguments
......@@ -135,9 +149,7 @@ namespace campvis {
/// All pipelines
std::vector<AbstractPipeline*> _pipelines;
/// All visualisations (i.e. Pipelines with their corresponding painters/canvases)
std::vector< std::pair<AbstractPipeline*, CampVisPainter*> > _visualizations;
std::vector<PipelineRecord> _pipelines;
/// All DataContainers
std::vector<DataContainer*> _dataContainers;
......
......@@ -58,6 +58,7 @@ namespace campvis {
, _selectedProcessor(0)
, _selectedDataContainer(0)
, _logViewer(0)
, _scriptingConsoleWidget(nullptr)
{
tgtAssert(_application != 0, "Application must not be 0.");
ui.setupUi(this);
......@@ -130,6 +131,12 @@ namespace campvis {
_logViewer = new LogViewerWidget(this);
ui.logViewerDock->setWidget(_logViewer);
#ifdef CAMPVIS_HAS_SCRIPTING
_scriptingConsoleWidget = new ScriptingWidget(this);
ui.scriptingConsoleDock->setWidget(_scriptingConsoleWidget);
connect(_scriptingConsoleWidget, SIGNAL(s_commandExecuted(const QString&)), this, SLOT(onLuaCommandExecuted(const QString&)));
#endif
_dcInspectorWidget = new DataContainerInspectorWidget();
this->populateMainMenu();
......@@ -185,11 +192,17 @@ namespace campvis {
}
void MainWindow::onPipelinesChanged() {
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
std::vector<AbstractPipeline*> pipelines;
std::for_each(_application->_pipelines.begin(), _application->_pipelines.end(), [&] (const CampVisApplication::PipelineRecord& pr) { pipelines.push_back(pr._pipeline); });
emit updatePipelineWidget(_application->_dataContainers, pipelines);
}
void MainWindow::onDataContainersChanged() {
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
std::vector<AbstractPipeline*> pipelines;
std::for_each(_application->_pipelines.begin(), _application->_pipelines.end(), [&] (const CampVisApplication::PipelineRecord& pr) { pipelines.push_back(pr._pipeline); });
emit updatePipelineWidget(_application->_dataContainers, pipelines);
}
void MainWindow::onPipelineWidgetItemClicked(const QModelIndex& index) {
......@@ -311,4 +324,11 @@ namespace campvis {
_application->rebuildAllShadersFromFiles();
}
void MainWindow::onLuaCommandExecuted(const QString& cmd) {
// FIXME: so far just a hack
if (! _application->_pipelines.empty()){
_application->_pipelines.front()._luaVmState->execString(cmd.toStdString());
}
}
}
......@@ -31,6 +31,7 @@
#include "application/gui/pipelinetreewidget.h"
#include "application/gui/properties/propertycollectionwidget.h"
#include "application/gui/logviewerwidget.h"
#include "application/gui/scriptingwidget.h"
#include "application/tools/qtexteditlog.h"
#include "application/ui_mainwindow.h"
......@@ -105,7 +106,7 @@ namespace campvis {
/// Qt signal for updating the PropertyCollectionWidget
void updatePropCollectionWidget(HasPropertyCollection*, DataContainer*);
private slots:
public slots:
/**
* Slot to be called by the PipelineWidget when the selected item changes.
* \param index Index of the selected item
......@@ -128,6 +129,9 @@ namespace campvis {
/// Slot to be called when all shaders shall be rebuilt.
void onRebuildShadersClicked();
/// Slot to be called when a Lua command shall be executed.
void onLuaCommandExecuted(const QString& cmd);
private:
/**
......@@ -185,6 +189,8 @@ namespace campvis {
DataContainer* _selectedDataContainer; ///< currently selected DataContainer
LogViewerWidget* _logViewer; ///< Widget displaying log messages
ScriptingWidget* _scriptingConsoleWidget; ///< Widget showing the scripting console (if available)
std::vector<QDockWidget*> _primaryDocks; ///< Docks located in top docking area of the main window
};
}
......
// ================================================================================================
//
// 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 "scriptingwidget.h"
namespace campvis {
ScriptingWidget::ScriptingWidget(QWidget* parent)
: QWidget(parent)
{
setupGUI();
}
ScriptingWidget::~ScriptingWidget() {
}
void ScriptingWidget::setupGUI() {
setWindowTitle(tr("Scripting Console"));
QVBoxLayout* mainLayout = new QVBoxLayout(this);
QHBoxLayout* controlsLayout = new QHBoxLayout();
mainLayout->addLayout(controlsLayout);
_consoleDisplay = new QTextEdit(this);
_consoleDisplay->setReadOnly(true);
mainLayout->addWidget(_consoleDisplay);
// Use the system's default monospace font at the default size in the log viewer
QFont monoFont = QFont("Monospace");
monoFont.setStyleHint(QFont::TypeWriter);
monoFont.setPointSize(QFont().pointSize() + 1);
_consoleDisplay->document()->setDefaultFont(monoFont);
_editCommand = new QLineEdit(this);
_editCommand->setPlaceholderText(tr("Enter Lua commands here..."));
controlsLayout->addWidget(_editCommand);
_btnExecute = new QPushButton(tr("&Execute"), this);
controlsLayout->addWidget(_btnExecute);
_btnClear = new QPushButton(tr("&Clear"), this);
controlsLayout->addWidget(_btnClear);
connect(_btnClear, SIGNAL(clicked()), this, SLOT(clearLog()));
connect(_btnExecute, SIGNAL(clicked()), this, SLOT(execute()));
connect(_editCommand, SIGNAL(returnPressed()), this, SLOT(execute()));
connect(this, SIGNAL(s_commandExecuted(QString)), this, SLOT(appendMessage(const QString&)));
}
void ScriptingWidget::appendMessage(const QString& message) {
_consoleDisplay->append(tr("> ") + message);
}
void ScriptingWidget::clearLog() {
_consoleDisplay->clear();
}
void ScriptingWidget::execute() {
QString command = _editCommand->text();
emit s_commandExecuted(command);
_editCommand->clear();
}
}
// ================================================================================================
//
// 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.
//
// ================================================================================================
#ifndef SCRIPTINGWIDGET_H__
#define SCRIPTINGWIDGET_H__
#include "sigslot/sigslot.h"
#include "tgt/painter.h"
#include "tbb/mutex.h"
#include "application/tools/bufferinglog.h"
#include "application/gui/loghighlighter.h"
#include <QComboBox>
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QString>
#include <QPushButton>
#include <QLineEdit>
#include <QTextEdit>
namespace campvis {
class ScriptingWidget : public QWidget {
Q_OBJECT;
public:
/**
* Creates a new DataContainerInspectorWidget.
* \param parent Parent Qt widget, may be 0 (default)
*/
explicit ScriptingWidget(QWidget* parent = 0);
/**
* Destructor.
*/
~ScriptingWidget();
protected:
/**
* Setup the the log viewer's GUI
*/
void setupGUI();
public slots:
/**
* Append the given message to the log viewer
*
* This function adds the specified message to the log viewer's message cache and
* displays it.
*
* \param message message to append to the log viewer
*/
void appendMessage(const QString& message);
/**
* Delete all messages from the log viewer
*/
void clearLog();
void execute();
signals:
void s_commandExecuted(const QString& cmd);
private:
QTextEdit* _consoleDisplay; ///< Text edit to hold the console output
QLineEdit* _editCommand; ///< Text field to enter Lua commands
QPushButton* _btnExecute; ///< Button to execute command
QPushButton* _btnClear; ///< Button to clear the console output
};
}
#endif // SCRIPTINGWIDGET_H__
......@@ -58,6 +58,15 @@
</attribute>
<widget class="QWidget" name="logViewerDockContents"/>
</widget>
<widget class="QDockWidget" name="scriptingConsoleDock">
<property name="windowTitle">
<string>Scripting Console</string>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="scriptingConsoleDockContents"/>
</widget>
</widget>
<resources/>
<connections/>
......
Subproject commit 96245accd1539c8bb0d8be310eaa9cf5fbab9fed
Subproject commit aaf39ecc16c688f6a3804477f9355651534ddec1
......@@ -3,17 +3,6 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
MESSAGE(STATUS "Configuring CAMPVis Scripting")
# Lua
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)
# SWIG
FIND_PACKAGE(SWIG REQUIRED)
MESSAGE(STATUS "* Found SWIG")
......@@ -37,7 +26,8 @@ SET(CampvisLuaModulesDirectory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_IN
# Lua modules will be placed in a sub-directory that won't be picked up by Lua automatically. Let
# the code know via a #define what that sub-directory is so that it can instruct Lua to search it.
LIST(APPEND CampvisScriptingDefinitions "-DCAMPVIS_LUA_MODS_PATH=\"${CampvisLuaModulesDirectory}?${CMAKE_SHARED_MODULE_SUFFIX}\"")
LIST(APPEND CampvisGlobalDefinitions "-DCAMPVIS_LUA_MODS_PATH=\"${CampvisLuaModulesDirectory}?${CMAKE_SHARED_MODULE_SUFFIX}\"")
SET(CampvisGlobalDefinitions "${CampvisGlobalDefinitions}" PARENT_SCOPE)
SET(CampvisBindingDirs ext/tgt core)
......
......@@ -3,7 +3,7 @@
#include <memory>
#include <string>
#include "swigluarun.h"
#include "scripting/swigluarun.h"
#include "tbb/recursive_mutex.h"
extern "C" {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment