Commit 18a150aa authored by schultezub's avatar schultezub
Browse files

* added ImageDataRenderTarget

 * added some initial GLSL shaders
 * work on VisualizationPipeline
 * added SliceVis pipeline stub and SliceExtractor processor stub

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@185 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent fc9111ee
......@@ -3,6 +3,8 @@
#include "tgt/qt/qtcanvas.h"
#include "tumvispainter.h"
#include "modules/pipelines/slicevis.h"
using namespace TUMVis;
......@@ -23,6 +25,9 @@ int main(int argc, char** argv) {
tgt::Camera camera;
canvas->setCamera(&camera);
//SliceVis sliceVis(canvas);
//canvas->setPainter(&sliceVis);
TumVisPainter painter(canvas);
canvas->setPainter(&painter);
......
......@@ -14,7 +14,7 @@ namespace TUMVis {
*/
class AbstractData {
public:
AbstractData();
AbstractData() {};
virtual ~AbstractData() {};
virtual AbstractData* clone() const = 0;
......
......@@ -75,6 +75,17 @@ namespace TUMVis {
*/
const DataHandle* getData(const std::string& name) const;
/**
* Get the DataHandle with the given name from this container and tries to dynamic_cast it to const T*.
* If no such DataHandle exists or the dynamic_cast fails, this method returns 0.
*
* \param name Key of the DataHandle to search for
* \tparam T Target type of data for dynamic_cast.
* \return The stored DataHandle with the given name, casted to const T*, 0 if no such DataHandle exists or conversion failed.
*/
template<typename T>
inline const T* getTypedData(const std::string& name) const;
private:
std::map<std::string, const DataHandle*> _handles;
mutable tbb::spin_mutex _localMutex;
......@@ -82,6 +93,12 @@ namespace TUMVis {
static const std::string loggerCat_;
};
template<typename T>
const T* TUMVis::DataContainer::getTypedData(const std::string& name) const {
const DataHandle* dh = getData(name);
return dynamic_cast<const T*>(dh);
}
}
#endif // DATACONTAINER_H__
......@@ -4,7 +4,8 @@ namespace TUMVis {
const std::string ImageData::loggerCat_ = "TUMVis.core.datastructures.ImageData";
ImageData::ImageData(size_t dimensionality, const tgt::svec3& size)
: _dimensionality(dimensionality)
: AbstractData()
, _dimensionality(dimensionality)
, _size(size)
, _numElements(tgt::hmul(size))
{
......
#include "imagedatarendertarget.h"
#include "tgt/assert.h"
#include "tgt/gpucapabilities.h"
#include "tgt/logmanager.h"
#include "tgt/shadermanager.h"
#include "tgt/tgt_gl.h"
namespace TUMVis {
const std::string ImageDataRenderTarget::loggerCat_ = "TUMVis.core.datastructures.ImageDataRenderTarget";
ImageDataRenderTarget::ImageDataRenderTarget(const tgt::svec3& size, GLint internalFormatColor /*= GL_RGBA8*/, GLint internalFormatDepth /*= GL_DEPTH_COMPONENT24*/)
: ImageData(2, size)
, _colorTexture(0)
, _depthTexture(0)
, _fbo(0)
{
tgtAssert(size.z == 1, "RenderTargets are only two-dimensional, expected size.z == 1.");
initRenderTarget(internalFormatColor, internalFormatDepth);
tgtAssert(_colorTexture != 0, "Color texture is 0, something went terribly wrong...");
tgtAssert(_depthTexture != 0, "Depth texture is 0, something went terribly wrong...");
tgtAssert(_fbo != 0, "Framebuffer object is 0, something went terribly wrong...");
}
ImageDataRenderTarget::~ImageDataRenderTarget() {
delete _fbo;
delete _colorTexture;
delete _depthTexture;
}
void ImageDataRenderTarget::initRenderTarget(GLint internalFormatColor, GLint internalFormatDepth) {
if (!GpuCaps.isNpotSupported() && !GpuCaps.areTextureRectanglesSupported()) {
LWARNING("Neither non-power-of-two textures nor texture rectangles seem to be supported!");
}
switch(internalFormatColor) {
case GL_RGB:
_colorTexture = new tgt::Texture(0, _size, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tgt::Texture::LINEAR);
break;
case GL_RGBA:
_colorTexture = new tgt::Texture(0, _size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tgt::Texture::LINEAR);
break;
case GL_RGBA16:
_colorTexture = new tgt::Texture(0, _size, GL_RGBA, GL_RGBA16, GL_UNSIGNED_SHORT, tgt::Texture::LINEAR);
break;
case GL_RGB16F_ARB:
_colorTexture = new tgt::Texture(0, _size, GL_RGB, GL_RGB16F_ARB, GL_FLOAT, tgt::Texture::LINEAR);
break;
case GL_RGBA16F_ARB:
_colorTexture = new tgt::Texture(0, _size, GL_RGBA, GL_RGBA16F_ARB, GL_FLOAT, tgt::Texture::LINEAR);
break;
case GL_RGBA32F_ARB:
_colorTexture = new tgt::Texture(0, _size, GL_RGBA, GL_RGBA32F_ARB, GL_FLOAT, tgt::Texture::LINEAR);
break;
default:
LERROR("Unknown internal format!");
}
_colorTexture->uploadTexture();
_colorTexture->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
switch(internalFormatDepth) {
case GL_DEPTH_COMPONENT16:
_depthTexture = new tgt::Texture(0, _size, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_FLOAT, tgt::Texture::LINEAR);
break;
case GL_DEPTH_COMPONENT24:
_depthTexture = new tgt::Texture(0, _size, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24, GL_FLOAT, tgt::Texture::LINEAR);
break;
case GL_DEPTH_COMPONENT32:
_depthTexture = new tgt::Texture(0, _size, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT32, GL_FLOAT, tgt::Texture::LINEAR);
break;
#ifdef GL_DEPTH_COMPONENT32F
case GL_DEPTH_COMPONENT32F:
_depthTexture = new tgt::Texture(0, _size, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT32F, GL_FLOAT, tgt::Texture::LINEAR);
break;
#endif
default:
LERROR("Unknown internal depth format!");
}
_depthTexture->uploadTexture();
_depthTexture->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
_fbo = new tgt::FramebufferObject();
if (!_fbo) {
LERROR("Failed to initialize framebuffer object!");
return;
}
_fbo->activate();
_fbo->attachTexture(_colorTexture);
_fbo->isComplete();
_fbo->attachTexture(_depthTexture, GL_DEPTH_ATTACHMENT_EXT);
_fbo->isComplete();
_fbo->deactivate();
}
void ImageDataRenderTarget::activate() {
_fbo->activate();
glViewport(0, 0, _size.x, _size.y);
}
void ImageDataRenderTarget::deactivate() {
_fbo->deactivate();
}
void ImageDataRenderTarget::bindColorTexture() const {
_colorTexture->bind();
}
void ImageDataRenderTarget::bindColorTexture(GLint texUnit) const {
glActiveTexture(texUnit);
_colorTexture->bind();
}
void ImageDataRenderTarget::bindDepthTexture() const {
_depthTexture->bind();
}
void ImageDataRenderTarget::bindDepthTexture(GLint texUnit) const {
glActiveTexture(texUnit);
_depthTexture->bind();
}
void ImageDataRenderTarget::bind(tgt::Shader* shader, GLint colorTexUnit /*= GL_TEXTURE0*/, GLint depthTexUnit /*= GL_TEXTURE1*/, const std::string& colorTexUniform /*= "_colorTexture"*/, const std::string& depthTexUniform /*= "_depthTexture"*/, const std::string& textureParametersUniform /*= "_textureParameters"*/) const {
bindColorTexture(colorTexUnit);
bindDepthTexture(depthTexUnit);
shader->setUniform(colorTexUniform, 0);
shader->setUniform(depthTexUniform, 1);
shader->setUniform(textureParametersUniform + "._size", tgt::vec2(_size.xy()));
shader->setUniform(textureParametersUniform + "._sizeRCP", tgt::vec2(1.f) / tgt::vec2(_size.xy()));
}
ImageDataRenderTarget* ImageDataRenderTarget::clone() const {
tgtAssert(false, "To be implemented!");
return 0;
}
ImageDataRenderTarget* ImageDataRenderTarget::getSubImage(const tgt::svec3& llf, const tgt::svec3& urb) const {
tgtAssert(false, "To be implemented!");
return 0;
}
}
\ No newline at end of file
#ifndef IMAGEDATARENDERTARGET_H__
#define IMAGEDATARENDERTARGET_H__
#include "tgt/framebufferobject.h"
#include "tgt/texture.h"
#include "tgt/vector.h"
#include "core/datastructures/imagedata.h"
namespace tgt {
class Shader;
}
namespace TUMVis {
/**
* Stores render target data.
* This is basically a wrapper for two OpenGL textures (color + depth) and their attachment to the framebuffer.
*
* \note Its dimensionality must be 2.
*
* \todo The constructor only asserts if one of the textures or the FBO weren't successfully created.
* The member functions don't double check, whether the pointers are != 0. Make sure, that this
* is a sane design and if not, adapt the code.
*/
class ImageDataRenderTarget : public ImageData {
public:
/**
* Creates a new ImageDataRenderTarget representation.
*
* \param size Size of this image (number of elements per dimension)
* \param internalFormatColor Internal OpenGL format for the color texture.
* \param internalFormatDepth Internal OpenGL format for the depth texture.
*/
ImageDataRenderTarget(const tgt::svec3& size, GLint internalFormatColor = GL_RGBA8, GLint internalFormatDepth = GL_DEPTH_COMPONENT24);
/**
* Destructor
*/
virtual ~ImageDataRenderTarget();
/**
* \see AbstractData::clone()
**/
virtual ImageDataRenderTarget* clone() const;
/**
* \see ImageData::getSubImage
*/
virtual ImageDataRenderTarget* getSubImage(const tgt::svec3& llf, const tgt::svec3& urb) const;
/**
* Activates the render target (binds the FBO and sets the viewport).
*/
void activate();
/**
* Deactivates the render target (unbinds the FBO).
*/
void deactivate();
/**
* Binds the color texture without activating a texture unit.
*/
void bindColorTexture() const;
/**
* Binds the depth texture without activating a texture unit.
*/
void bindDepthTexture() const;
/**
* Activates the texture unit \a texUnit and binds the color texture.
* \param texUnit Texture unit to activate
*/
void bindColorTexture(GLint texUnit) const;
/**
* Activates the texture unit \a texUnit and binds the depth texture.
* \param texUnit Texture unit to activate
*/
void bindDepthTexture(GLint texUnit) const;
void bind(
tgt::Shader* shader,
GLint colorTexUnit = GL_TEXTURE0,
GLint depthTexUnit = GL_TEXTURE1,
const std::string& colorTexUniform = "_colorTexture",
const std::string& depthTexUniform = "_depthTexture",
const std::string& textureParametersUniform = "_textureParameters") const;
protected:
/**
* Initializes the textures as well as the FBO.
* \param internalFormatColor Internal OpenGL format for the color texture.
* \param internalFormatDepth Internal OpenGL format for the depth texture.
*/
void initRenderTarget(GLint internalFormatColor, GLint internalFormatDepth);
tgt::Texture* _colorTexture; ///< color texture
tgt::Texture* _depthTexture; ///< depth texture
tgt::FramebufferObject* _fbo; ///< Framebuffer object coordinating color and depth texture
static const std::string loggerCat_;
};
}
#endif // IMAGEDATARENDERTARGET_H__
#include "tools/sampler2d.frag"
uniform sampler2D _colorTexture;
uniform sampler2D _depthTexture;
uniform TextureParameters _textureParameters;
void main() {
vec2 fragCoord = gl_FragCoord.xy * screenDimRCP_;
gl_FragData[0] = getElement2DNormalized(_colorTexture, _textureParameters, fragCoord);
gl_FragDepth = getElement2DNormalized(_depthTexture, _textureParameters, fragCoord).z;
}
void main() {
// just pass everything through to fragment shader.
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}
uniform _viewportSize;
uniform _viewportSizeRCP;
struct TextureParameters {
vec2 _size;
vec2 _sizeRCP;
};
// Texture lookup function for 2D textures,
// expecting texture coordinates as pixel coordinates, i.e, [(0,0) , textureSize].
vec4 getElement2D(in sampler2D myTexture, in TextureParameters texParams, in vec2 texCoords) {
vec2 texCoordsNormalized = texCoords * texParams.dimensionsRCP_;
vec2 texCoordsTransformed = (texParams.matrix_ * vec4(texCoordsNormalized, 0.0, 1.0)).xy;
return texture2D(myTexture, texCoordsTransformed);
}
// Texture lookup function for 2D textures,
// expecting normalized texture coordinates, i.e., [0,1].
vec4 getElement2DNormalized(in sampler2D myTexture, in TextureParameters texParams, in vec2 texCoords) {
vec2 texCoordsTransformed = (texParams.matrix_ * vec4(texCoords, 0.0, 1.0)).xy;
return texture2D(myTexture, texCoordsTransformed);
}
#include "visualizationpipeline.h"
#include "tgt/camera.h"
#include "tgt/quadric.h"
#include "core/datastructures/imagedatarendertarget.h"
namespace TUMVis {
const std::string VisualizationPipeline::loggerCat_ = "TUMVis.core.datastructures.VisualizationPipeline";
VisualizationPipeline::VisualizationPipeline(tgt::GLCanvas* canvas /*= 0*/)
: _canvas(canvas)
: AbstractPipeline()
, _canvas(canvas)
, _canvasSize("canvasSize", "Canvas Size", tgt::ivec2(128, 128))
, _renderTargetID("renderTargetID", "Render Target ID", "VisualizationPipeline.renderTarget")
{
}
......@@ -36,24 +42,75 @@ namespace TUMVis {
void VisualizationPipeline::init() {
AbstractPipeline::init();
// initialize all processors:
// for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
// (*it)->initGL();
// }
// TODO: Remove hardcoded paths, and use ShdrMgr.addPath() at some central location
_copyShader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "core/glsl/copyimage.frag", "", false);
}
void VisualizationPipeline::paint() {
// TODO: implement - is there a generic way to initiate the painting in the subclasses?
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->setUniform("_viewportSize", tgt::vec2(_canvasSize.getValue()));
_copyShader->setUniform("_viewportSizeRCP", 1.f / tgt::vec2(_canvasSize.getValue()));
// bind input textures
image->bind(_copyShader);
LGL_ERROR;
// execute the shader
//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()->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;
}
void VisualizationPipeline::sizeChanged(const tgt::ivec2& size) {
// nothing to change if nothing changes
if (size != _canvasSize) {
_canvasSize = size;
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.
}
// TODO: initiate pipeline evaluation, is a simple execute() what we want?
execute();
}
}
......@@ -3,9 +3,11 @@
#include "tgt/glcanvas.h"
#include "tgt/painter.h"
#include "tgt/shadermanager.h"
#include "tgt/event/eventlistener.h"
#include "core/eventhandlers/abstracteventhandler.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/properties/genericproperty.h"
#include <vector>
......@@ -30,7 +32,6 @@ namespace TUMVis {
/**
* Initializes the OpenGL context of the pipeline and its processors.
* \todo merge with init() ?
* \note When overwriting this method, make sure to call the base class version first.
*/
virtual void init();
......@@ -71,13 +72,12 @@ namespace TUMVis {
PropertyCollection& getPropertyCollection();
protected:
DataContainer _data; ///< DataContainer containing local working set of data for this Pipeline
tgt::GLCanvas* _canvas; ///< Target canvas for rendering
tgt::ivec2 _canvasSize; ///< Viewport size of target canvas
GenericProperty<tgt::ivec2> _canvasSize; ///< Viewport size of target canvas
GenericProperty<std::string> _renderTargetID; ///< ID of the render target image to be rendered to the canvas
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer.
std::vector<AbstractEventHandler*> _eventHandlers; ///< List of registered event handlers for the 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
static const std::string loggerCat_;
};
......
......@@ -8,6 +8,7 @@ namespace TUMVis {
: _name(name)
, _title(title)
, _invalidationLevel(il)
, _inUse(false)
{
}
......@@ -43,4 +44,15 @@ namespace TUMVis {
const std::set<AbstractProperty*>& AbstractProperty::getSharedProperties() const {
return _sharedProperties;
}
void AbstractProperty::lock() {
tbb::spin_mutex::scoped_lock lock(_localMutex);
_inUse = true;
}
void AbstractProperty::unlock() {
tbb::spin_mutex::scoped_lock lock(_localMutex);
_inUse = false;
}
}
#ifndef ABSTRACTPROPERTY_H__
#define ABSTRACTPROPERTY_H__
#include "tbb/include/tbb/spin_mutex.h"
#include "tgt/logmanager.h"
#include "core/tools/invalidationlevel.h"
#include "core/tools/observer.h"
......@@ -103,12 +104,28 @@ namespace TUMVis {
const std::set<AbstractProperty*>& getSharedProperties() const;
/**
* Locks the property and marks it as "in use". Overwrite if necessary.
* \sa AbstractProperty::unlock
*/
virtual void lock();
/**
* Unlocks the property and marks it as "not in use". Overwrite if necessary.
* \sa AbstractProperty::lock
*/
virtual void unlock();
protected:
// DO NOT REMOVE THE CONSTNESS OF _name. PropertyCollection relies on it!
const std::string _name; ///< Property name (unchangable on purpose!)
std::string _title; ///< Property title (e.g. used for GUI)
InvalidationLevel _invalidationLevel; ///< Invalidation level that this property triggers
bool _inUse; ///< flag whether property is currently in use and values are written to back buffer
tbb::spin_mutex _localMutex; ///< Mutex used when altering local members
/**
* List of shared properties that will be changed when this property changes.
* \note Property sharing only works in one direction, i.e. shared properties act as child properties.
......
......@@ -62,14 +62,14 @@ namespace TUMVis {
* the back buffer. The buffers will be swapped on unlocking the property.
* \sa GenericProperty::unlock
*/
void lock();
virtual void lock();
/**
* Unlocks the property. If the back buffer has changed, the changes will be written to the front
* buffer and all observers will be notified.
* \sa GenericProperty::lock
*/
void unlock();
virtual void unlock();
protected:
......@@ -90,9 +90,6 @@ namespace TUMVis {
T _value; ///< value of the property
T _backBuffer; ///< back buffer for values when property is in use
bool _inUse; ///< flag whether property is currently in use and values are written to back buffer
tbb::spin_mutex _localMutex; ///< Mutex used when altering local members