Commit d9f37c2b authored by schultezub's avatar schultezub

* Introduced RaycastingProcessor as common super class for ray casting processors

 * adapted SimpleRaycaster and DRRRaycaster
 * fixed TumVisApplication::deinit() using wrong OpenGL context for deinitialization

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@227 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 1d4fea74
......@@ -61,6 +61,9 @@ namespace TUMVis {
// create a local OpenGL context and init GL
_localContext = CtxtMgr.createContext("AppContext", "", tgt::ivec2(16, 16));
tgtAssert(_localContext != 0, "Could not create local OpenGL context");
tgt::GLContextScopedLock lock(_localContext->getContext());
tgt::initGL(featureset);
LGL_ERROR;
......@@ -96,18 +99,24 @@ namespace TUMVis {
void TumVisApplication::deinit() {
tgtAssert(_initialized, "Tried to deinitialize uninitialized TumVisApplication.");
// Deinit pipeline first
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
(*it)->deinit();
}
{
// Deinit everything OpenGL related using the local context.
tgt::GLContextScopedLock lock(_localContext->getContext());
// Now deinit painters:
for (std::vector< std::pair<VisualizationPipeline*, TumVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->deinit();
// 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<VisualizationPipeline*, TumVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->deinit();
}
// deinit OpenGL and tgt
tgt::deinitGL();
}
// deinit OpenGL and tgt
tgt::deinitGL();
tgt::QtContextManager::deinit();
tgt::deinit();
......
......@@ -138,7 +138,7 @@ namespace TUMVis {
}
if (depthTexUnit != 0) {
bindDepthTexture(*depthTexUnit);
shader->setUniform(depthTexUniform + "._texture", colorTexUnit->getUnitNumber());
shader->setUniform(depthTexUniform + "._texture", depthTexUnit->getUnitNumber());
shader->setUniform(depthTexUniform + "._size", tgt::vec2(_size.xy()));
shader->setUniform(depthTexUniform + "._sizeRCP", tgt::vec2(1.f) / tgt::vec2(_size.xy()));
}
......
......@@ -60,7 +60,7 @@ namespace TUMVis {
/**
* Deinitializes this processor.
* \note When overwriting this method, make sure to call the base class version first.
* \note When overwriting this method, make sure to call the base class version at the end.
*/
virtual void deinit();
......
#include "raycastingprocessor.h"
#include "tgt/logmanager.h"
#include "tgt/quadrenderer.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagedatagl.h"
#include "core/datastructures/imagedatarendertarget.h"
#include "core/datastructures/imagedataconverter.h"
#include "core/classification/simpletransferfunction.h"
namespace TUMVis {
const std::string RaycastingProcessor::loggerCat_ = "TUMVis.modules.vis.RaycastingProcessor";
RaycastingProcessor::RaycastingProcessor(GenericProperty<tgt::ivec2>& canvasSize, const std::string& fragmentShaderFileName, bool bindEntryExitDepthTextures)
: VisualizationProcessor(canvasSize)
, _sourceImageID("sourceImageID", "Input Image", "")
, _entryImageID("entryImageID", "Output Entry Points Image", "")
, _exitImageID("exitImageID", "Output Exit Points Image", "")
, _transferFunction("transferFunction", "Transfer Function", new SimpleTransferFunction(256))
, _samplingStepSize("samplingStepSize", "Sampling Step Size", .1f, 0.001f, 1.f)
, _jitterEntryPoints("jitterEntryPoints", "Jitter Entry Points", true)
, _fragmentShaderFilename(fragmentShaderFileName)
, _shader(0)
, _bindEntryExitDepthTextures(bindEntryExitDepthTextures)
{
addProperty(&_sourceImageID);
addProperty(&_entryImageID);
addProperty(&_exitImageID);
addProperty(&_transferFunction);
addProperty(&_samplingStepSize);
addProperty(&_jitterEntryPoints);
}
RaycastingProcessor::~RaycastingProcessor() {
}
void RaycastingProcessor::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", _fragmentShaderFilename, "", false);
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
void RaycastingProcessor::deinit() {
ShdrMgr.dispose(_shader);
_shader = 0;
VisualizationProcessor::deinit();
}
void RaycastingProcessor::process(DataContainer& data) {
DataContainer::ScopedTypedData<ImageDataGL> img(data, _sourceImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> entryPoints(data, _entryImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> exitPoints(data, _exitImageID.getValue());
if (img != 0 && entryPoints != 0 && exitPoints != 0) {
if (img->getDimensionality() == 3) {
if (_invalidationLevel.isInvalidShader()) {
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
glPushAttrib(GL_ALL_ATTRIB_BITS);
_shader->activate();
_shader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(_renderTargetSize.getValue()));
_shader->setUniform("_jitterEntryPoints", _jitterEntryPoints.getValue());
_shader->setUniform("_samplingStepSize", _samplingStepSize.getValue());
tgt::TextureUnit volumeUnit, entryUnit, exitUnit, tfUnit;
img->bind(_shader, volumeUnit, "_volume");
_transferFunction.getTF()->bind(_shader, tfUnit);
if (! _bindEntryExitDepthTextures) {
// FIXME: something is somehow wrong here - see DRRRaycaster...
entryPoints->bind(_shader, &entryUnit, 0, "_entryPoints");
exitPoints->bind(_shader, &exitUnit, 0, "_exitPoints");
processImpl(data);
}
else {
tgt::TextureUnit entryUnitDepth, exitUnitDepth;
entryPoints->bind(_shader, &entryUnit, &entryUnitDepth, "_entryPoints", "_entryPointsDepth");
exitPoints->bind(_shader, &exitUnit, &exitUnitDepth, "_exitPoints", "_exitPointsDepth");
processImpl(data);
}
_shader->deactivate();
tgt::TextureUnit::setZeroUnit();
glPopAttrib();
LGL_ERROR;
}
else {
LERROR("Input image must have dimensionality of 3.");
}
}
else {
LERROR("No suitable input image found.");
}
_invalidationLevel.setValid();
}
std::string RaycastingProcessor::generateHeader() const {
std::string toReturn;
return toReturn;
}
}
#ifndef RAYCASTINGPROCESSOR_H__
#define RAYCASTINGPROCESSOR_H__
#include <string>
#include "core/pipeline/visualizationprocessor.h"
#include "core/properties/genericproperty.h"
#include "core/properties/numericproperty.h"
#include "core/properties/transferfunctionproperty.h"
namespace tgt {
class Shader;
}
namespace TUMVis {
/**
* Base class for raycasting processors.
* Offfers properties various common properties and automatic shader loading/linking.
*
* \note The intended way to use this class is to inherit from it, add additional properties if necessary
* and implement the processImpl() method which will be called by RaycastingProcessor::process()
* after successful validation of the incoming images.
* Of course you can also directly overwrite process() yourself, but then you will need to to the
* sanity checks yourself.
*/
class RaycastingProcessor : public VisualizationProcessor {
public:
/**
* Creates a RaycastingProcessor.
* \note The render target size property of this RaycastingProcessor will automatically
* be assigned as shared property of the given \a renderTargetSize property.
* \see VisualizationProcessor
* \param renderTargetSize Reference to the parent pipeline's render target size property.
* \param fragmentShaderFileName Filename for the fragment shader being automatically loaded.
* \param bindEntryExitDepthTextures Flag whether to also bind the depth textures of the entry-/exit points.
*/
RaycastingProcessor(GenericProperty<tgt::ivec2>& canvasSize, const std::string& fragmentShaderFileName, bool bindEntryExitDepthTextures);
/**
* Destructor
**/
virtual ~RaycastingProcessor();
/**
* Initalizes the Processor, loads and builds the shader.
* \see AbstractProcessor::init
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void init();
/**
* Disposes the shader and deinitializes the processor.
* \see AbstractProcessor::deinit
* \note When overwriting this method, make sure to call the base class version at the end.
*/
virtual void deinit();
/**
* Performs sanity checks, sets up the rendering and calls RaycastingProcessor::processImpl().
* This method first reads the input image, entry and exit points from \a data and validates them. On sucess
* the shader will be rebuild if necessary, the shader will be activated, common uniforms will be set and
* the textures and transfer function will be bound before calling processImpl().
*
* \sa RaycastingProcessor::processImpl()
* \param data DataContainer to work on.
*/
virtual void process(DataContainer& data);
GenericProperty<std::string> _sourceImageID; ///< image ID for input image
GenericProperty<std::string> _entryImageID; ///< image ID for output entry points image
GenericProperty<std::string> _exitImageID; ///< image ID for output exit points image
TransferFunctionProperty _transferFunction; ///< Transfer function
FloatProperty _samplingStepSize; ///< Ray casting step size
BoolProperty _jitterEntryPoints; ///< Flag whether to jitter the entry points
protected:
/**
* Gets called by RaycastingProcessor::process().
* Put additional (processor specific) setup code here, create and activate your render target(s), render
* your quad and store your results in \a data.
*
* \sa RaycastingProcessor::process()
* \param data DataContainer to work on.
*/
virtual void processImpl(DataContainer& data) = 0;
/**
* Returns an additional header that will be linked into the fragment shader.
* Gets calles when building \a _shader. Overwrite this method to add a processor specific header to
* your fragment shader.
* \note When overwriting this method make sure to call the base class version and append its result.
* \return The current default implementation returns an empty string.
*/
virtual std::string generateHeader() const;
const std::string _fragmentShaderFilename; ///< Filename for the fragment shader being automatically loaded.
tgt::Shader* _shader; ///< Shader for raycasting
bool _bindEntryExitDepthTextures; ///< Flag whether to also bind the depth textures of the entry-/exit points.
static const std::string loggerCat_;
};
}
#endif // RAYCASTINGPROCESSOR_H__
......@@ -41,14 +41,10 @@ namespace TUMVis {
}
void VisualizationPipeline::init() {
tgtAssert(_canvas != 0, "Set a valid canvas before calling this method!");
tgt::GLContextScopedLock lock(_canvas->getContext());
AbstractPipeline::init();
}
void VisualizationPipeline::deinit() {
tgtAssert(_canvas != 0, "Set a valid canvas before calling this method!");
tgt::GLContextScopedLock lock(_canvas->getContext());
AbstractPipeline::deinit();
}
......
......@@ -36,13 +36,14 @@ namespace TUMVis {
/**
* Initializes the OpenGL context of the pipeline and its processors.
* Pipeline must have a valid canvas set before calling this method.
* Must be called with a valid and locked OpenGL context.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void init();
/**
* Deinitializes this pipeline and all of its processors.
* Must be called with a valid and locked OpenGL context.
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void deinit();
......
#include "drrraycaster.h"
#include "tgt/logmanager.h"
#include "tgt/quadrenderer.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagedatagl.h"
#include "core/datastructures/imagedatarendertarget.h"
#include "core/datastructures/imagedataconverter.h"
#include "core/classification/simpletransferfunction.h"
namespace TUMVis {
const std::string DRRRaycaster::loggerCat_ = "TUMVis.modules.vis.DRRRaycaster";
DRRRaycaster::DRRRaycaster(GenericProperty<tgt::ivec2>& canvasSize)
: VisualizationProcessor(canvasSize)
, _sourceImageID("sourceImageID", "Input Image", "")
, _entryImageID("entryImageID", "Output Entry Points Image", "")
, _exitImageID("exitImageID", "Output Exit Points Image", "")
: RaycastingProcessor(canvasSize, "modules/vis/drrraycaster.frag", true) // FIXME: the last parameter should be false, but it results in a wrong rendering
, _targetImageID("targetImageID", "Output Image", "")
, _transferFunction("transferFunction", "Transfer Function", new SimpleTransferFunction(256))
, _samplingStepSize("samplingStepSize", "Sampling Step Size", .1f, 0.001f, 1.f)
, _shift("shift", "Normalization Shift", 0.f, -10.f, 10.f)
, _scale("scale", "Normalization Scale", 1.f, 0.f, 1000.f)
, _invertMapping("invertMapping", "Invert Mapping", false, InvalidationLevel::INVALID_RESULT | InvalidationLevel::INVALID_SHADER)
, _jitterEntryPoints("jitterEntryPoints", "Jitter Entry Points", true)
, _shader(0)
{
addProperty(&_sourceImageID);
addProperty(&_entryImageID);
addProperty(&_exitImageID);
addProperty(&_targetImageID);
addProperty(&_transferFunction);
addProperty(&_samplingStepSize);
addProperty(&_shift);
addProperty(&_scale);
addProperty(&_invertMapping);
addProperty(&_jitterEntryPoints);
}
DRRRaycaster::~DRRRaycaster() {
}
void DRRRaycaster::init() {
VisualizationProcessor::init();
// _shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/copyimage.frag", "", false);
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/drrraycaster.frag", "", false);
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
void DRRRaycaster::deinit() {
ShdrMgr.dispose(_shader);
_shader = 0;
VisualizationProcessor::deinit();
}
void DRRRaycaster::process(DataContainer& data) {
DataContainer::ScopedTypedData<ImageDataGL> img(data, _sourceImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> entryPoints(data, _entryImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> exitPoints(data, _exitImageID.getValue());
if (img != 0 && entryPoints != 0 && exitPoints != 0) {
if (img->getDimensionality() == 3) {
if (_invalidationLevel.isInvalidShader()) {
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_renderTargetSize.getValue(), 1));
void DRRRaycaster::processImpl(DataContainer& data) {
_shader->setUniform("_shift", _shift.getValue());
_shader->setUniform("_scale", _scale.getValue());
glPushAttrib(GL_ALL_ATTRIB_BITS);
_shader->activate();
_shader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(_renderTargetSize.getValue()));
_shader->setUniform("_jitterEntryPoints", _jitterEntryPoints.getValue());
_shader->setUniform("_samplingStepSize", _samplingStepSize.getValue());
_shader->setUniform("_shift", _shift.getValue());
_shader->setUniform("_scale", _scale.getValue());
ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_renderTargetSize.getValue(), 1));
rt->activate();
tgt::TextureUnit volumeUnit, entryUnit, exitUnit, tfUnit;
img->bind(_shader, volumeUnit, "_volume");
entryPoints->bind(_shader, &entryUnit, 0, "_entryPoints");
exitPoints->bind(_shader, &exitUnit, 0, "_exitPoints");
_transferFunction.getTF()->bind(_shader, tfUnit);
rt->activate();
if (_invertMapping.getValue())
glClearColor(0.f, 0.f, 0.f, 1.f);
else
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LGL_ERROR;
tgt::QuadRenderer::renderQuad();
LGL_ERROR;
rt->deactivate();
_shader->deactivate();
tgt::TextureUnit::setZeroUnit();
glPopAttrib();
data.addData(_targetImageID.getValue(), rt);
}
else {
LERROR("Input image must have dimensionality of 3.");
}
}
else {
LERROR("No suitable input image found.");
}
_invalidationLevel.setValid();
if (_invertMapping.getValue())
glClearColor(0.f, 0.f, 0.f, 1.f);
else
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
tgt::QuadRenderer::renderQuad();
LGL_ERROR;
rt->deactivate();
data.addData(_targetImageID.getValue(), rt);
}
std::string DRRRaycaster::generateHeader() const {
......@@ -121,10 +47,9 @@ namespace TUMVis {
if (_invertMapping.getValue())
toReturn += "#define DRR_INVERT 1\n";
// if (depthMapping_.get())
// header +="#define DEPTH_MAPPING 1\n";
// if (depthMapping_.get())
// header +="#define DEPTH_MAPPING 1\n";
return toReturn;
}
}
......@@ -3,7 +3,7 @@
#include <string>
#include "core/pipeline/visualizationprocessor.h"
#include "core/pipeline/raycastingprocessor.h"
#include "core/properties/genericproperty.h"
#include "core/properties/numericproperty.h"
#include "core/properties/transferfunctionproperty.h"
......@@ -18,7 +18,7 @@ namespace TUMVis {
/**
* Creates a Digitally Reconstructed Radiograph.
*/
class DRRRaycaster : public VisualizationProcessor {
class DRRRaycaster : public RaycastingProcessor {
public:
/**
* Constructs a new DRRRaycaster Processor
......@@ -30,35 +30,26 @@ namespace TUMVis {
**/
virtual ~DRRRaycaster();
/// \see AbstractProcessor::init
virtual void init();
/// \see AbstractProcessor::deinit
virtual void deinit();
/// \see AbstractProcessor::getName()
virtual const std::string getName() const { return "DRRRaycaster"; };
/// \see AbstractProcessor::getDescription()
virtual const std::string getDescription() const { return "Creates a Digitally Reconstructed Radiograph."; };
virtual void process(DataContainer& data);
GenericProperty<std::string> _sourceImageID; ///< image ID for input image
GenericProperty<std::string> _entryImageID; ///< image ID for output entry points image
GenericProperty<std::string> _exitImageID; ///< image ID for output exit points image
GenericProperty<std::string> _targetImageID; ///< image ID for output image
TransferFunctionProperty _transferFunction; ///< Transfer function
FloatProperty _samplingStepSize;
FloatProperty _shift;
FloatProperty _scale;
BoolProperty _invertMapping;
BoolProperty _jitterEntryPoints;
protected:
std::string generateHeader() const;
/// \see RaycastingProcessor::processImpl()
virtual void processImpl(DataContainer& data);
tgt::Shader* _shader; ///< Shader for DRR rendering
/**
* \see RaycastingProcessor::generateHeader()
* \return "#define DRR_INVERT 1" if \a _invertMapping is set to true.
*/
virtual std::string generateHeader() const;
static const std::string loggerCat_;
};
......
#include "simpleraycaster.h"
#include "tgt/logmanager.h"
#include "tgt/quadrenderer.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagedatagl.h"
#include "core/datastructures/imagedatarendertarget.h"
#include "core/datastructures/imagedataconverter.h"
#include "core/classification/simpletransferfunction.h"
namespace TUMVis {
const std::string SimpleRaycaster::loggerCat_ = "TUMVis.modules.vis.SimpleRaycaster";
SimpleRaycaster::SimpleRaycaster(GenericProperty<tgt::ivec2>& canvasSize)
: VisualizationProcessor(canvasSize)
, _sourceImageID("sourceImageID", "Input Image", "")
, _entryImageID("entryImageID", "Output Entry Points Image", "")
, _exitImageID("exitImageID", "Output Exit Points Image", "")
: RaycastingProcessor(canvasSize, "modules/vis/simpleraycaster.frag", true)
, _targetImageID("targetImageID", "Output Image", "")
, _transferFunction("transferFunction", "Transfer Function", new SimpleTransferFunction(256))
, _samplingStepSize("samplingStepSize", "Sampling Step Size", .1f, 0.001f, 1.f)
, _jitterEntryPoints("jitterEntryPoints", "Jitter Entry Points", true)
, _shader(0)
{
addProperty(&_sourceImageID);
addProperty(&_entryImageID);
addProperty(&_exitImageID);
addProperty(&_targetImageID);
addProperty(&_transferFunction);
addProperty(&_samplingStepSize);
addProperty(&_jitterEntryPoints);
}
SimpleRaycaster::~SimpleRaycaster() {
}
void SimpleRaycaster::init() {
VisualizationProcessor::init();
_shader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/simpleraycaster.frag", "", false);
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
void SimpleRaycaster::deinit() {
ShdrMgr.dispose(_shader);
_shader = 0;
VisualizationProcessor::deinit();
}
void SimpleRaycaster::process(DataContainer& data) {
DataContainer::ScopedTypedData<ImageDataGL> img(data, _sourceImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> entryPoints(data, _entryImageID.getValue());
DataContainer::ScopedTypedData<ImageDataRenderTarget> exitPoints(data, _exitImageID.getValue());
if (img != 0 && entryPoints != 0 && exitPoints != 0) {
if (img->getDimensionality() == 3) {
if (_invalidationLevel.isInvalidShader()) {
_shader->setHeaders(generateHeader());
_shader->rebuild();
}
ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_renderTargetSize.getValue(), 1));
glPushAttrib(GL_ALL_ATTRIB_BITS);
_shader->activate();
_shader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(_renderTargetSize.getValue()));
_shader->setUniform("_jitterEntryPoints", _jitterEntryPoints.getValue());
_shader->setUniform("_samplingStepSize", _samplingStepSize.getValue());
void SimpleRaycaster::processImpl(DataContainer& data) {
ImageDataRenderTarget* rt = new ImageDataRenderTarget(tgt::svec3(_renderTargetSize.getValue(), 1));
rt->activate();
tgt::TextureUnit volumeUnit, entryUnit, entryUnitDepth, exitUnit, exitUnitDepth, tfUnit;
img->bind(_shader, volumeUnit, "_volume");
entryPoints->bind(_shader, &entryUnit, &entryUnitDepth, "_entryPoints", "_entryPointsDepth");
exitPoints->bind(_shader, &exitUnit, &exitUnitDepth, "_exitPoints", "_exitPointsDepth");
_transferFunction.getTF()->bind(_shader, tfUnit);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
tgt::QuadRenderer::renderQuad();
LGL_ERROR;
rt->activate();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LGL_ERROR;
tgt::QuadRenderer::renderQuad();
LGL_ERROR;
rt->deactivate();
_shader->deactivate();
tgt::TextureUnit::setZeroUnit();
glPopAttrib();
data.addData(_targetImageID.getValue(), rt);