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

Various improvements of the SWIG Lua bindings:

* Added DISOWN typemaps to various functions, where CAMPVis takes ownership of passed pointers. This prevents the Lua garbage collector from deleting those items.
* Improved sigslot bindings to also support pass-by-value signal arguments.
* Changed import type of campvis.i from #include to #import

refs #643
parent 12f36262
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
%include std_string.i %include std_string.i
%include std_vector.i %include std_vector.i
%include "core/bindings/campvis.i" %import "core/bindings/campvis.i"
%{ %{
#include "application/campvisapplication.h" #include "application/campvisapplication.h"
//#include "core/properties/allproperties.h" #include "core/properties/allproperties.h"
//#include "core/pipeline/abstractprocessor.h" #include "core/pipeline/abstractprocessor.h"
//#include "core/pipeline/abstractworkflow.h" #include "core/pipeline/abstractworkflow.h"
//#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
%} %}
namespace campvis { namespace campvis {
...@@ -26,8 +26,10 @@ namespace campvis { ...@@ -26,8 +26,10 @@ namespace campvis {
void deinit(); void deinit();
int run(); int run();
%apply SWIGTYPE *DISOWN {AbstractPipeline* pipeline};
void addPipeline(const std::string& name, AbstractPipeline* pipeline); void addPipeline(const std::string& name, AbstractPipeline* pipeline);
DataContainer* createAndAddDataContainer(const std::string& name); DataContainer* createAndAddDataContainer(const std::string& name);
%clear AbstractPipeline* pipeline;
void rebuildAllShadersFromFiles(); void rebuildAllShadersFromFiles();
void setPipelineVisibility(AbstractPipeline* pipeline, bool visibility); void setPipelineVisibility(AbstractPipeline* pipeline, bool visibility);
......
...@@ -89,9 +89,11 @@ namespace campvis { ...@@ -89,9 +89,11 @@ namespace campvis {
connect(_btnClear, SIGNAL(clicked()), this, SLOT(clearLog())); connect(_btnClear, SIGNAL(clicked()), this, SLOT(clearLog()));
connect(_btnExecute, SIGNAL(clicked()), this, SLOT(execute())); connect(_btnExecute, SIGNAL(clicked()), this, SLOT(execute()));
connect(_editCommand, SIGNAL(returnPressed()), this, SLOT(execute())); connect(_editCommand, SIGNAL(returnPressed()), this, SLOT(execute()));
connect(this, SIGNAL(s_messageAppended(QString)), this, SLOT(appendMessage(QString)));
} }
void ScriptingWidget::appendMessage(const QString& message) { void ScriptingWidget::appendMessage(QString message) {
_consoleDisplay->append(message); _consoleDisplay->append(message);
} }
...@@ -134,7 +136,7 @@ namespace campvis { ...@@ -134,7 +136,7 @@ namespace campvis {
void ScriptingWidget::logFiltered(const std::string &cat, cgt::LogLevel level, const std::string& msg, const std::string& extendedInfo/*=""*/) { void ScriptingWidget::logFiltered(const std::string &cat, cgt::LogLevel level, const std::string& msg, const std::string& extendedInfo/*=""*/) {
if (level == cgt::LuaInfo || level == cgt::LuaError) { if (level == cgt::LuaInfo || level == cgt::LuaError) {
appendMessage(QString::fromStdString(msg)); emit s_messageAppended(QString::fromStdString(msg));
} }
} }
......
...@@ -99,7 +99,7 @@ namespace campvis { ...@@ -99,7 +99,7 @@ namespace campvis {
* *
* \param message message to append to the log viewer * \param message message to append to the log viewer
*/ */
void appendMessage(const QString& message); void appendMessage(QString message);
private slots: private slots:
/** /**
...@@ -110,7 +110,8 @@ namespace campvis { ...@@ -110,7 +110,8 @@ namespace campvis {
void execute(); void execute();
signals: signals:
void s_commandExecuted(const QString& cmd); void s_commandExecuted(QString cmd);
void s_messageAppended(QString message);
private: private:
QTextEdit* _consoleDisplay; ///< Text edit to hold the console output QTextEdit* _consoleDisplay; ///< Text edit to hold the console output
......
...@@ -58,17 +58,10 @@ local initCallback = function() ...@@ -58,17 +58,10 @@ local initCallback = function()
LuaDemo.image_reader.s_validated:connect(callback) LuaDemo.image_reader.s_validated:connect(callback)
-- let us create a fancy transfer function -- let us create a fancy transfer function
local geometry1 = campvis.TFGeometry1D_createQuad(cgt.vec2(0.12, 0.15), cgt.col4(85, 0, 0, 128),
cgt.col4(255, 0, 0, 128))
local geometry2 = campvis.TFGeometry1D_createQuad(cgt.vec2(.19, .28), cgt.col4(89, 89, 89, 155),
cgt.col4(89, 89, 89, 155))
local geometry3 = campvis.TFGeometry1D_createQuad(cgt.vec2(.41, .51), cgt.col4(170, 170, 128, 64),
cgt.col4(192, 192, 128, 64))
local dvrTF = campvis.Geometry1DTransferFunction(128, cgt.vec2(0, 0.05)) local dvrTF = campvis.Geometry1DTransferFunction(128, cgt.vec2(0, 0.05))
dvrTF:addGeometry(geometry1) dvrTF:addGeometry(campvis.TFGeometry1D_createQuad(cgt.vec2(0.12, 0.15), cgt.col4(85, 0, 0, 128), cgt.col4(255, 0, 0, 128)))
dvrTF:addGeometry(geometry2) dvrTF:addGeometry(campvis.TFGeometry1D_createQuad(cgt.vec2(.19, .28), cgt.col4(89, 89, 89, 155), cgt.col4(89, 89, 89, 155)))
dvrTF:addGeometry(geometry3) dvrTF:addGeometry(campvis.TFGeometry1D_createQuad(cgt.vec2(.41, .51), cgt.col4(170, 170, 128, 64), cgt.col4(192, 192, 128, 64)))
LuaDemo.vr:getNestedProperty("RaycasterProps::TransferFunction"):replaceTF(dvrTF) LuaDemo.vr:getNestedProperty("RaycasterProps::TransferFunction"):replaceTF(dvrTF)
end end
......
...@@ -31,16 +31,22 @@ static const char* const SOURCE_DIR = CAMPVIS_SOURCE_DIR; ...@@ -31,16 +31,22 @@ static const char* const SOURCE_DIR = CAMPVIS_SOURCE_DIR;
// Template specialisations and instantiations required to get signals to work in Lua // Template specialisations and instantiations required to get signals to work in Lua
namespace sigslot { namespace sigslot {
template<> template<>
struct LuaConnectionArgTraits<campvis::AbstractProcessor*> { struct LuaConnectionArgTraits<campvis::AbstractProcessor*> { static const char* const typeName; };
static const char* const typeName;
};
const char* const LuaConnectionArgTraits<campvis::AbstractProcessor*>::typeName = "campvis::AbstractProcessor *"; const char* const LuaConnectionArgTraits<campvis::AbstractProcessor*>::typeName = "campvis::AbstractProcessor *";
template<>
struct LuaConnectionArgTraits<campvis::DataHandle> { static const char* const typeName; };
const char* const LuaConnectionArgTraits<campvis::DataHandle>::typeName = "campvis::DataHandle *";
template<>
struct LuaConnectionArgTraits<std::string> { static const char* const typeName; };
const char* const LuaConnectionArgTraits<std::string>::typeName = "std::string *";
} }
} }
%template(sigslot_signal1_AbstractProcessor) sigslot::signal1<campvis::AbstractProcessor*>; %template(sigslot_signal1_AbstractProcessor) sigslot::signal1<campvis::AbstractProcessor*>;
%template(sigslot_signal2_string_DataHandle) sigslot::signal2<std::string, campvis::DataHandle>;
%template(PairStringDataHandle) std::pair<std::string, campvis::DataHandle>; %template(PairStringDataHandle) std::pair<std::string, campvis::DataHandle>;
%template(VectorOfPairStringDataHandle) std::vector< std::pair< std::string, campvis::DataHandle> >; %template(VectorOfPairStringDataHandle) std::vector< std::pair< std::string, campvis::DataHandle> >;
...@@ -262,7 +268,9 @@ namespace campvis { ...@@ -262,7 +268,9 @@ namespace campvis {
GenericGeometryTransferFunction(const cgt::vec3& size, const cgt::vec2& intensityDomain = cgt::vec2(0.f, 1.f)); GenericGeometryTransferFunction(const cgt::vec3& size, const cgt::vec2& intensityDomain = cgt::vec2(0.f, 1.f));
virtual ~GenericGeometryTransferFunction(); virtual ~GenericGeometryTransferFunction();
%apply SWIGTYPE *DISOWN {T* geometry};
void addGeometry(T* geometry); void addGeometry(T* geometry);
%clear T* geometry;
}; };
/* Geometry1DTransferFunction */ /* Geometry1DTransferFunction */
...@@ -293,11 +301,13 @@ namespace campvis { ...@@ -293,11 +301,13 @@ namespace campvis {
class TransferFunctionProperty : public AbstractProperty { class TransferFunctionProperty : public AbstractProperty {
public: public:
%apply SWIGTYPE *DISOWN {AbstractTransferFunction* tf};
TransferFunctionProperty(const std::string& name, const std::string& title, AbstractTransferFunction* tf); TransferFunctionProperty(const std::string& name, const std::string& title, AbstractTransferFunction* tf);
virtual ~TransferFunctionProperty(); virtual ~TransferFunctionProperty();
AbstractTransferFunction* getTF(); AbstractTransferFunction* getTF();
void replaceTF(AbstractTransferFunction* tf); void replaceTF(AbstractTransferFunction* tf);
%clear AbstractTransferFunction* tf;
}; };
/* IHasWorldBounds */ /* IHasWorldBounds */
...@@ -327,6 +337,7 @@ namespace campvis { ...@@ -327,6 +337,7 @@ namespace campvis {
/* Downcast the return value of DataHandle::getData to appropriate subclass */ /* Downcast the return value of DataHandle::getData to appropriate subclass */
%factory(const AbstractData* campvis::DataHandle::getData, const campvis::ImageData); %factory(const AbstractData* campvis::DataHandle::getData, const campvis::ImageData);
%apply SWIGTYPE *DISOWN {AbstractData* data};
class DataHandle { class DataHandle {
public: public:
explicit DataHandle(AbstractData* data = 0); explicit DataHandle(AbstractData* data = 0);
...@@ -384,8 +395,11 @@ namespace campvis { ...@@ -384,8 +395,11 @@ namespace campvis {
%immutable; %immutable;
sigslot::signal0 s_changed; sigslot::signal0 s_changed;
sigslot::signal2<std::string, DataHandle> s_dataAdded;
%mutable; %mutable;
}; };
%clear AbstractData* data;
/* Down casting or super classes. /* Down casting or super classes.
* Down casting follows the order of declaration. * Down casting follows the order of declaration.
...@@ -439,6 +453,7 @@ namespace campvis { ...@@ -439,6 +453,7 @@ namespace campvis {
%immutable; %immutable;
sigslot::signal1<AbstractProcessor*> s_validated; sigslot::signal1<AbstractProcessor*> s_validated;
sigslot::signal1<AbstractProcessor*> s_invalidated;
%mutable; %mutable;
}; };
...@@ -459,8 +474,10 @@ namespace campvis { ...@@ -459,8 +474,10 @@ namespace campvis {
AbstractProcessor* getProcessor(const std::string& name) const; AbstractProcessor* getProcessor(const std::string& name) const;
AbstractProcessor* getProcessor(size_t index) const; AbstractProcessor* getProcessor(size_t index) const;
%immutable;
sigslot::signal0 s_init; sigslot::signal0 s_init;
sigslot::signal0 s_deinit; sigslot::signal0 s_deinit;
%mutable;
}; };
/* AutoEvaluationPipeline */ /* AutoEvaluationPipeline */
...@@ -494,8 +511,10 @@ namespace campvis { ...@@ -494,8 +511,10 @@ namespace campvis {
int getCurrentStageId() const; int getCurrentStageId() const;
void setCurrentStage(int stage); void setCurrentStage(int stage);
%immutable;
sigslot::signal2<int, int> s_stageChanged; sigslot::signal2<int, int> s_stageChanged;
sigslot::signal0 s_stageAvailabilityChanged; sigslot::signal0 s_stageAvailabilityChanged;
%mutable;
}; };
...@@ -509,16 +528,5 @@ namespace campvis { ...@@ -509,16 +528,5 @@ namespace campvis {
} }
%luacode { %luacode {
function campvis.newPipeline (name, o)
if not name then
error("A name must be provided when creating a new pipeline!")
end
o = o or {} -- create object if user does not provide one
setmetatable(o, {__index = instance})
return o
end
print("Module campvis-core loaded") print("Module campvis-core loaded")
} }
...@@ -7,7 +7,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR) ...@@ -7,7 +7,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
MESSAGE(STATUS "Configuring sigslot Library") MESSAGE(STATUS "Configuring sigslot Library")
# headers # headers
SET(SIGSLOT_HEADERS sigslot.h) SET(SIGSLOT_HEADERS sigslot.h sigslot.i)
# sources # sources
SET(SIGSLOT_SOURCES sigslot.cpp) SET(SIGSLOT_SOURCES sigslot.cpp)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
%{ %{
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <type_traits>
#include "tbb/recursive_mutex.h" #include "tbb/recursive_mutex.h"
#include "ext/cgt/logmanager.h" #include "ext/cgt/logmanager.h"
#include "ext/sigslot/sigslot.h" #include "ext/sigslot/sigslot.h"
...@@ -42,7 +43,35 @@ namespace sigslot { ...@@ -42,7 +43,35 @@ namespace sigslot {
* Type bundling all information necessary to inject a signal argument into a Lua state: * Type bundling all information necessary to inject a signal argument into a Lua state:
* a pointer to the argument and its corresponding SWIG type information. * a pointer to the argument and its corresponding SWIG type information.
*/ */
typedef std::pair<void*, swig_type_info*> ArgWithTypeInfoType; struct ArgWithTypeInfoType {
void* ptr;
swig_type_info* type_info;
void (*deleter)(void*);
};
template<typename T, bool makeCopy>
struct CreateAwtitHelper {};
template<typename T>
struct CreateAwtitHelper<T, true> {
static void deletePtr(void* ptr) {
delete static_cast<T*>(ptr);
}
static ArgWithTypeInfoType createAwtit(T arg, swig_type_info* typeInfo) {
ArgWithTypeInfoType toReturn = { new T(arg), typeInfo, &deletePtr };
return toReturn;
}
};
template<typename T>
struct CreateAwtitHelper<T, false> {
static ArgWithTypeInfoType createAwtit(T arg, swig_type_info* typeInfo) {
ArgWithTypeInfoType toReturn = { arg, typeInfo, nullptr };
return toReturn;
}
};
/* /*
* Return an object bundling the provided argument with its SWIG type information. * Return an object bundling the provided argument with its SWIG type information.
...@@ -56,7 +85,8 @@ namespace sigslot { ...@@ -56,7 +85,8 @@ namespace sigslot {
LogMgr.log("Lua", cgt::LuaError, "SWIG wrapper for " + std::string(typeName) + " not found"); LogMgr.log("Lua", cgt::LuaError, "SWIG wrapper for " + std::string(typeName) + " not found");
} }
return std::make_pair(arg, typeInfo); ArgWithTypeInfoType toReturn = CreateAwtitHelper<T, !std::is_pointer<T>::value && !std::is_reference<T>::value>::createAwtit(arg, typeInfo);
return toReturn;
} }
/* /*
...@@ -66,7 +96,7 @@ namespace sigslot { ...@@ -66,7 +96,7 @@ namespace sigslot {
inline std::list<ArgWithTypeInfoType>* argWithTypeInfoListCons(ArgWithTypeInfoType head, inline std::list<ArgWithTypeInfoType>* argWithTypeInfoListCons(ArgWithTypeInfoType head,
std::list<ArgWithTypeInfoType>* tail) std::list<ArgWithTypeInfoType>* tail)
{ {
if (head.second == nullptr) { if (head.type_info == nullptr) {
delete tail; delete tail;
} else if (tail != nullptr) { } else if (tail != nullptr) {
tail->push_front(head); tail->push_front(head);
...@@ -227,7 +257,7 @@ namespace sigslot { ...@@ -227,7 +257,7 @@ namespace sigslot {
swiglua_ref_get(&_slot_fn); swiglua_ref_get(&_slot_fn);
for (auto it = argWithTypeInfoList->begin(); it != argWithTypeInfoList->end(); ++it) for (auto it = argWithTypeInfoList->begin(); it != argWithTypeInfoList->end(); ++it)
SWIG_NewPointerObj(_slot_fn.L, it->first, it->second, 0); SWIG_NewPointerObj(_slot_fn.L, it->ptr, it->type_info, 0);
if (lua_pcall(_slot_fn.L, argWithTypeInfoList->size(), 0, 0) != LUA_OK) { if (lua_pcall(_slot_fn.L, argWithTypeInfoList->size(), 0, 0) != LUA_OK) {
const char* errorMsg = lua_tostring(_slot_fn.L, -1); const char* errorMsg = lua_tostring(_slot_fn.L, -1);
...@@ -240,6 +270,10 @@ namespace sigslot { ...@@ -240,6 +270,10 @@ namespace sigslot {
lua_pop(_slot_fn.L, 1); lua_pop(_slot_fn.L, 1);
} }
for (auto it = argWithTypeInfoList->begin(); it != argWithTypeInfoList->end(); ++it) {
if (it->deleter != nullptr)
(it->deleter)(it->ptr);
}
delete argWithTypeInfoList; delete argWithTypeInfoList;
} }
} }
...@@ -627,6 +661,24 @@ namespace sigslot { ...@@ -627,6 +661,24 @@ namespace sigslot {
++it; ++it;
} }
} }
void disconnectAllLuaSlots() {
typedef sigslot::_signal_base2<arg1_type, arg2_type>::connections_list connections_list;
connections_list::iterator it = $self->m_connected_slots.begin();
connections_list::iterator itEnd = $self->m_connected_slots.end();
while (it != itEnd) {
sigslot::_lua_connection2<arg1_type, arg2_type>* lua_connection =
dynamic_cast<sigslot::_lua_connection2<arg1_type, arg2_type>*>(*it);
if (lua_connection != nullptr) {
delete lua_connection;
$self->m_connected_slots.erase(it);
}
++it;
}
}
} }
}; };
......
%module base %module base
%include std_string.i %include std_string.i
%import "ext/cgt/bindings/cgt.i" %import "ext/cgt/bindings/cgt.i"
%include "core/bindings/campvis.i"
%import "core/bindings/campvis.i"
%{ %{
#include "core/properties/allproperties.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/visualizationprocessor.h" #include "core/pipeline/visualizationprocessor.h"
#include "modules/base/processors/lightsourceprovider.h" #include "modules/base/processors/lightsourceprovider.h"
......
%module devil %module devil
%include std_string.i %include std_string.i
%include "core/bindings/campvis.i" %import "core/bindings/campvis.i"
%{ %{
#include "core/pipeline/visualizationprocessor.h" #include "core/properties/allproperties.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/visualizationprocessor.h"
#include "modules/devil/processors/devilimagereader.h" #include "modules/devil/processors/devilimagereader.h"
#include "modules/devil/processors/devilimagewriter.h" #include "modules/devil/processors/devilimagewriter.h"
%} %}
......
%module cvio %module cvio
%include std_string.i %include std_string.i
%include "core/bindings/campvis.i" %import "core/bindings/campvis.i"
%{ %{
#include "core/pipeline/visualizationprocessor.h" #include "core/properties/allproperties.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/visualizationprocessor.h"
#include "modules/io/processors/mhdimagereader.h" #include "modules/io/processors/mhdimagereader.h"
#include "modules/io/processors/mhdimagewriter.h" #include "modules/io/processors/mhdimagewriter.h"
%} %}
......
%module preprocessing %module preprocessing
%include std_string.i %include std_string.i
%include "core/bindings/campvis.i" %import "core/bindings/campvis.i"
%{ %{
#include "core/properties/allproperties.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/visualizationprocessor.h"
#include "modules/preprocessing/processors/glimageresampler.h" #include "modules/preprocessing/processors/glimageresampler.h"
%} %}
......
%module vis %module vis
%include std_string.i %include std_string.i
%include "core/bindings/campvis.i" %import "core/bindings/campvis.i"
%{ %{
#include "core/properties/allproperties.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/autoevaluationpipeline.h" #include "core/pipeline/autoevaluationpipeline.h"
#include "core/pipeline/visualizationprocessor.h"
#include "modules/vis/processors/volumeexplorer.h" #include "modules/vis/processors/volumeexplorer.h"
#include "modules/vis/processors/volumerenderer.h" #include "modules/vis/processors/volumerenderer.h"
......
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