Commit 5ea6ef24 authored by schultezub's avatar schultezub

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);
......@@ -35,14 +38,14 @@ int main(int argc, char** argv) {
}
tgt::Camera camera;
canvas->setCamera(&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
// Some Dummy rendering:
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
getCamera()->look();
glColor3f(1.f, 0.f, 0.f);
tgt::Sphere sphere(.5f, 64, 32);
sphere.render();
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);
// 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);
}
else {
LWARNING("initialize(): No canvas");
catch (tgt::Exception& e) {
LERRORC("main.cpp", "Encountered tgt::Exception: " << e.what());
}
}
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();
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,22 +16,25 @@ 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) {
DataHandle::removeOwner(it->second, this);
it->second = dh;
}
else {
_handles.insert(it, std::make_pair(name, 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) {
DataHandle::removeOwner(it->second, this);
it->second = dh;
}
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,10 +6,11 @@ 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)
{
addOwner(this, owner);
if (owner != 0)
addOwner(this, owner);
}
DataHandle::~DataHandle() {
......
......@@ -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!
......
#include "mwheeltonumericpropertyeventhandler.h"
#include "tgt/assert.h"
#include "tgt/event/mouseevent.h"
#include "tgt/event/mouseevent.h"
namespace TUMVis {
const std::string MWheelToNumericPropertyEventHandler::loggerCat_ = "TUMVis.core.eventhandler.MWheelToNumericPropertyEventHandler";
......
......@@ -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;
}
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();
const tgt::ivec2& VisualizationPipeline::getRenderTargetSize() const {
return _renderTargetSize.getValue();
}
errorTex_->disable();*/
void VisualizationPipeline::onDataContainerDataAdded(const std::string& name, const DataHandle* dh) {
if (name == _renderTargetID.getValue()) {
s_renderTargetChanged();
}
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 {