The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 5ea6ef24 authored by schultezub's avatar schultezub
Browse files

various design revisions:

 * Moved paint() method out of VisualizationPipeline back to TumVisPainter
 * started using signals/slots instead of simple observer implementation

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@193 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 29c1c9cb
......@@ -4,6 +4,8 @@
#include "tgt/qt/qtapplication.h"
#include "tgt/qt/qtcanvas.h"
#include "tbb/include/tbb/task_scheduler_init.h"
#include "tumvispainter.h"
#include "modules/pipelines/slicevis.h"
......@@ -22,6 +24,7 @@ int main(int argc, char** argv) {
tgt::QtCanvas* canvas = new tgt::QtCanvas("TUMVis");
SliceVis* sliceVis = 0;
tbb::task_scheduler_init init;
app->addCanvas(canvas);
app->init();
LogMgr.getConsoleLog()->addCat("", true);
......@@ -36,13 +39,13 @@ int main(int argc, char** argv) {
tgt::Camera camera;
canvas->setCamera(&camera);
TumVisPainter* painter;
try {
sliceVis = new SliceVis(canvas);
canvas->setPainter(sliceVis);
// TumVisPainter painter(canvas);
// canvas->setPainter(&painter);
sliceVis = new SliceVis();
painter = new TumVisPainter(canvas, sliceVis);
canvas->setPainter(painter);
sliceVis->init();
}
catch (tgt::Exception& e) {
LERRORC("main.cpp", "Encountered tgt::Exception: " << e.what());
......@@ -53,6 +56,7 @@ int main(int argc, char** argv) {
app->run();
delete painter;
delete sliceVis;
delete canvas;
delete app;
......
#include "tumvispainter.h"
#include "tgt/assert.h"
#include "tgt/camera.h"
#include "tgt/quadrenderer.h"
#include "tgt/quadric.h"
#include "core/datastructures/imagedatarendertarget.h"
namespace TUMVis {
const std::string TumVisPainter::loggerCat_ = "TUMVis.core.TumVisPainter";
TumVisPainter::TumVisPainter(tgt::GLCanvas* canvas)
TumVisPainter::TumVisPainter(tgt::GLCanvas* canvas, VisualizationPipeline* pipeline)
: tgt::Painter(canvas)
, _pipeline(0)
, _dirty(0)
, _currentlyRendering(false)
, _copyShader(0)
{
tgtAssert(getCanvas() != 0, "The given canvas must not be 0!");
setPipeline(pipeline);
}
void TumVisPainter::paint() {
// Put TUMVis rendering pipeline evaluation inside
if (getCanvas() == 0)
return;
{
tbb::mutex::scoped_lock lock(_localMutex);
_currentlyRendering = true;
_dirty = false;
}
// get OpenGL focus and setup context
getCanvas()->getGLFocus();
const tgt::ivec2 size = getCanvas()->getSize();
glViewport(0, 0, size.x, size.y);
// try get Data
const ImageDataRenderTarget* image = _pipeline->getRenderTarget();
if (image != 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Some Dummy rendering:
// activate shader
_copyShader->activate();
_copyShader->setIgnoreUniformLocationError(true);
_copyShader->setUniform("_viewportSize", size);
_copyShader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(size));
_copyShader->setIgnoreUniformLocationError(false);
// bind input textures
tgt::TextureUnit colorUnit, depthUnit;
image->bind(_copyShader, colorUnit, depthUnit);
LGL_ERROR;
// execute the shader
tgt::QuadRenderer::renderQuad();
_copyShader->deactivate();
LGL_ERROR;
}
else {
// TODO: render some nifty error texture
// so long, we do some dummy rendering
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
getCamera()->setPosition(tgt::vec3(0.f,0.f,2.f));
getCamera()->look();
glColor3f(1.f, 0.f, 0.f);
tgt::Sphere sphere(.5f, 64, 32);
sphere.render();
/*
// render error texture
if (!errorTex_) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
}
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
errorTex_->bind();
errorTex_->enable();
glColor3f(1.f, 1.f, 1.f);
renderQuad();
errorTex_->disable();*/
}
LGL_ERROR;
{
tbb::mutex::scoped_lock lock(_localMutex);
_currentlyRendering = false;
}
if (_dirty)
getCanvas()->repaint();
}
void TumVisPainter::sizeChanged(const tgt::ivec2& size) {
if (getCanvas()) {
getCanvas()->getGLFocus();
}
glViewport(0, 0, size.x, size.y);
getCamera()->setRatio((float) size.x/size.y);
_pipeline->setRenderTargetSize(size);
}
void TumVisPainter::init() {
if (getCanvas()) {
getCanvas()->getGLFocus();
try {
// TODO: Remove hardcoded paths, and use ShdrMgr.addPath() at some central location
_copyShader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/copyimage.frag", "", false);
}
catch (tgt::Exception& e) {
LERRORC("main.cpp", "Encountered tgt::Exception: " << e.what());
}
else {
LWARNING("initialize(): No canvas");
}
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
getCamera()->setPosition(tgt::vec3(0.f,0.f,2.f));
/*
void TumVisPainter::setPipeline(VisualizationPipeline* pipeline) {
tgtAssert(pipeline != 0, "The given pipeline must not be 0.");
if (_pipeline != 0) {
_pipeline->s_renderTargetChanged.disconnect(this);
if (getCanvas()->getEventHandler() != 0)
getCanvas()->getEventHandler()->removeListener(_pipeline);
}
_pipeline = pipeline;
_pipeline->s_renderTargetChanged.connect(this, &TumVisPainter::onPipelineInvalidated);
_pipeline->setRenderTargetSize(getCanvas()->getSize());
if (getCanvas()->getEventHandler() != 0)
getCanvas()->getEventHandler()->addListenerToFront(_pipeline);
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_CULL_FACE);
glCullFace(GL_BACK);*/
void TumVisPainter::onPipelineInvalidated() {
if (! _currentlyRendering)
getCanvas()->repaint();
else {
tbb::mutex::scoped_lock lock(_localMutex);
_dirty = true;
}
}
}
\ No newline at end of file
#include "sigslot/sigslot.h"
#include "tbb/include/tbb/mutex.h"
#include "tgt/logmanager.h"
#include "tgt/glcanvas.h"
#include "tgt/painter.h"
#include "tgt/event/eventhandler.h"
#include "core/pipeline/visualizationpipeline.h"
namespace tgt {
class Shader;
}
namespace TUMVis {
/**
......@@ -10,18 +18,26 @@ namespace TUMVis {
*
* \todo
*/
class TumVisPainter : public tgt::Painter {
class TumVisPainter : public tgt::Painter, public sigslot::has_slots<> {
public:
TumVisPainter(tgt::GLCanvas* canvas);
TumVisPainter(tgt::GLCanvas* canvas, VisualizationPipeline* pipeline);
virtual void paint();
virtual void sizeChanged(const tgt::ivec2& size);
virtual void init();
void setPipeline(VisualizationPipeline* pipeline);
void onPipelineInvalidated();
private:
static const std::string loggerCat_;
float _size;
VisualizationPipeline* _pipeline;
bool _dirty;
bool _currentlyRendering;
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer.
tbb::mutex _localMutex;
};
}
......@@ -16,12 +16,13 @@ namespace TUMVis {
}
const DataHandle* DataContainer::addData(const std::string& name, AbstractData* data) {
DataHandle* dh = new DataHandle(this, data);
DataHandle* dh = new DataHandle(data);
addDataHandle(name, dh);
return dh;
}
void DataContainer::addDataHandle(const std::string& name, const DataHandle* dh) {
{
tbb::spin_mutex::scoped_lock lock(_localMutex);
std::map<std::string, const DataHandle*>::iterator it = _handles.lower_bound(name);
if (it != _handles.end() && it->first == name) {
......@@ -31,7 +32,9 @@ namespace TUMVis {
else {
_handles.insert(it, std::make_pair(name, dh));
}
}
DataHandle::addOwner(dh, this);
s_dataAdded(name, dh);
}
bool DataContainer::hasData(const std::string& name) const {
......
#ifndef DATACONTAINER_H__
#define DATACONTAINER_H__
#include "sigslot/sigslot.h"
#include "tbb/include/tbb/spin_mutex.h"
#include "core/datastructures/abstractdata.h"
#include "core/datastructures/datahandle.h"
#include "core/tools/observer.h"
#include <string>
#include <map>
namespace TUMVis {
/**
* A DataContainer manages instances of AbstractData and offers access to them via string identifiers (names/keys).
* Therefore, it stores them in DataHandles which take ownership of the AbstractData instance. Hence,
......@@ -41,7 +42,7 @@ namespace TUMVis {
/**
* Adds the given AbstractData instance \a data, accessible by the key \name, to this DataContainer.
* In doing so, the DataContainer (respectively the created DataHandle) takes ownership of \a data
* and will manage its lifetime. So don't even dare to delete \a data yourself!
* and will manage its lifetime. So don't even think about deleting \a data yourself!
*
* \param name Key for accessing the DataHandle within this DataContainer
* \param data DataHandle to add.
......@@ -86,6 +87,9 @@ namespace TUMVis {
template<typename T>
inline const T* getTypedData(const std::string& name) const;
sigslot::signal2<const std::string&, const DataHandle*> s_dataAdded;
private:
std::map<std::string, const DataHandle*> _handles;
mutable tbb::spin_mutex _localMutex;
......
......@@ -6,9 +6,10 @@ namespace TUMVis {
const std::string DataHandle::loggerCat_ = "TUMVis.core.datastructures.DataHandle";
DataHandle::DataHandle(const DataContainer* owner, AbstractData* data)
DataHandle::DataHandle(AbstractData* data, const DataContainer* owner /*= 0*/)
: _data(data)
{
if (owner != 0)
addOwner(this, owner);
}
......
......@@ -53,13 +53,13 @@ namespace TUMVis {
private:
/**
* Creates a new DataHandle for \a data and takes its ownership in terms of lifetime management.
* The DataContainer \a owner will automatically be added to the set of owners of this DataHandle, so
* it is NOT needed to call DataHandle::addOwner().
* If \a owner != 0, it will automatically be added to the set of owners of this DataHandle, so
* in this case it is NOT needed to call DataHandle::addOwner().
*
* \param owner Initial owner of this DataHandle (usually the DataContainer creating the handle)
* \param data AbstractData instance to manage
* \param owner Initial owner of this DataHandle, may be 0.
*/
DataHandle(const DataContainer* owner, AbstractData* data);
DataHandle(AbstractData* data, const DataContainer* owner = 0);
/**
* DO NOT USE - it is private on purpose!
......
......@@ -27,4 +27,15 @@ namespace TUMVis {
}
}
void AbstractPipeline::onNotify(const ProcessorObserverArgs& poa) {
// tbb::spin_mutex::scoped_lock lock(_localMutex);
// _invalidationLevel.setLevel(InvalidationLevel::INVALID_RESULT);
execute();
}
const DataContainer& AbstractPipeline::getDataContainer() const {
return _data;
}
}
......@@ -2,6 +2,9 @@
#define ABSTRACTPIPELINE_H__
#include "tgt/logmanager.h"
#include "tbb/include/tbb/spin_mutex.h"
#include "core/tools/observer.h"
#include "core/tools/invalidationlevel.h"
#include "core/datastructures/datacontainer.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/properties/propertycollection.h"
......@@ -14,7 +17,7 @@ namespace TUMVis {
* Abstract base class for TUMVis Pipelines.
*
*/
class AbstractPipeline {
class AbstractPipeline : public GenericObserver<ProcessorObserverArgs> {
public:
/**
* Creates a AbstractPipeline.
......@@ -40,16 +43,33 @@ namespace TUMVis {
virtual void execute() = 0;
/**
* Returns the PropertyCollection of this processor.
* Returns the PropertyCollection of this pipeline.
* \return _properties
*/
PropertyCollection& getPropertyCollection();
/**
* Returns the DataContainer of this pipeline
* \return _data
*/
const DataContainer& getDataContainer() const;
/**
* Gets called when one of the observed processors changed and thus notifies its observers.
* The default behaviour is just to set the invalidation level to invalid.
* \sa GenericObserver::onNotify, AbstractProcessor
* \param poa ProcessorObserverArgs ObserverArgument struct containing the emitting processor and its InvalidationLevel
*/
virtual void onNotify(const ProcessorObserverArgs& poa);
protected:
DataContainer _data; ///< DataContainer containing local working set of data for this Pipeline
std::vector<AbstractProcessor*> _processors; ///< List of all processors of this pipeline
PropertyCollection _properties; ///< PropertyCollection of this pipeline, put in here all properties you want to be publicly accessible
InvalidationLevel _invalidationLevel; ///< current invalidation level
tbb::spin_mutex _localMutex; ///< mutex for altering local members
static const std::string loggerCat_;
};
......
......@@ -7,21 +7,22 @@
namespace TUMVis {
const std::string VisualizationPipeline::loggerCat_ = "TUMVis.core.datastructures.VisualizationPipeline";
VisualizationPipeline::VisualizationPipeline(tgt::GLCanvas* canvas /*= 0*/)
VisualizationPipeline::VisualizationPipeline()
: AbstractPipeline()
, _canvas(0)
, _canvasSize("canvasSize", "Canvas Size", tgt::ivec2(128, 128))
, tgt::EventListener()
, _renderTargetSize("canvasSize", "Canvas Size", tgt::ivec2(128, 128))
, _renderTargetID("renderTargetID", "Render Target ID", "VisualizationPipeline.renderTarget")
{
setCanvas(canvas);
_data.s_dataAdded.connect(this, &VisualizationPipeline::onDataContainerDataAdded);
}
VisualizationPipeline::~VisualizationPipeline() {
_data.s_dataAdded.disconnect(this);
}
void VisualizationPipeline::onEvent(tgt::Event* e) {
// cycle through event handlers, ask each one if it handles the event and if so, execute it.
for (std::vector<AbstractEventHandler*>::iterator it = _eventHandlers.begin(); it != _eventHandlers.end() && !e->isAccepted(); ++it) {
for (std::vector<AbstractEventHandler*>::iterator it = _eventHandlers.begin(); it != _eventHandlers.end() && e->isAccepted(); ++it) {
if ((*it)->accept(e)) {
(*it)->execute(e);
}
......@@ -32,107 +33,30 @@ namespace TUMVis {
}
}
void VisualizationPipeline::setCanvas(tgt::GLCanvas* canvas) {
if (_canvas != 0 && _canvas->getEventHandler() != 0) {
_canvas->getEventHandler()->removeListener(this);
}
_canvas = canvas;
_canvasSize.setValue(_canvas->getSize());
if (_canvas->getEventHandler() != 0) {
_canvas->getEventHandler()->addListenerToFront(this);
}
}
PropertyCollection& VisualizationPipeline::getPropertyCollection() {
return _properties;
}
void VisualizationPipeline::init() {
AbstractPipeline::init();
try {
// TODO: Remove hardcoded paths, and use ShdrMgr.addPath() at some central location
_copyShader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/copyimage.frag", "", false);
}
catch (tgt::Exception& e) {
LERRORC("main.cpp", "Encountered tgt::Exception: " << e.what());
}
}
void VisualizationPipeline::paint() {
execute();
if (_canvas == 0)
return;
// get OpenGL focus and setup context
_canvas->getGLFocus();
glViewport(0, 0, _canvas->getSize().x, _canvas->getSize().y);
// try get Data
const ImageDataRenderTarget* image = _data.getTypedData<ImageDataRenderTarget>(_renderTargetID.getValue());
if (image != 0) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// activate shader
_copyShader->activate();
_copyShader->setIgnoreUniformLocationError(true);
_copyShader->setUniform("_viewportSize", tgt::vec2(_canvasSize.getValue()));
_copyShader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(_canvasSize.getValue()));
_copyShader->setIgnoreUniformLocationError(false);
// bind input textures
tgt::TextureUnit colorUnit, depthUnit;
image->bind(_copyShader, colorUnit, depthUnit);
LGL_ERROR;
// execute the shader
tgt::QuadRenderer::renderQuad();
_copyShader->deactivate();
LGL_ERROR;
const tgt::ivec2& VisualizationPipeline::getRenderTargetSize() const {
return _renderTargetSize.getValue();
}
else {
// TODO: render some nifty error texture
// so long, we do some dummy rendering
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
getCamera()->setPosition(tgt::vec3(0.f,0.f,2.f));
getCamera()->look();
glColor3f(1.f, 0.f, 0.f);
tgt::Sphere sphere(.5f, 64, 32);
sphere.render();
/*
// render error texture
if (!errorTex_) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return;
void VisualizationPipeline::onDataContainerDataAdded(const std::string& name, const DataHandle* dh) {
if (name == _renderTargetID.getValue()) {
s_renderTargetChanged();
}
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
errorTex_->bind();
errorTex_->enable();
glColor3f(1.f, 1.f, 1.f);
renderQuad();
errorTex_->disable();*/
}
LGL_ERROR;
}
void VisualizationPipeline::sizeChanged(const tgt::ivec2& size) {
// nothing to change if nothing changes
if (size != _canvasSize.getValue()) {
_canvasSize.setValue(size);
// this should be enough here: Changing the property issues a notification of the
// owner (i.e. this pipeline), who is then up to decide how to proceed.
}
const ImageDataRenderTarget* VisualizationPipeline::getRenderTarget() const {
return _data.getTypedData<ImageDataRenderTarget>(_renderTargetID.getValue());
}
const tgt::ivec2& VisualizationPipeline::getCanvasSize() const {
return _canvasSize.getValue();
void VisualizationPipeline::setRenderTargetSize(const tgt::ivec2& size) {
_renderTargetSize.setValue(size);
}
}
#ifndef VISUALIZATIONPIPELINE_H__
#define VISUALIZATIONPIPELINE_H__
#include "sigslot/sigslot.h"
#include "tgt/glcanvas.h"
#include "tgt/painter.h"
#include "tgt/shadermanager.h"
......@@ -12,17 +13,18 @@
#include <vector>
namespace TUMVis {
class ImageDataRenderTarget;
/**
* Abstract base class for TUMVis Pipelines.
*
*/
class VisualizationPipeline : public AbstractPipeline, public tgt::EventListener, public tgt::Painter {
class VisualizationPipeline : public AbstractPipeline, public tgt::EventListener, public sigslot::has_slots<> {
public:
/**
* Creates a VisualizationPipeline.
*/
VisualizationPipeline(tgt::GLCanvas* canvas = 0);
VisualizationPipeline();
/**
* Virtual Destructor
......@@ -49,40 +51,47 @@ namespace TUMVis {
virtual void onEvent(tgt::Event* e);
/**
* Acquires the OpenGL context, and executes the pipeline
* Returns the PropertyCollection of this processor.
* \return _properties
*/
virtual void paint();
PropertyCollection& getPropertyCollection();
/**
* Is called when the viewport dimensions change, notifies the pipeline of that.
* Sets the size of the render target
* \param size New viewport dimensions