Commit 39eb232a authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge remote-tracking branch 'remotes/origin/DataInspector' into development

Conflicts:
	application/gui/datacontainerinspectorcanvas.cpp

+ some minor beautifications/fixes
parents 94e178dc e841360b
......@@ -26,3 +26,6 @@ moc_*.cxx_parameters
# Documentation generated by Doxygen
/doc/html/
/doc/Doxyfile
# TBB library in ext/
ext/tbb
......@@ -43,12 +43,17 @@
#include "core/classification/tfgeometry1d.h"
#include "core/classification/geometry1dtransferfunction.h"
#include "datacontainerinspectorwidget.h"
#include "ext/tgt/navigation/trackball.h"
namespace campvis {
DataContainerInspectorCanvas::DataContainerInspectorCanvas(QWidget* parent /*= 0*/)
: tgt::QtThreadedCanvas("DataContainer Inspector", tgt::ivec2(640, 480), tgt::GLCanvas::RGBA_BUFFER, parent, true)
, p_currentSlice("CurrentSlice", "Slice", -1, -1, -1)
, p_meshSolidColor("MeshSolidColor", "Mesh Solid Color", tgt::vec4(50.f, 70.0f, 50.0f, 255.f), tgt::vec4(0.0f), tgt::vec4(255.0f))
, p_transferFunction("TransferFunction", "Transfer Function", new Geometry1DTransferFunction(256, tgt::vec2(0.f, 1.f)))
, _dataContainer(0)
, _paintShader(0)
......@@ -58,6 +63,8 @@ namespace campvis {
, _selectedTexture(0)
, _renderFullscreen(false)
, _currentSlice(-1)
, _color(0.0f, 0.0f, 0.0f, 0.0f)
, _meshGeomTexturesDirty(false)
{
static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(tgt::vec2(0.f, 1.f), tgt::col4(0, 0, 0, 255), tgt::col4(255, 255, 255, 255)));
......@@ -70,20 +77,25 @@ namespace campvis {
std::cerr << "glewInit failed, error: " << glewGetErrorString(err) << std::endl;
exit(EXIT_FAILURE);
}
addProperty(&p_currentSlice);
addProperty(&p_transferFunction);
addProperty(&p_meshSolidColor);
}
DataContainerInspectorCanvas::~DataContainerInspectorCanvas() {
}
void DataContainerInspectorCanvas::init() {
void DataContainerInspectorCanvas::init(DataContainerInspectorWidget* _pWidget) {
initAllProperties();
_widget = _pWidget;
GLJobProc.registerContext(this);
_paintShader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "application/glsl/datacontainerinspector.frag", "", false);
_geometryRenderingShader = ShdrMgr.loadSeparate("core/glsl/passthrough.vert", "modules/vis/glsl/geometryrenderer.frag", "", false);
_paintShader->setAttributeLocation(0, "in_Position");
_paintShader->setAttributeLocation(1, "in_TexCoords");
......@@ -92,6 +104,9 @@ namespace campvis {
// set this as painter to get notified when window size changes
setPainter(this, false);
getEventHandler()->addEventListenerToFront(this);
_frameBuffer = new tgt::FramebufferObject();
_depthBuffer = new tgt::Texture(0, tgt::ivec3(width(), height(), 1), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24, GL_FLOAT, tgt::Texture::LINEAR); //, _renderingWndSize(tgt::ivec2(400, 100))
}
void DataContainerInspectorCanvas::deinit() {
......@@ -104,7 +119,39 @@ namespace campvis {
_handles.clear();
GLJobProc.deregisterContext(this);
ShdrMgr.dispose(_paintShader);
ShdrMgr.dispose(_geometryRenderingShader);
delete _quad;
delete _frameBuffer;
delete _depthBuffer;
resetContent();
}
void DataContainerInspectorCanvas::resetContent() {
/// Clear the textures Array and geometry textures indicies array
_textures.clear();
/// Clear the trackball navigation event listener array
/// - First delete the data that it contains
std::vector<TrackballNavigationEventListener*>::iterator trackballNavEHIterator = _trackballEHs.begin();
for(; trackballNavEHIterator != _trackballEHs.end(); trackballNavEHIterator++) {
delete (*trackballNavEHIterator);
}
_trackballEHs.clear();
/// Clear the Camera properties related to the trackballs array
/// - First delete the data that it contains
std::vector<campvis::CameraProperty*>::iterator camPropertyIterator = _trackballCameraProperties.begin();
for(; camPropertyIterator != _trackballCameraProperties.end(); camPropertyIterator++) {
delete (*camPropertyIterator);
}
_trackballCameraProperties.clear();
std::vector<GeometryTextureInfo>::iterator geomTexInfoIter = _geomTextureInfos.begin();
for(; geomTexInfoIter != _geomTextureInfos.end(); geomTexInfoIter++) {
(*geomTexInfoIter).destroy();
}
_geomTextureInfos.clear();
}
QSize DataContainerInspectorCanvas::sizeHint() const {
......@@ -113,6 +160,16 @@ namespace campvis {
void DataContainerInspectorCanvas::paint() {
/// if the window is resized, change the depth buffer size, also!
if(!_depthBuffer || _depthBuffer->getWidth() != width() || _depthBuffer->getHeight() != height()) {
delete _depthBuffer;
_depthBuffer = new tgt::Texture(0, tgt::ivec3(width(), height(), 1), GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24, GL_FLOAT, tgt::Texture::LINEAR); //, _renderingWndSize(tgt::ivec2(400, 100))
_texturesDirty = true;
}
LGL_ERROR;
tbb::mutex::scoped_lock lock(_localMutex);
if (_texturesDirty)
updateTextures();
......@@ -159,6 +216,54 @@ namespace campvis {
glPopAttrib();
}
void DataContainerInspectorCanvas::paintMeshGeomTextures() {
LGL_ERROR;
tbb::mutex::scoped_lock lock(_localMutex);
if (_meshGeomTexturesDirty)
updateMeshGeomRenderedTextures();
if (_textures.empty())
return;
glPushAttrib(GL_ALL_ATTRIB_BITS);
glViewport(0, 0, size_.x, size_.y);
glClearColor(0.7f, 0.7f, 0.7f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
LGL_ERROR;
// update layout dimensions
_numTiles.x = ceil(sqrt(static_cast<float>(_textures.size())));
_numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x);
_quadSize = size_ / _numTiles;
_paintShader->activate();
tgt::mat4 projection = tgt::mat4::createOrtho(0, size_.x, 0, size_.y, -1, 1);
_paintShader->setUniform("_projectionMatrix", projection);
tgt::TextureUnit tfUnit, unit2d, unit3d;
p_transferFunction.getTF()->bind(_paintShader, tfUnit);
_paintShader->setUniform("_texture2d", unit2d.getUnitNumber());
_paintShader->setUniform("_texture3d", unit3d.getUnitNumber());
for (int y = 0; y < _numTiles.y; ++y) {
for (int x = 0; x < _numTiles.x; ++x) {
int index = (_numTiles.x * y) + x;
if (index >= static_cast<int>(_textures.size()))
break;
tgt::mat4 scaleMatrix = tgt::mat4::createScale(tgt::vec3(_quadSize, 1.f));
tgt::mat4 translation = tgt::mat4::createTranslation(tgt::vec3(_quadSize.x * x, _quadSize.y * y, 0.f));
_paintShader->setUniform("_modelMatrix", translation * scaleMatrix);
paintTexture(_textures[index], unit2d, unit3d);
}
}
_paintShader->deactivate();
LGL_ERROR;
glPopAttrib();
}
void DataContainerInspectorCanvas::paintTexture(const tgt::Texture* texture, const tgt::TextureUnit& unit2d, const tgt::TextureUnit& unit3d) {
_paintShader->setIgnoreUniformLocationError(true);
......@@ -186,6 +291,87 @@ namespace campvis {
_paintShader->setIgnoreUniformLocationError(false);
_quad->render(GL_POLYGON);
LGL_ERROR;
}
void DataContainerInspectorCanvas::drawGeomteryData(const campvis::GeometryData* mg, tgt::Texture* colorBuffer, const int& trackballndx) {
LGL_ERROR;
glPushAttrib(GL_ALL_ATTRIB_BITS);
/// Activate the shader for geometry Rendering.
_geometryRenderingShader->activate();
LGL_ERROR;
_geometryRenderingShader->setIgnoreUniformLocationError(true);
LGL_ERROR;
_trackballEHs[trackballndx]->setSceneBounds(mg->getWorldBounds());
_geometryRenderingShader->setUniform("_projectionMatrix", _trackballEHs[trackballndx]->getTrackball()->getCamera()->getProjectionMatrix()/*_trackballCameraProperty->getValue().getProjectionMatrix()*/);
LGL_ERROR;
_geometryRenderingShader->setUniform("_viewMatrix", _trackballEHs[trackballndx]->getTrackball()->getCamera()->getViewMatrix());
LGL_ERROR;
// The color that will be used for rendering the object
tgt::Vector4<float> meshColor = static_cast<tgt::Vector4<float>>(p_meshSolidColor.getValue());
meshColor.r /= 255.0f;
meshColor.g /= 255.0f;
meshColor.b /= 255.0f;
meshColor.a /= 255.0f;
_geometryRenderingShader->setUniform("_color", meshColor);
LGL_ERROR;
_geometryRenderingShader->setIgnoreUniformLocationError(false);
LGL_ERROR;
_frameBuffer->activate();
LGL_ERROR;
// Set OpenGL pixel alignment to 1 to avoid problems with NPOT textures
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
colorBuffer->uploadTexture();
colorBuffer->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
_depthBuffer->uploadTexture();
_depthBuffer->setWrapping(tgt::Texture::CLAMP_TO_EDGE);
LGL_ERROR;
_frameBuffer->attachTexture(colorBuffer, GL_COLOR_ATTACHMENT0);
_frameBuffer->attachTexture(_depthBuffer, GL_DEPTH_ATTACHMENT);
_frameBuffer->isComplete();
LGL_ERROR;
glViewport(0, 0, width(), height());
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
LGL_ERROR;
// render the geometry into a polygon mesh.
glPolygonMode(GL_FRONT, GL_POLYGON);
mg->render(GL_POLYGON);
// change the color to white for the wireframe.
_geometryRenderingShader->setUniform("_color", 1.0f, 1.0f, 1.0f, 1.0f);
// Render wireframe around the geometry.
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
mg->render(GL_POLYGON);
LGL_ERROR;
colorBuffer->downloadTexture();
_frameBuffer->deactivate();
LGL_ERROR;
_geometryRenderingShader->deactivate();
glPopAttrib();
}
void DataContainerInspectorCanvas::invalidate() {
......@@ -194,6 +380,12 @@ namespace campvis {
GLJobProc.enqueueJob(this, makeJobOnHeap(this, &DataContainerInspectorCanvas::paint), OpenGLJobProcessor::PaintJob);
}
void DataContainerInspectorCanvas::invalidateMeshGeomTextures() {
// only if inited
if (_quad != 0 && _paintShader != 0)
GLJobProc.enqueueJob(this, makeJobOnHeap(this, &DataContainerInspectorCanvas::paintMeshGeomTextures), OpenGLJobProcessor::PaintJob);
}
void DataContainerInspectorCanvas::createQuad() {
delete _quad;
_quad = 0;
......@@ -204,7 +396,7 @@ namespace campvis {
invalidate();
}
void DataContainerInspectorCanvas::sizeChanged(const tgt::ivec2&) {
void DataContainerInspectorCanvas::sizeChanged(const tgt::ivec2& size) {
invalidate();
}
......@@ -221,6 +413,53 @@ namespace campvis {
invalidate();
}
void DataContainerInspectorCanvas::mouseMoveEvent(tgt::MouseEvent* e)
{
if(e->button() == tgt::MouseEvent::MOUSE_BUTTON_LEFT) {
tgt::MouseEvent* me = static_cast<tgt::MouseEvent*>(e);
tgt::MouseEvent adjustedMe(
me->x(),
me->y(),
me->action(),
me->modifiers(),
me->button(),
me->viewport()
);
if(_selectedTrackball >= 0) {
_trackballEHs[_selectedTrackball]->onEvent(&adjustedMe);
_meshGeomTexturesDirty = true;
invalidateMeshGeomTextures();
}
}
else if(e->button() == tgt::MouseEvent::MOUSE_BUTTON_RIGHT) {
tgt::ivec2 dimCanvas = tgt::ivec2(_quadSize.x * _numTiles.x, _quadSize.y * _numTiles.y);
if(e->x() >= dimCanvas.x || e->y() >= dimCanvas.y || e->x() < 0 || e->y() < 0)
return;
int texIndx = (e->y() / _quadSize.y) * _numTiles.x + (e->x() / _quadSize.x);
const tgt::Texture* texturePtr = _textures[texIndx];
const int texWidth = texturePtr->getWidth();
const int texHeight = texturePtr->getHeight();
int cursorPosX = static_cast<int>(static_cast<float>(e->x() % _quadSize.x) / _quadSize.x * texWidth);
int cursorPosY = static_cast<int>(static_cast<float>(e->y() % _quadSize.y) / _quadSize.y * texHeight);
float f = 0.0;
if(_textures[texIndx]->isDepthTexture()) {
_depth = _textures[texIndx]->depthAsFloat(cursorPosX, texHeight - cursorPosY - 1);
_widget->updateDepth();
}
else {
_color = _textures[texIndx]->texelAsFloat(cursorPosX, texHeight - cursorPosY - 1);
_widget->updateColor();
}
}
}
void DataContainerInspectorCanvas::wheelEvent(tgt::MouseEvent* e) {
if (_renderFullscreen) {
switch (e->button()) {
......@@ -240,6 +479,45 @@ namespace campvis {
}
}
void DataContainerInspectorCanvas::mousePressEvent(tgt::MouseEvent* e) {
tgt::ivec2 selectedIndex(e->x() / _quadSize.x, e->y() / _quadSize.y);
_selectedTrackball = -1;
std::vector<GeometryTextureInfo>::iterator geomTexInfoIter = _geomTextureInfos.begin();
switch (e->button()) {
case tgt::MouseEvent::MOUSE_BUTTON_LEFT:
_selectedTexture = (selectedIndex.y * _numTiles.x) + selectedIndex.x;
for(; geomTexInfoIter != _geomTextureInfos.end(); geomTexInfoIter++) {
if((*geomTexInfoIter)._trackballIndx == _selectedTexture) {
_selectedTrackball = (*geomTexInfoIter)._trackballIndx;
break;
}
}
if(_selectedTrackball >= 0)
_trackballEHs[_selectedTrackball]->getTrackball()->mousePressEvent(e);
break;
default:
break;
}
}
void DataContainerInspectorCanvas::mouseReleaseEvent(tgt::MouseEvent* e) {
if (_renderFullscreen) {
switch (e->button()) {
case tgt::MouseEvent::MOUSE_BUTTON_LEFT:
if(_selectedTrackball >= 0)
_trackballEHs[_selectedTrackball]->getTrackball()->mouseReleaseEvent(e);
break;
default:
break;
}
}
}
void DataContainerInspectorCanvas::onDataContainerChanged(const QString& key, QtDataHandle dh) {
{
tbb::mutex::scoped_lock lock(_localMutex);
......@@ -274,9 +552,22 @@ namespace campvis {
invalidate();
}
const tgt::Color& DataContainerInspectorCanvas::getCapturedColor() {
return _color;
}
const float& DataContainerInspectorCanvas::getCapturedDepth() {
return _depth;
}
void DataContainerInspectorCanvas::updateTextures() {
_textures.clear();
/// Reset the content of the Canvas.
resetContent();
/// Calculate the maximum slices of the textures and fill the textures array
int maxSlices = 1;
unsigned int nMeshGeometry = 0;
for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
if (const ImageData* img = dynamic_cast<const ImageData*>(it->second.getData())) {
if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) {
......@@ -287,27 +578,85 @@ namespace campvis {
else if (const RenderData* rd = dynamic_cast<const RenderData*>(it->second.getData())) {
for (size_t i = 0; i < rd->getNumColorTextures(); ++i) {
const ImageRepresentationGL* imgGL = rd->getColorTexture(i)->getRepresentation<ImageRepresentationGL>();
if (imgGL)
if (imgGL) {
imgGL->downloadTexture();
_textures.push_back(imgGL->getTexture());
}
}
if (rd->hasDepthTexture()) {
const ImageRepresentationGL* imgGL = rd->getDepthTexture()->getRepresentation<ImageRepresentationGL>();
if (imgGL)
if (imgGL) {
imgGL->downloadTexture();
_textures.push_back(imgGL->getTexture());
}
}
}
else if(const campvis::GeometryData* gd = dynamic_cast<const campvis::GeometryData*>(it->second.getData())) {
LGL_ERROR;
GeometryTextureInfo geomTexInfo;
geomTexInfo._geomData = it->second;
geomTexInfo._trackballIndx = nMeshGeometry;
campvis::CameraProperty* cameraProperty = new CameraProperty("camera", "Camera");
_trackballCameraProperties.push_back(cameraProperty);
/// re-initialize the trackball navigation event listener to reset the object's pose
TrackballNavigationEventListener* trackballEH = new TrackballNavigationEventListener(cameraProperty, new IVec2Property("QuadSize", "Size", tgt::ivec2(width(), height()), tgt::ivec2(0), tgt::ivec2(1024)) );
float dist = 3 * fabs(gd->getWorldBounds().getLLF().z - gd->getWorldBounds().getURB().z);
trackballEH->reinitializeCamera(gd->getWorldBounds());
trackballEH->getTrackball()->moveCameraBackward(dist);
LGL_ERROR;
/// store the trackball in the vector
_trackballEHs.push_back(trackballEH);
/// create color buffer and depth buffer.
tgt::Texture* colorBuffer = new tgt::Texture(0, tgt::ivec3(width(), height(), 1), GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tgt::Texture::LINEAR);
/// Render the object on the buffers.
glewExperimental = true;
drawGeomteryData(gd, colorBuffer, nMeshGeometry++);
geomTexInfo._texture = colorBuffer;
/// Store the buffers into array.
_geomTextureInfos.push_back(geomTexInfo);
/// Store the rendered texture in textures.
_textures.push_back(colorBuffer);
}
}
if (maxSlices == 1)
maxSlices = -1;
p_currentSlice.setMaxValue(maxSlices);
_meshGeomTexturesDirty = false;
_texturesDirty = false;
}
void DataContainerInspectorCanvas::updateMeshGeomRenderedTextures() {
std::vector<GeometryTextureInfo>::iterator geomTexInfosIter = _geomTextureInfos.begin();
for(;geomTexInfosIter != _geomTextureInfos.end(); geomTexInfosIter++) {
drawGeomteryData(dynamic_cast<const campvis::GeometryData*>((*geomTexInfosIter)._geomData.getData()), (*geomTexInfosIter)._texture, (*geomTexInfosIter)._trackballIndx);
}
_meshGeomTexturesDirty = false;
}
void DataContainerInspectorCanvas::onPropertyChanged(const AbstractProperty* prop) {
HasPropertyCollection::onPropertyChanged(prop);
invalidate();
}
}
/// if the Mesh Solid Color property is changed, update the mesh's color
const std::string propertyName = (prop)->getName();
if(propertyName == "MeshSolidColor") {
_meshGeomTexturesDirty = true;
invalidateMeshGeomTextures();
}
}
}
\ No newline at end of file
......@@ -44,6 +44,10 @@
#include "core/properties/numericproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "core/tools/opengljobprocessor.h"
#include "modules/vis/processors/geometryrenderer.h"
#include "core/eventhandlers/trackballnavigationeventlistener.h"
#include "core/datastructures/meshgeometry.h"
namespace tgt {
class Shader;
......@@ -57,6 +61,27 @@ namespace campvis {
class DataContainerTreeWidget;
class DataHandle;
class FaceGeometry;
class DataContainerInspectorWidget;
/**
* Stores information about the textures which store the rendered geomtery.
* Note: The object's destroy() function should be called before deleting or releasing the object's memory.
*/
struct GeometryTextureInfo {
campvis::QtDataHandle _geomData;
tgt::Texture* _texture;
int _trackballIndx;
GeometryTextureInfo(): _geomData(0), _texture(0) {
}
void destroy() {
delete _texture;
}
~GeometryTextureInfo() {
}
};
class DataContainerInspectorCanvas : public tgt::QtThreadedCanvas, tgt::Painter, public tgt::EventListener, public HasPropertyCollection {
Q_OBJECT;
......@@ -77,7 +102,7 @@ namespace campvis {
* Initializes the OpenGL stuff (e.g. shaders).
* Must be called with a valid and locked OpenGL context.
*/
virtual void init();
virtual void init(DataContainerInspectorWidget* _pWidget);
/**
* Deinitializes the OpenGL stuff (e.g. shaders).
......@@ -85,7 +110,23 @@ namespace campvis {
*/
void deinit();
/**
* Reset the content of the canvas.
* It will clear the array of textures, rendered geomteries, color buffers, depth buffers and its content.
*/
void resetContent();
void setDataHandles(const std::vector< std::pair<QString, QtDataHandle> >& handles);
/**
* returns the color value which is captured with the mouse.
*/
const tgt::Color& getCapturedColor();
/**
* returns the depth value which is captured with the mouse.
*/
const float& getCapturedDepth();
/**
* Size hint for the default window size
......@@ -108,11 +149,29 @@ namespace campvis {
virtual void mouseDoubleClickEvent(tgt::MouseEvent* e);
/**
* Called on mouse wheel even on this canvas.
* Called on mouse move event on this canvas
* \param e Mouse event arguments
*/
virtual void mouseMoveEvent(tgt::MouseEvent* e);
/**
* Called on mouse wheel event on this canvas.
* \param e Mouse event arguments
*/
virtual void wheelEvent(tgt::MouseEvent* e);
/**
* Called on mouse press button event on this canvas.
* \param e Mouse event arguments
*/
virtual void mousePressEvent(tgt::MouseEvent* e);
/**
* Called on mouse release button event on this canvas.