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 aae87572 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'neuro-project-cleaned' into 'development'

Neuro project cleaned

See merge request !109
parents 45a42e7b dbe26e96
......@@ -199,8 +199,8 @@ namespace campvis {
// compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x)
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y);
float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio;
cgt::mat4 viewMatrix = (ratioRatio > 1) ? cgt::mat4::createScale(cgt::vec3(1.f, 1.f / ratioRatio, 1.f)) : cgt::mat4::createScale(cgt::vec3(ratioRatio, 1.f, 1.f));
......@@ -291,8 +291,8 @@ namespace campvis {
// compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x)
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y);
float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio;
lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f);
......
......@@ -322,7 +322,7 @@ namespace campvis {
std::string pipeScript = "pipeline = pipelines[\"" + _selectedPipeline->getName()+"\"]\n\n";
for (size_t i = 0; i < _selectedPipeline->getProcessors().size(); i++) {
pipeScript += "proc = pipeline:getProcessor(" + StringUtils::toString(i) + ")\n";
AbstractProcessor* proc = _selectedPipeline->getProcessor(i);
AbstractProcessor* proc = _selectedPipeline->getProcessor(int(i));
_pcLua->updatePropCollection(proc, &_selectedPipeline->getDataContainer());
std::string res = _pcLua->getLuaScript(std::string(""), std::string("proc:"));
......
......@@ -28,6 +28,7 @@
#include <QComboBox>
#include <QLineEdit>
#include <QSortFilterProxyModel>
namespace campvis {
DataNamePropertyWidget::DataNamePropertyWidget(DataNameProperty* property, DataContainer* dc, QWidget* parent /*= 0*/)
......@@ -39,6 +40,11 @@ namespace campvis {
_combobox = new QComboBox(this);
_combobox->setEditable(true);
QSortFilterProxyModel* proxy = new QSortFilterProxyModel(_combobox);
proxy->setSourceModel(_combobox->model());
_combobox->model()->setParent(proxy); // combo's current model must be reparented, otherwise QComboBox::setModel() will delete it
_combobox->setModel(proxy);
if (dc != 0) {
std::vector< std::pair<std::string, DataHandle> > tmp = dc->getDataHandlesCopy();
QStringList sl;
......@@ -48,6 +54,7 @@ namespace campvis {
dc->s_dataAdded.connect(this, &DataNamePropertyWidget::onDataAdded);
connect(this, SIGNAL(s_dataAddedQt(const QString&, QtDataHandle)), this, SLOT(onDataAddedQt(const QString&, QtDataHandle)));
_combobox->model()->sort(Qt::AscendingOrder);
setCurrentComboBoxText(QString::fromStdString(property->getValue()));
}
......@@ -106,6 +113,7 @@ namespace campvis {
void DataNamePropertyWidget::onDataAddedQt(const QString& key, QtDataHandle dh) {
if (_combobox->findText(key) == -1) {
_combobox->addItem(key);
_combobox->model()->sort(Qt::AscendingOrder);
}
}
......
......@@ -71,7 +71,7 @@ namespace campvis {
_layout->setSpacing(8);
_layout->setMargin(0);
setLayout(_layout);
connect(this, SIGNAL(s_widgetVisibilityChanged(QWidget*, bool)), this, SLOT(onWidgetVisibilityChanged(QWidget*, bool)));
connect(this, SIGNAL(s_propertyVisibilityChanged(const AbstractProperty*)), this, SLOT(onWidgetVisibilityChanged(const AbstractProperty*)), Qt::QueuedConnection);
connect(this, SIGNAL(propertyAdded(AbstractProperty*)), this, SLOT(addProperty(AbstractProperty*)));
connect(this, SIGNAL(propertyRemoved(AbstractProperty*, QWidget*)), this, SLOT(removeProperty(AbstractProperty*, QWidget*)));
}
......@@ -91,14 +91,18 @@ namespace campvis {
}
void PropertyCollectionWidget::onPropertyVisibilityChanged(const AbstractProperty* prop) {
// This method is not always called on the main thread, so it is not safe to check anything here.
// The event is instead forwarded using the QT sigslot mechanism through a queued connection to the
// main thread.
emit s_propertyVisibilityChanged(prop);
}
void PropertyCollectionWidget::onWidgetVisibilityChanged(const AbstractProperty* prop) {
// const_cast does not harm anything.
std::map<AbstractProperty*, QWidget*>::iterator item = _widgetMap.find(const_cast<AbstractProperty*>(prop));
if (item != _widgetMap.end())
emit s_widgetVisibilityChanged(item->second, item->first->isVisible());
}
void PropertyCollectionWidget::onWidgetVisibilityChanged(QWidget* widget, bool visibility) {
widget->setVisible(visibility);
item->second->setVisible(item->first->isVisible());
}
void PropertyCollectionWidget::onPropCollectionPropAdded(AbstractProperty* prop) {
......
......@@ -72,7 +72,7 @@ namespace campvis {
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void onWidgetVisibilityChanged(QWidget* widget, bool visibility);
virtual void onWidgetVisibilityChanged(const AbstractProperty* prop);
/**
* Creates the property widget for \a prop, connects all neccesary signals, etc.
......@@ -87,7 +87,7 @@ namespace campvis {
void removeProperty(AbstractProperty* prop, QWidget* widget);
signals:
void s_widgetVisibilityChanged(QWidget* widget, bool visibility);
void s_propertyVisibilityChanged(const AbstractProperty* prop);
void propertyAdded(AbstractProperty* prop);
void propertyRemoved(AbstractProperty* prop, QWidget* widget);
......
......@@ -160,7 +160,7 @@ namespace campvis {
return toReturn;
}
MultiIndexedGeometry* GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/) {
MultiIndexedGeometry* GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/, const cgt::vec3& exponents /*= cgt::vec3(1.f)*/) {
cgtAssert(numStacks > 1 && numSlices > 2, "Sphere must have minimum 2 stacks and 3 slices!");
std::vector<cgt::vec3> vertices;
std::vector<cgt::vec3> textureCoordinates;
......@@ -175,7 +175,17 @@ namespace campvis {
for (int j = 0; j < numSlices; ++j) {
float theta = static_cast<float>(j) * 2.f*cgt::PIf / static_cast<float>(numSlices);
vertices.push_back(cgt::vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)));
// apply exponents for supersphere
cgt::vec3 theVertex(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
for (size_t e = 0; e < 3; ++e) {
if (theVertex[e] < 0)
theVertex[e] = -pow(-theVertex[e], exponents[e]);
else
theVertex[e] = pow(theVertex[e], exponents[e]);
}
vertices.push_back(theVertex);
textureCoordinates.push_back(cgt::vec3(theta / (2.f * cgt::PIf), phi / cgt::PIf, 0.f));
}
}
......
......@@ -68,22 +68,23 @@ namespace campvis {
/**
* Creates an MultiIndexedGeometry storing a unit sphere around the origin.
* \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices in the sphere
* \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices in the sphere
* \param exponents Exponent for each dimension to define a supersphere (defines the roundness)
* \return MultiIndexedGeometry storing a unit sphere around the origin.
*/
static MultiIndexedGeometry* createSphere(uint16_t numStacks = 6, uint16_t numSlices = 12);
static MultiIndexedGeometry* createSphere(uint16_t numStacks = 6, uint16_t numSlices = 12, const cgt::vec3& exponents = cgt::vec3(1.f));
/**
* Creates an MultiIndexedGeometry storing a unit length arrow in Z direction starting from the origin.
* \param numSlices Number of slices in the cylinder and cone
* \param tipLen Length of arrow tip (between 0 and 1)
* \param tipLen Length of arrow tip (between 0 and 1)
* \param cylRadius Radius of the cylinder (arrow shaft)
* \param tipRadius Radius of the bottom of the arrow tip
* \param tipRadius Radius of the bottom of the arrow tip
* \return MultiIndexedGeometry storing a unit arrow in Z direction starting from the origin.
*/
static MultiIndexedGeometry* createArrow(uint16_t numSlices = 12, float tipLen = 0.35, float cylRadius = 0.05, float tipRadius = 0.15);
static MultiIndexedGeometry* createArrow(uint16_t numSlices = 12, float tipLen = 0.35, float cylRadius = 0.05, float tipRadius = 0.15);
};
}
......
......@@ -88,13 +88,11 @@ namespace campvis {
}
cgt::Bounds ImageData::getWorldBounds() const {
return cgt::Bounds(_mappingInformation.getOffset(), _mappingInformation.getOffset() + (cgt::vec3(_size) * _mappingInformation.getVoxelSize()));
return getWorldBounds(cgt::svec3(0, 0, 0), cgt::svec3(_size));
}
cgt::Bounds ImageData::getWorldBounds(const cgt::svec3& llf, const cgt::svec3& urb) const {
return cgt::Bounds(
_mappingInformation.getOffset() + (cgt::vec3(llf) * _mappingInformation.getVoxelSize()),
_mappingInformation.getOffset() + (cgt::vec3(urb) * _mappingInformation.getVoxelSize()));
return cgt::Bounds(_mappingInformation.getVoxelToWorldMatrix() * cgt::vec3(llf), _mappingInformation.getVoxelToWorldMatrix() * cgt::vec3(urb));
}
size_t ImageData::getNumElements() const {
......
......@@ -215,7 +215,7 @@ namespace campvis {
template<typename T>
const T* campvis::ImageData::getRepresentation(bool performConversion) const {
// look, whether we already have a suitable representation
for (tbb::concurrent_vector<const AbstractImageRepresentation*>::const_iterator it = _representations.begin(); it != _representations.end(); ++it) {
for (auto it = _representations.begin(); it != _representations.end(); ++it) {
if (const T* tester = dynamic_cast<const T*>(*it)) {
return tester;
}
......@@ -226,7 +226,7 @@ namespace campvis {
tbb::spin_mutex::scoped_lock lock(_conversionMutex);
// in the meantime, there something might have changed, so check again whether there is a new rep.
for (tbb::concurrent_vector<const AbstractImageRepresentation*>::const_iterator it = _representations.begin(); it != _representations.end(); ++it) {
for (auto it = _representations.begin(); it != _representations.end(); ++it) {
if (const T* tester = dynamic_cast<const T*>(*it)) {
return tester;
}
......@@ -240,7 +240,7 @@ namespace campvis {
template<typename T>
const T* campvis::ImageData::tryPerformConversion() const {
for (tbb::concurrent_vector<const AbstractImageRepresentation*>::const_iterator it = _representations.begin(); it != _representations.end(); ++it) {
for (auto it = _representations.begin(); it != _representations.end(); ++it) {
const T* tester = ImageRepresentationConverter::getRef().tryConvertFrom<T>(*it);
if (tester != 0) {
//LDEBUG("Performed a image representation conversion from " + std::string(typeid(**it).name()) + " to " + std::string(typeid(T).name()) + ".");
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
......@@ -53,11 +54,11 @@ namespace campvis {
}
void ImageMappingInformation::updateMatrices() {
_textureToWorldTransformation = cgt::mat4::createTranslation(_offset) * _customTransformation * cgt::mat4::createScale(_voxelSize * _size);
_textureToWorldTransformation = _customTransformation * cgt::mat4::createTranslation(_offset) * cgt::mat4::createScale(_voxelSize * _size);
if (! _textureToWorldTransformation.invert(_worldToTextureTransformation))
cgtAssert(false, "Could not invert texture-to-world matrix. That should not happen!");
_voxelToWorldTransformation = cgt::mat4::createTranslation(_offset) * _customTransformation * cgt::mat4::createScale(_voxelSize);
_voxelToWorldTransformation = _customTransformation * cgt::mat4::createTranslation(_offset) * cgt::mat4::createScale(_voxelSize);
if (! _voxelToWorldTransformation.invert(_worldToVoxelTransformation))
cgtAssert(false, "Could not invert voxel-to-world matrix. That should not happen!");
}
......
......@@ -60,8 +60,8 @@ namespace campvis {
std::ifstream file(_url.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (file.is_open()) {
size_t fileSize = static_cast<size_t>(file.tellg());
if (fileSize < numBytes) {
LERROR("File is smaller than expected.");
if (fileSize < numBytes + _offset) {
LERROR("File is smaller than expected, " << (numBytes + _offset) - fileSize << " Bytes missing.");
return WeaklyTypedPointer(_type, _parent->getNumChannels(), 0);
}
......
......@@ -82,5 +82,13 @@ namespace campvis {
return "Image Series";
}
cgt::Bounds ImageSeries::getWorldBounds() const {
cgt::Bounds b;
for (size_t i = 0; i < _images.size(); ++i) {
b.addVolume(static_cast<const ImageData*>(_images[i].getData())->getWorldBounds());
}
return b;
}
}
\ No newline at end of file
......@@ -35,7 +35,7 @@ namespace campvis {
/**
* Class encapsulating a series of images.
*/
class CAMPVIS_CORE_API ImageSeries : public AbstractData {
class CAMPVIS_CORE_API ImageSeries : public AbstractData, public IHasWorldBounds {
public:
/**
* Constructor
......@@ -69,6 +69,12 @@ namespace campvis {
/// \see AbstractData::getTypeAsString()
virtual std::string getTypeAsString() const;
/**
* Returns the data extent in world coordinates.
* \return The data extent in world coordinates.
*/
virtual cgt::Bounds getWorldBounds() const;
/**
* Appends the image \a image to the series.
* \param image Image to be added.
......
......@@ -59,8 +59,6 @@ namespace campvis {
MultiIndexedGeometry::MultiIndexedGeometry(const MultiIndexedGeometry& rhs)
: GeometryData(rhs)
, _indices(rhs._indices)
, _offsets(rhs._offsets)
, _counts(rhs._counts)
, _vertices(rhs._vertices)
, _textureCoordinates(rhs._textureCoordinates)
, _colors(rhs._colors)
......@@ -80,8 +78,6 @@ namespace campvis {
GeometryData::operator=(rhs);
_indices = rhs._indices;
_offsets = rhs._offsets;
_counts = rhs._counts;
_vertices = rhs._vertices;
_textureCoordinates = rhs._textureCoordinates;
......@@ -97,8 +93,6 @@ namespace campvis {
MultiIndexedGeometry* MultiIndexedGeometry::clone() const {
MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(_vertices, _textureCoordinates, _colors, _normals);
toReturn->_indices = _indices;
toReturn->_offsets = _offsets;
toReturn->_counts = _counts;
return toReturn;
}
......@@ -121,12 +115,11 @@ namespace campvis {
}
void MultiIndexedGeometry::addPrimitive(const std::vector<uint16_t>& indices) {
_offsets.push_back(reinterpret_cast<void*>(_indices.size() * 2));
_counts.push_back(static_cast<GLsizei>(indices.size()));
_indices.insert(_indices.end(), indices.begin(), indices.end());
if (! _indices.empty())
_indices.push_back(65535);
_indices.insert(_indices.end(), indices.begin(), indices.end());
_buffersDirty = true;
}
const std::vector<cgt::col4>& MultiIndexedGeometry::getPickingInformation() const {
......@@ -140,7 +133,38 @@ namespace campvis {
}
void MultiIndexedGeometry::render(GLenum mode) const {
if (_counts.empty())
if (_indices.empty())
return;
createGLBuffers();
if (_buffersDirty) {
LERROR("Cannot render without initialized OpenGL buffers.");
return;
}
cgt::VertexArrayObject vao;
if (_verticesBuffer)
vao.setVertexAttributePointer(0, _verticesBuffer);
if (_texCoordsBuffer)
vao.setVertexAttributePointer(1, _texCoordsBuffer);
if (_colorsBuffer)
vao.setVertexAttributePointer(2, _colorsBuffer);
if (_normalsBuffer)
vao.setVertexAttributePointer(3, _normalsBuffer);
if (_pickingBuffer)
vao.setVertexAttributePointer(4, _pickingBuffer);
vao.bindIndexBuffer(_indicesBuffer);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535);
glDrawElements(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0);
glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR;
}
void MultiIndexedGeometry::renderInstanced(GLsizei count, GLenum mode /*= GL_TRIANGLE_FAN*/) const {
if (_indices.empty())
return;
createGLBuffers();
......@@ -162,8 +186,10 @@ namespace campvis {
vao.setVertexAttributePointer(4, _pickingBuffer);
vao.bindIndexBuffer(_indicesBuffer);
const GLvoid** ptr = (const GLvoid**)(&_offsets.front()); // <- hidden reinterpret_cast<const GLvoid**> here, ugly OpenGL...
glMultiDrawElements(mode, &_counts.front(), GL_UNSIGNED_SHORT, ptr, static_cast<GLsizei>(_offsets.size()));
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(65535);
glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0, count);
glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR;
}
......
......@@ -109,6 +109,14 @@ namespace campvis {
* \param mode OpenGL rendering mode for this mesh
*/
virtual void render(GLenum mode) const;
/**
* Renders multiple instances of this GeometryData.
* Must be called from a valid OpenGL context.
* \param count Number of instances
* \param mode OpenGL rendering mode
*/
virtual void renderInstanced(GLsizei count, GLenum mode = GL_TRIANGLE_FAN) const;
/// \see GeometryData::getWorldBounds
virtual cgt::Bounds getWorldBounds() const;
......@@ -130,8 +138,6 @@ namespace campvis {
void deleteIndicesBuffer() const;
std::vector<uint16_t> _indices; ///< Index list defining the faces
std::vector<void*> _offsets; ///< Byte offsets for each primitive to render
std::vector<GLsizei> _counts; ///< Numer of vertices for each primitive to render
std::vector<cgt::vec3> _vertices; ///< The list of the vertex positions of the face.
std::vector<cgt::vec3> _textureCoordinates; ///< The list of vertex texture coordinates, may be empty.
......
......@@ -32,6 +32,11 @@ void jitterEntryPoint(inout vec3 position, in vec3 direction, in float stepSize)
position = position + direction * (stepSize * random);
}
void jitterFloat(inout float t, in float stepSize) {
float random = fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453);
t += (stepSize * random);
}
/**
* Computes the intersection of the given ray with the given axis-aligned box.
* \param rayOrigin Origin of ray
......@@ -60,6 +65,18 @@ float rayBoxIntersection(in vec3 rayOrigin, in vec3 rayDirection, in vec3 boxLlf
return min(min(tMin.x, min(tMin.y, tMin.z)) , min(tMax.x, min(tMax.y, tMax.z)));
}
// compute the near and far intersections of the cube (stored in the x and y components) using the slab method
// no intersection means vec.x > vec.y (really tNear > tFar)
vec2 intersectAABB(vec3 rayOrigin, vec3 rayDirection, in vec3 boxLlf, in vec3 boxUrb) {
vec3 tMin = (boxLlf - rayOrigin) / rayDirection;
vec3 tMax = (boxUrb - rayOrigin) / rayDirection;
vec3 t1 = min(tMin, tMax);
vec3 t2 = max(tMin, tMax);
float tNear = max(max(t1.x, t1.y), t1.z);
float tFar = min(min(t2.x, t2.y), t2.z);
return vec2(tNear, tFar);
};
/**
* Converts a depth value in eye space to the corresponding depth value in viewport space.
* \param depth Depth value in eye space.
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "viewportsplitter.h"
#include "cgt/framebufferobject.h"
#include "cgt/textureunit.h"
#include "cgt/event/mouseevent.h"
#include "cgt/event/keyevent.h"
#include "core/datastructures/geometrydatafactory.h"
#include "core/datastructures/renderdata.h"
namespace campvis {
const std::string ViewportSplitter::loggerCat_ = "CAMPVis.core.datastructures.ViewportSplitter";
// ================================================================================================
ViewportSplitter::ViewportSplitter(size_t numSubViews, SplitMode splitMode, IVec2Property* viewportSizeProp)
: p_outputImageId("OutputImageId", "Output Image ID", "", DataNameProperty::WRITE)
, p_subViewViewportSize("ElementViewportSize", "Element Viewport Size", cgt::ivec2(128), cgt::ivec2(1), cgt::ivec2(2048))
, _numSubViews(numSubViews)
, _splitMode(splitMode)
, _mousePressed(false)
, _viewIndexOfEvent(0)
, _fbo(nullptr)
, p_viewportSizeProperty(viewportSizeProp)
, _copyShader(nullptr)
{
p_viewportSizeProperty->s_changed.connect(this, &ViewportSplitter::onViewportSizePropertyChanged);
p_inputImageIds.resize(_numSubViews, nullptr);
}
ViewportSplitter::~ViewportSplitter() {
}
void ViewportSplitter::init() {
_quad = GeometryDataFactory::createQuad(cgt::vec3(0.f), cgt::vec3(1.f), cgt::vec3(0.f), cgt::vec3(1.f));
_fbo = new cgt::FramebufferObject();
_copyShader = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/copyimage.frag", "");
_copyShader->setAttributeLocation(0, "in_Position");
_copyShader->setAttributeLocation(1, "in_TexCoord");
}
void ViewportSplitter::deinit() {
delete _fbo;
delete _quad;
ShdrMgr.dispose(_copyShader);
}
void ViewportSplitter::setInputImageIdProperty(size_t index, DataNameProperty* prop) {
cgtAssert(index < _numSubViews, "Index out of bounds");
p_inputImageIds[index] = prop;
}
void ViewportSplitter::onEvent(cgt::Event* e) {
if (typeid(*e) == typeid(cgt::MouseEvent)) {
cgt::MouseEvent* me = static_cast<cgt::MouseEvent*>(e);
cgt::ivec2 position(me->x(), me->y());
if (! _mousePressed) {
if (_splitMode == HORIZONTAL)
_viewIndexOfEvent = std::min(size_t(position.x / p_subViewViewportSize.getValue().x), _numSubViews);
else if (_splitMode == VERTICAL)
_viewIndexOfEvent = std::min(size_t(position.y / p_subViewViewportSize.getValue().y), _numSubViews);
}
if (me->action() == cgt::MouseEvent::PRESSED)
_mousePressed = true;
else if (me->action() == cgt::MouseEvent::RELEASED)
_mousePressed = false;
// compute adjusted mouse event
if (_splitMode == HORIZONTAL)
position.x -= int(_viewIndexOfEvent) * p_subViewViewportSize.getValue().x;
else if (_splitMode == VERTICAL)
position.y -= int(_viewIndexOfEvent) * p_subViewViewportSize.getValue().y;
cgt::MouseEvent adjustedMe(position.x, position.y, me->action(), me->modifiers(), me->button(), p_subViewViewportSize.getValue());
// trigger signal, this HAS to be done synchroneously
s_onEvent.triggerSignal(_viewIndexOfEvent, &adjustedMe);
}
else {
// trigger signal, this HAS to be done synchroneously
s_onEvent.triggerSignal(_viewIndexOfEvent, e);
}
}
void ViewportSplitter::render(DataContainer& dataContainer) {
cgt::vec2 vps(p_viewportSizeProperty->getValue());
cgt::vec2 evps(p_subViewViewportSize.getValue());
cgt::TextureUnit rtUnit, colorUnit, depthUnit;
rtUnit.activate();
cgt::Texture* tex = new cgt::Texture(GL_TEXTURE_2D, cgt::ivec3(p_viewportSizeProperty->getValue(), 1), GL_RGBA8, cgt::Texture::LINEAR);
tex->setWrapping(cgt::Texture::CLAMP_TO_EDGE);
_fbo->activate();
_fbo->attachTexture(tex, GL_COLOR_ATTACHMENT0);
glViewport(0, 0, static_cast<GLsizei>(vps.x), static_cast<GLsizei>(vps.y));
_copyShader->activate();
_copyShader->setUniform("_projectionMatrix", cgt::mat4::createOrtho(0, vps.x, vps.y, 0, -1, 1));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (size_t i = 0; i < _numSubViews; ++i) {
if (p_inputImageIds[i] != nullptr) {
ScopedTypedData<RenderData> rd(dataContainer, p_inputImageIds[i]->getValue());
if (rd != nullptr) {
rd->bind(_copyShader, colorUnit, depthUnit);
_copyShader->setUniform("_modelMatrix", cgt::mat4::createScale(cgt::vec3(evps.x, evps.y, .5f)));