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 { ...@@ -199,8 +199,8 @@ namespace campvis {
// compute transformation matrices // compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y); float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x) float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y); / (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio; 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)); 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 { ...@@ -291,8 +291,8 @@ namespace campvis {
// compute transformation matrices // compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y); float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x) float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y); / (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio; float ratioRatio = sliceRatio / renderTargetRatio;
lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f); lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f);
......
...@@ -322,7 +322,7 @@ namespace campvis { ...@@ -322,7 +322,7 @@ namespace campvis {
std::string pipeScript = "pipeline = pipelines[\"" + _selectedPipeline->getName()+"\"]\n\n"; std::string pipeScript = "pipeline = pipelines[\"" + _selectedPipeline->getName()+"\"]\n\n";
for (size_t i = 0; i < _selectedPipeline->getProcessors().size(); i++) { for (size_t i = 0; i < _selectedPipeline->getProcessors().size(); i++) {
pipeScript += "proc = pipeline:getProcessor(" + StringUtils::toString(i) + ")\n"; pipeScript += "proc = pipeline:getProcessor(" + StringUtils::toString(i) + ")\n";
AbstractProcessor* proc = _selectedPipeline->getProcessor(i); AbstractProcessor* proc = _selectedPipeline->getProcessor(int(i));
_pcLua->updatePropCollection(proc, &_selectedPipeline->getDataContainer()); _pcLua->updatePropCollection(proc, &_selectedPipeline->getDataContainer());
std::string res = _pcLua->getLuaScript(std::string(""), std::string("proc:")); std::string res = _pcLua->getLuaScript(std::string(""), std::string("proc:"));
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <QComboBox> #include <QComboBox>
#include <QLineEdit> #include <QLineEdit>
#include <QSortFilterProxyModel>
namespace campvis { namespace campvis {
DataNamePropertyWidget::DataNamePropertyWidget(DataNameProperty* property, DataContainer* dc, QWidget* parent /*= 0*/) DataNamePropertyWidget::DataNamePropertyWidget(DataNameProperty* property, DataContainer* dc, QWidget* parent /*= 0*/)
...@@ -39,6 +40,11 @@ namespace campvis { ...@@ -39,6 +40,11 @@ namespace campvis {
_combobox = new QComboBox(this); _combobox = new QComboBox(this);
_combobox->setEditable(true); _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) { if (dc != 0) {
std::vector< std::pair<std::string, DataHandle> > tmp = dc->getDataHandlesCopy(); std::vector< std::pair<std::string, DataHandle> > tmp = dc->getDataHandlesCopy();
QStringList sl; QStringList sl;
...@@ -48,6 +54,7 @@ namespace campvis { ...@@ -48,6 +54,7 @@ namespace campvis {
dc->s_dataAdded.connect(this, &DataNamePropertyWidget::onDataAdded); dc->s_dataAdded.connect(this, &DataNamePropertyWidget::onDataAdded);
connect(this, SIGNAL(s_dataAddedQt(const QString&, QtDataHandle)), this, SLOT(onDataAddedQt(const QString&, QtDataHandle))); connect(this, SIGNAL(s_dataAddedQt(const QString&, QtDataHandle)), this, SLOT(onDataAddedQt(const QString&, QtDataHandle)));
_combobox->model()->sort(Qt::AscendingOrder);
setCurrentComboBoxText(QString::fromStdString(property->getValue())); setCurrentComboBoxText(QString::fromStdString(property->getValue()));
} }
...@@ -106,6 +113,7 @@ namespace campvis { ...@@ -106,6 +113,7 @@ namespace campvis {
void DataNamePropertyWidget::onDataAddedQt(const QString& key, QtDataHandle dh) { void DataNamePropertyWidget::onDataAddedQt(const QString& key, QtDataHandle dh) {
if (_combobox->findText(key) == -1) { if (_combobox->findText(key) == -1) {
_combobox->addItem(key); _combobox->addItem(key);
_combobox->model()->sort(Qt::AscendingOrder);
} }
} }
......
...@@ -71,7 +71,7 @@ namespace campvis { ...@@ -71,7 +71,7 @@ namespace campvis {
_layout->setSpacing(8); _layout->setSpacing(8);
_layout->setMargin(0); _layout->setMargin(0);
setLayout(_layout); 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(propertyAdded(AbstractProperty*)), this, SLOT(addProperty(AbstractProperty*)));
connect(this, SIGNAL(propertyRemoved(AbstractProperty*, QWidget*)), this, SLOT(removeProperty(AbstractProperty*, QWidget*))); connect(this, SIGNAL(propertyRemoved(AbstractProperty*, QWidget*)), this, SLOT(removeProperty(AbstractProperty*, QWidget*)));
} }
...@@ -91,14 +91,18 @@ namespace campvis { ...@@ -91,14 +91,18 @@ namespace campvis {
} }
void PropertyCollectionWidget::onPropertyVisibilityChanged(const AbstractProperty* prop) { 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. // const_cast does not harm anything.
std::map<AbstractProperty*, QWidget*>::iterator item = _widgetMap.find(const_cast<AbstractProperty*>(prop)); std::map<AbstractProperty*, QWidget*>::iterator item = _widgetMap.find(const_cast<AbstractProperty*>(prop));
if (item != _widgetMap.end()) if (item != _widgetMap.end())
emit s_widgetVisibilityChanged(item->second, item->first->isVisible()); item->second->setVisible(item->first->isVisible());
}
void PropertyCollectionWidget::onWidgetVisibilityChanged(QWidget* widget, bool visibility) {
widget->setVisible(visibility);
} }
void PropertyCollectionWidget::onPropCollectionPropAdded(AbstractProperty* prop) { void PropertyCollectionWidget::onPropCollectionPropAdded(AbstractProperty* prop) {
......
...@@ -72,7 +72,7 @@ namespace campvis { ...@@ -72,7 +72,7 @@ namespace campvis {
/** /**
* Gets called when the property has changed, so that widget can update its state. * 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. * Creates the property widget for \a prop, connects all neccesary signals, etc.
...@@ -87,7 +87,7 @@ namespace campvis { ...@@ -87,7 +87,7 @@ namespace campvis {
void removeProperty(AbstractProperty* prop, QWidget* widget); void removeProperty(AbstractProperty* prop, QWidget* widget);
signals: signals:
void s_widgetVisibilityChanged(QWidget* widget, bool visibility); void s_propertyVisibilityChanged(const AbstractProperty* prop);
void propertyAdded(AbstractProperty* prop); void propertyAdded(AbstractProperty* prop);
void propertyRemoved(AbstractProperty* prop, QWidget* widget); void propertyRemoved(AbstractProperty* prop, QWidget* widget);
......
...@@ -160,7 +160,7 @@ namespace campvis { ...@@ -160,7 +160,7 @@ namespace campvis {
return toReturn; 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!"); cgtAssert(numStacks > 1 && numSlices > 2, "Sphere must have minimum 2 stacks and 3 slices!");
std::vector<cgt::vec3> vertices; std::vector<cgt::vec3> vertices;
std::vector<cgt::vec3> textureCoordinates; std::vector<cgt::vec3> textureCoordinates;
...@@ -175,7 +175,17 @@ namespace campvis { ...@@ -175,7 +175,17 @@ namespace campvis {
for (int j = 0; j < numSlices; ++j) { for (int j = 0; j < numSlices; ++j) {
float theta = static_cast<float>(j) * 2.f*cgt::PIf / static_cast<float>(numSlices); 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)); textureCoordinates.push_back(cgt::vec3(theta / (2.f * cgt::PIf), phi / cgt::PIf, 0.f));
} }
} }
......
...@@ -68,22 +68,23 @@ namespace campvis { ...@@ -68,22 +68,23 @@ namespace campvis {
/** /**
* Creates an MultiIndexedGeometry storing a unit sphere around the origin. * Creates an MultiIndexedGeometry storing a unit sphere around the origin.
* \param numStacks Number of stacks in the sphere * \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices 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. * \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. * 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 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 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. * \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 { ...@@ -88,13 +88,11 @@ namespace campvis {
} }
cgt::Bounds ImageData::getWorldBounds() const { 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 { cgt::Bounds ImageData::getWorldBounds(const cgt::svec3& llf, const cgt::svec3& urb) const {
return cgt::Bounds( return cgt::Bounds(_mappingInformation.getVoxelToWorldMatrix() * cgt::vec3(llf), _mappingInformation.getVoxelToWorldMatrix() * cgt::vec3(urb));
_mappingInformation.getOffset() + (cgt::vec3(llf) * _mappingInformation.getVoxelSize()),
_mappingInformation.getOffset() + (cgt::vec3(urb) * _mappingInformation.getVoxelSize()));
} }
size_t ImageData::getNumElements() const { size_t ImageData::getNumElements() const {
......
...@@ -215,7 +215,7 @@ namespace campvis { ...@@ -215,7 +215,7 @@ namespace campvis {
template<typename T> template<typename T>
const T* campvis::ImageData::getRepresentation(bool performConversion) const { const T* campvis::ImageData::getRepresentation(bool performConversion) const {
// look, whether we already have a suitable representation // 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)) { if (const T* tester = dynamic_cast<const T*>(*it)) {
return tester; return tester;
} }
...@@ -226,7 +226,7 @@ namespace campvis { ...@@ -226,7 +226,7 @@ namespace campvis {
tbb::spin_mutex::scoped_lock lock(_conversionMutex); tbb::spin_mutex::scoped_lock lock(_conversionMutex);
// in the meantime, there something might have changed, so check again whether there is a new rep. // 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)) { if (const T* tester = dynamic_cast<const T*>(*it)) {
return tester; return tester;
} }
...@@ -240,7 +240,7 @@ namespace campvis { ...@@ -240,7 +240,7 @@ namespace campvis {
template<typename T> template<typename T>
const T* campvis::ImageData::tryPerformConversion() const { 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); const T* tester = ImageRepresentationConverter::getRef().tryConvertFrom<T>(*it);
if (tester != 0) { if (tester != 0) {
//LDEBUG("Performed a image representation conversion from " + std::string(typeid(**it).name()) + " to " + std::string(typeid(T).name()) + "."); //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. // This file is part of the CAMPVis Software Framework.
...@@ -53,11 +54,11 @@ namespace campvis { ...@@ -53,11 +54,11 @@ namespace campvis {
} }
void ImageMappingInformation::updateMatrices() { 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)) if (! _textureToWorldTransformation.invert(_worldToTextureTransformation))
cgtAssert(false, "Could not invert texture-to-world matrix. That should not happen!"); 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)) if (! _voxelToWorldTransformation.invert(_worldToVoxelTransformation))
cgtAssert(false, "Could not invert voxel-to-world matrix. That should not happen!"); cgtAssert(false, "Could not invert voxel-to-world matrix. That should not happen!");
} }
......
...@@ -60,8 +60,8 @@ namespace campvis { ...@@ -60,8 +60,8 @@ namespace campvis {
std::ifstream file(_url.c_str(), std::ios::in | std::ios::binary | std::ios::ate); std::ifstream file(_url.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (file.is_open()) { if (file.is_open()) {
size_t fileSize = static_cast<size_t>(file.tellg()); size_t fileSize = static_cast<size_t>(file.tellg());
if (fileSize < numBytes) { if (fileSize < numBytes + _offset) {
LERROR("File is smaller than expected."); LERROR("File is smaller than expected, " << (numBytes + _offset) - fileSize << " Bytes missing.");
return WeaklyTypedPointer(_type, _parent->getNumChannels(), 0); return WeaklyTypedPointer(_type, _parent->getNumChannels(), 0);
} }
......
...@@ -82,5 +82,13 @@ namespace campvis { ...@@ -82,5 +82,13 @@ namespace campvis {
return "Image Series"; 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 { ...@@ -35,7 +35,7 @@ namespace campvis {
/** /**
* Class encapsulating a series of images. * Class encapsulating a series of images.
*/ */
class CAMPVIS_CORE_API ImageSeries : public AbstractData { class CAMPVIS_CORE_API ImageSeries : public AbstractData, public IHasWorldBounds {
public: public:
/** /**
* Constructor * Constructor
...@@ -69,6 +69,12 @@ namespace campvis { ...@@ -69,6 +69,12 @@ namespace campvis {
/// \see AbstractData::getTypeAsString() /// \see AbstractData::getTypeAsString()
virtual std::string getTypeAsString() const; 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. * Appends the image \a image to the series.
* \param image Image to be added. * \param image Image to be added.
......
...@@ -59,8 +59,6 @@ namespace campvis { ...@@ -59,8 +59,6 @@ namespace campvis {
MultiIndexedGeometry::MultiIndexedGeometry(const MultiIndexedGeometry& rhs) MultiIndexedGeometry::MultiIndexedGeometry(const MultiIndexedGeometry& rhs)
: GeometryData(rhs) : GeometryData(rhs)
, _indices(rhs._indices) , _indices(rhs._indices)
, _offsets(rhs._offsets)
, _counts(rhs._counts)
, _vertices(rhs._vertices) , _vertices(rhs._vertices)
, _textureCoordinates(rhs._textureCoordinates) , _textureCoordinates(rhs._textureCoordinates)
, _colors(rhs._colors) , _colors(rhs._colors)
...@@ -80,8 +78,6 @@ namespace campvis { ...@@ -80,8 +78,6 @@ namespace campvis {
GeometryData::operator=(rhs); GeometryData::operator=(rhs);
_indices = rhs._indices; _indices = rhs._indices;
_offsets = rhs._offsets;
_counts = rhs._counts;
_vertices = rhs._vertices; _vertices = rhs._vertices;
_textureCoordinates = rhs._textureCoordinates; _textureCoordinates = rhs._textureCoordinates;
...@@ -97,8 +93,6 @@ namespace campvis { ...@@ -97,8 +93,6 @@ namespace campvis {
MultiIndexedGeometry* MultiIndexedGeometry::clone() const { MultiIndexedGeometry* MultiIndexedGeometry::clone() const {
MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(_vertices, _textureCoordinates, _colors, _normals); MultiIndexedGeometry* toReturn = new MultiIndexedGeometry(_vertices, _textureCoordinates, _colors, _normals);
toReturn->_indices = _indices; toReturn->_indices = _indices;
toReturn->_offsets = _offsets;
toReturn->_counts = _counts;
return toReturn; return toReturn;
} }
...@@ -121,12 +115,11 @@ namespace campvis { ...@@ -121,12 +115,11 @@ namespace campvis {
} }
void MultiIndexedGeometry::addPrimitive(const std::vector<uint16_t>& indices) { void MultiIndexedGeometry::addPrimitive(const std::vector<uint16_t>& indices) {
_offsets.push_back(reinterpret_cast<void*>(_indices.size() * 2)); if (! _indices.empty())
_counts.push_back(static_cast<GLsizei>(indices.size())); _indices.push_back(65535);
_indices.insert(_indices.end(), indices.begin(), indices.end());
_indices.insert(_indices.end(), indices.begin(), indices.end());
_buffersDirty = true; _buffersDirty = true;
} }
const std::vector<cgt::col4>& MultiIndexedGeometry::getPickingInformation() const { const std::vector<cgt::col4>& MultiIndexedGeometry::getPickingInformation() const {
...@@ -140,7 +133,38 @@ namespace campvis { ...@@ -140,7 +133,38 @@ namespace campvis {
} }
void MultiIndexedGeometry::render(GLenum mode) const { 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; return;
createGLBuffers(); createGLBuffers();
...@@ -162,8 +186,10 @@ namespace campvis { ...@@ -162,8 +186,10 @@ namespace campvis {
vao.setVertexAttributePointer(4, _pickingBuffer); vao.setVertexAttributePointer(4, _pickingBuffer);
vao.bindIndexBuffer(_indicesBuffer); vao.bindIndexBuffer(_indicesBuffer);
const GLvoid** ptr = (const GLvoid**)(&_offsets.front()); // <- hidden reinterpret_cast<const GLvoid**> here, ugly OpenGL... glEnable(GL_PRIMITIVE_RESTART);
glMultiDrawElements(mode, &_counts.front(), GL_UNSIGNED_SHORT, ptr, static_cast<GLsizei>(_offsets.size())); glPrimitiveRestartIndex(65535);
glDrawElementsInstanced(mode, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_SHORT, 0, count);
glDisable(GL_PRIMITIVE_RESTART);
LGL_ERROR; LGL_ERROR;
} }
......
...@@ -109,6 +109,14 @@ namespace campvis { ...@@ -109,6 +109,14 @@ namespace campvis {
* \param mode OpenGL rendering mode for this mesh * \param mode OpenGL rendering mode for this mesh
*/ */
virtual void render(GLenum mode) const; 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 /// \see GeometryData::getWorldBounds
virtual cgt::Bounds getWorldBounds() const; virtual cgt::Bounds getWorldBounds() const;
...@@ -130,8 +138,6 @@ namespace campvis { ...@@ -130,8 +138,6 @@ namespace campvis {
void deleteIndicesBuffer() const; void deleteIndicesBuffer() const;
std::vector<uint16_t> _indices; ///< Index list defining the faces 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> _vertices; ///< The list of the vertex positions of the face.
std::vector<cgt::vec3> _textureCoordinates; ///< The list of vertex texture coordinates, may be empty.