summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2014-08-22 16:40:52 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2014-08-25 08:17:45 +0300
commitf9bb71fd11cce59d74e78202a1117c8abb3a2e44 (patch)
tree3fcc832dfece19f6158b8b56e395a6c289e26bbe
parentae411d84b9eac08c217bdda3aa5fbc6f39d03d85 (diff)
Implement API function for rendering volume slice to an image.
Change-Id: Iea18967c3b525a8d4507a06e6541c85ed3abb470 Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
-rw-r--r--examples/datavisualization/volumetric/main.cpp22
-rw-r--r--examples/datavisualization/volumetric/volumetric.cpp56
-rw-r--r--examples/datavisualization/volumetric/volumetric.h4
-rw-r--r--src/datavisualization/data/qcustom3dvolume.cpp83
-rw-r--r--src/datavisualization/data/qcustom3dvolume.h2
-rw-r--r--src/datavisualization/engine/shaders/texture3dslice.frag4
-rw-r--r--tests/volumetrictest/main.cpp23
-rw-r--r--tests/volumetrictest/volumetrictest.cpp25
-rw-r--r--tests/volumetrictest/volumetrictest.h4
9 files changed, 204 insertions, 19 deletions
diff --git a/examples/datavisualization/volumetric/main.cpp b/examples/datavisualization/volumetric/main.cpp
index 66f62779..5a90070e 100644
--- a/examples/datavisualization/volumetric/main.cpp
+++ b/examples/datavisualization/volumetric/main.cpp
@@ -106,22 +106,42 @@ int main(int argc, char **argv)
colorTableCheckBox->setText(QStringLiteral("Alternate color table"));
colorTableCheckBox->setChecked(false);
+ QLabel *sliceImageXLabel = new QLabel(widget);
+ QLabel *sliceImageYLabel = new QLabel(widget);
+ QLabel *sliceImageZLabel = new QLabel(widget);
+ sliceImageXLabel->setMinimumSize(QSize(200, 100));
+ sliceImageYLabel->setMinimumSize(QSize(200, 200));
+ sliceImageZLabel->setMinimumSize(QSize(200, 100));
+ sliceImageXLabel->setMaximumSize(QSize(200, 100));
+ sliceImageYLabel->setMaximumSize(QSize(200, 200));
+ sliceImageZLabel->setMaximumSize(QSize(200, 100));
+ sliceImageXLabel->setFrameShape(QFrame::Box);
+ sliceImageYLabel->setFrameShape(QFrame::Box);
+ sliceImageZLabel->setFrameShape(QFrame::Box);
+ sliceImageXLabel->setScaledContents(true);
+ sliceImageYLabel->setScaledContents(true);
+ sliceImageZLabel->setScaledContents(true);
+
vLayout->addWidget(fpsCheckBox);
vLayout->addWidget(fpsLabel);
vLayout->addWidget(textureDetailGroupBox);
vLayout->addWidget(colorTableCheckBox);
vLayout->addWidget(sliceXCheckBox);
vLayout->addWidget(sliceXSlider);
+ vLayout->addWidget(sliceImageXLabel);
vLayout->addWidget(sliceYCheckBox);
vLayout->addWidget(sliceYSlider);
+ vLayout->addWidget(sliceImageYLabel);
vLayout->addWidget(sliceZCheckBox);
- vLayout->addWidget(sliceZSlider, 1, Qt::AlignTop);
+ vLayout->addWidget(sliceZSlider);
+ vLayout->addWidget(sliceImageZLabel, 1, Qt::AlignTop);
VolumetricModifier *modifier = new VolumetricModifier(graph);
modifier->setFpsLabel(fpsLabel);
modifier->setMediumDetailRB(mediumDetailRB);
modifier->setHighDetailRB(highDetailRB);
modifier->setSliceSliders(sliceXSlider, sliceYSlider, sliceZSlider);
+ modifier->setSliceLabels(sliceImageXLabel, sliceImageYLabel, sliceImageZLabel);
QObject::connect(fpsCheckBox, &QCheckBox::stateChanged, modifier,
&VolumetricModifier::setFpsMeasurement);
diff --git a/examples/datavisualization/volumetric/volumetric.cpp b/examples/datavisualization/volumetric/volumetric.cpp
index b4ea769c..a553ccf8 100644
--- a/examples/datavisualization/volumetric/volumetric.cpp
+++ b/examples/datavisualization/volumetric/volumetric.cpp
@@ -51,7 +51,10 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_highDetailIndex(0),
m_sliceSliderX(0),
m_sliceSliderY(0),
- m_sliceSliderZ(0)
+ m_sliceSliderZ(0),
+ m_sliceLabelX(0),
+ m_sliceLabelY(0),
+ m_sliceLabelZ(0)
{
m_graph->activeTheme()->setType(Q3DTheme::ThemeQt);
m_graph->setShadowQuality(QAbstract3DGraph::ShadowQualityNone);
@@ -95,12 +98,12 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
}
// The alternate color table.
- // The first visible layer is a thin yellow one, and rest of the volume uses a smooth gradient.
+ // The first visible layer is a thin single color, and rest of the volume uses a smooth gradient.
for (int i = 1; i < colorTableSize; i++) {
if (i < cutOffColorIndex)
m_colorTable2[i] = qRgba(0, 0, 0, 0);
else if (i < cutOffColorIndex + 4)
- m_colorTable2[i] = qRgba(255, 255, 0, 255);
+ m_colorTable2[i] = qRgba(75, 150, 0, 255);
else
m_colorTable2[i] = qRgba(i, 0, 255 - i, 255);
}
@@ -108,6 +111,7 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_volumeItem->setColorTable(m_colorTable1);
m_graph->addCustomItem(m_volumeItem);
+
m_timer.start(0);
#else
// OpenGL ES2 doesn't support 3D textures, so show a warning label instead
@@ -152,6 +156,17 @@ void VolumetricModifier::setHighDetailRB(QRadioButton *button)
m_highDetailRB = button;
}
+void VolumetricModifier::setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel)
+{
+ m_sliceLabelX = xLabel;
+ m_sliceLabelY = yLabel;
+ m_sliceLabelZ = zLabel;
+
+ adjustSliceX(m_sliceSliderX->value());
+ adjustSliceY(m_sliceSliderY->value());
+ adjustSliceZ(m_sliceSliderZ->value());
+}
+
void VolumetricModifier::sliceX(int enabled)
{
if (m_volumeItem)
@@ -173,22 +188,40 @@ void VolumetricModifier::sliceZ(int enabled)
void VolumetricModifier::adjustSliceX(int value)
{
m_sliceIndexX = value / (1024 / m_volumeItem->textureWidth());
- if (m_volumeItem && m_volumeItem->sliceIndexX() != -1)
- m_volumeItem->setSliceIndexX(m_sliceIndexX);
+ if (m_sliceIndexX == m_volumeItem->textureWidth())
+ m_sliceIndexX--;
+ if (m_volumeItem) {
+ if (m_volumeItem->sliceIndexX() != -1)
+ m_volumeItem->setSliceIndexX(m_sliceIndexX);
+ m_sliceLabelX->setPixmap(QPixmap::fromImage(
+ m_volumeItem->renderSlice(Qt::XAxis, m_sliceIndexX)));
+ }
}
void VolumetricModifier::adjustSliceY(int value)
{
m_sliceIndexY = value / (1024 / m_volumeItem->textureHeight());
- if (m_volumeItem && m_volumeItem->sliceIndexY() != -1)
- m_volumeItem->setSliceIndexY(m_sliceIndexY);
+ if (m_sliceIndexY == m_volumeItem->textureHeight())
+ m_sliceIndexY--;
+ if (m_volumeItem) {
+ if (m_volumeItem->sliceIndexY() != -1)
+ m_volumeItem->setSliceIndexY(m_sliceIndexY);
+ m_sliceLabelY->setPixmap(QPixmap::fromImage(
+ m_volumeItem->renderSlice(Qt::YAxis, m_sliceIndexY)));
+ }
}
void VolumetricModifier::adjustSliceZ(int value)
{
m_sliceIndexZ = value / (1024 / m_volumeItem->textureDepth());
- if (m_volumeItem && m_volumeItem->sliceIndexZ() != -1)
- m_volumeItem->setSliceIndexZ(m_sliceIndexZ);
+ if (m_sliceIndexZ == m_volumeItem->textureDepth())
+ m_sliceIndexZ--;
+ if (m_volumeItem) {
+ if (m_volumeItem->sliceIndexZ() != -1)
+ m_volumeItem->setSliceIndexZ(m_sliceIndexZ);
+ m_sliceLabelZ->setPixmap(QPixmap::fromImage(
+ m_volumeItem->renderSlice(Qt::ZAxis, m_sliceIndexZ)));
+ }
}
void VolumetricModifier::handleZoomLevelChange()
@@ -282,6 +315,11 @@ void VolumetricModifier::changeColorTable(int enabled)
m_volumeItem->setColorTable(m_colorTable2);
else
m_volumeItem->setColorTable(m_colorTable1);
+
+ // Rerender image labels
+ adjustSliceX(m_sliceSliderX->value());
+ adjustSliceY(m_sliceSliderY->value());
+ adjustSliceZ(m_sliceSliderZ->value());
}
int VolumetricModifier::createVolume(int textureSize, int startIndex, int count,
diff --git a/examples/datavisualization/volumetric/volumetric.h b/examples/datavisualization/volumetric/volumetric.h
index bb7fb3fe..eb8a4172 100644
--- a/examples/datavisualization/volumetric/volumetric.h
+++ b/examples/datavisualization/volumetric/volumetric.h
@@ -40,6 +40,7 @@ public:
void setFpsLabel(QLabel *fpsLabel);
void setMediumDetailRB(QRadioButton *button);
void setHighDetailRB(QRadioButton *button);
+ void setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel);
public slots:
void sliceX(int enabled);
@@ -82,6 +83,9 @@ private:
QSlider *m_sliceSliderZ;
QVector<QRgb> m_colorTable1;
QVector<QRgb> m_colorTable2;
+ QLabel *m_sliceLabelX;
+ QLabel *m_sliceLabelY;
+ QLabel *m_sliceLabelZ;
};
#endif
diff --git a/src/datavisualization/data/qcustom3dvolume.cpp b/src/datavisualization/data/qcustom3dvolume.cpp
index a7bbae9b..cab79ac0 100644
--- a/src/datavisualization/data/qcustom3dvolume.cpp
+++ b/src/datavisualization/data/qcustom3dvolume.cpp
@@ -577,6 +577,86 @@ QImage::Format QCustom3DVolume::textureFormat() const
return dptrc()->m_textureFormat;
}
+/*!
+ * Renders the slice specified by \a index along \a axis into an image.
+ * The texture format of this object is used.
+ *
+ * \return the rendered image of the slice, or a null image if invalid index is specified.
+ *
+ * \sa textureFormat
+ */
+QImage QCustom3DVolume::renderSlice(Qt::Axis axis, int index)
+{
+ if (index < 0)
+ return QImage();
+
+ int x;
+ int y;
+ if (axis == Qt::XAxis) {
+ if (index >= textureWidth())
+ return QImage();
+ x = textureDepth();
+ y = textureHeight();
+ } else if (axis == Qt::YAxis) {
+ if (index >= textureHeight())
+ return QImage();
+ x = textureWidth();
+ y = textureDepth();
+ } else {
+ if (index >= textureDepth())
+ return QImage();
+ x = textureWidth();
+ y = textureHeight();
+ }
+
+ int padding = 0;
+ int pixelWidth = 4;
+ if (textureFormat() == QImage::Format_Indexed8) {
+ padding = x % 4;
+ pixelWidth = 1;
+ }
+ QVector<uchar> data((x + padding) * y * pixelWidth);
+ int frameSize = textureDataWidth() * textureHeight();
+
+ int dataIndex = 0;
+ if (axis == Qt::XAxis) {
+ for (int i = 0; i < y; i++) {
+ const uchar *p = textureData()->constData()
+ + (index * pixelWidth) + (textureDataWidth() * i);
+ for (int j = 0; j < x; j++) {
+ data[dataIndex++] = *p;
+ for (int k = 1; k < pixelWidth; k++)
+ data[dataIndex++] = *(p + k);
+ p += frameSize;
+ }
+ }
+ } else if (axis == Qt::YAxis) {
+ for (int i = 0; i < y; i++) {
+ const uchar *p = textureData()->constData() + (index * textureDataWidth())
+ + (frameSize * i);
+ for (int j = 0; j < (x * pixelWidth); j++) {
+ data[dataIndex++] = *p;
+ p++;
+ }
+ }
+ } else {
+ for (int i = 0; i < y; i++) {
+ const uchar *p = textureData()->constData() + (index * frameSize)
+ + (textureDataWidth() * i);
+ for (int j = 0; j < (x * pixelWidth); j++) {
+ data[dataIndex++] = *p;
+ p++;
+ }
+ }
+ }
+
+ QImage image(data.constData(), x, y, x * pixelWidth, textureFormat());
+ image.bits(); // Call bits() to detach the new image from local data
+ if (textureFormat() == QImage::Format_Indexed8)
+ image.setColorTable(colorTable());
+
+ return image;
+}
/*!
* \internal
@@ -637,9 +717,6 @@ QCustom3DVolumePrivate::QCustom3DVolumePrivate(QCustom3DVolume *q, const QVector
if (m_textureDepth < 0)
m_textureDepth = 0;
- if (m_colorTable.size() != 256)
- m_colorTable.clear();
-
if (m_textureFormat != QImage::Format_Indexed8)
m_textureFormat = QImage::Format_ARGB32;
diff --git a/src/datavisualization/data/qcustom3dvolume.h b/src/datavisualization/data/qcustom3dvolume.h
index 498922e8..00733d17 100644
--- a/src/datavisualization/data/qcustom3dvolume.h
+++ b/src/datavisualization/data/qcustom3dvolume.h
@@ -80,6 +80,8 @@ public:
void setTextureFormat(QImage::Format format);
QImage::Format textureFormat() const;
+ QImage renderSlice(Qt::Axis axis, int index);
+
signals:
void textureWidthChanged(int value);
void textureHeightChanged(int value);
diff --git a/src/datavisualization/engine/shaders/texture3dslice.frag b/src/datavisualization/engine/shaders/texture3dslice.frag
index 409ab41d..8870b26d 100644
--- a/src/datavisualization/engine/shaders/texture3dslice.frag
+++ b/src/datavisualization/engine/shaders/texture3dslice.frag
@@ -33,8 +33,8 @@ void main() {
if (rayDir.z < 0)
boxBounds.z = -1.0;
highp vec3 t = (boxBounds - rayStart) * invRayDir;
- tFar = max(t.x, t.y);
- tFar = max(tFar, t.z);
+ tFar = min(t.x, t.y);
+ tFar = min(tFar, t.z);
}
highp vec3 xPoint = vec3(volumeSliceIndices.x, 0, 0);
diff --git a/tests/volumetrictest/main.cpp b/tests/volumetrictest/main.cpp
index a15caf88..e838c43a 100644
--- a/tests/volumetrictest/main.cpp
+++ b/tests/volumetrictest/main.cpp
@@ -77,16 +77,37 @@ int main(int argc, char **argv)
QLabel *fpsLabel = new QLabel(QStringLiteral("Fps: "), widget);
+ QLabel *sliceImageXLabel = new QLabel(widget);
+ QLabel *sliceImageYLabel = new QLabel(widget);
+ QLabel *sliceImageZLabel = new QLabel(widget);
+ sliceImageXLabel->setMinimumSize(QSize(200, 100));
+ sliceImageYLabel->setMinimumSize(QSize(200, 200));
+ sliceImageZLabel->setMinimumSize(QSize(200, 100));
+ sliceImageXLabel->setMaximumSize(QSize(200, 100));
+ sliceImageYLabel->setMaximumSize(QSize(200, 200));
+ sliceImageZLabel->setMaximumSize(QSize(200, 100));
+ sliceImageXLabel->setFrameShape(QFrame::Box);
+ sliceImageYLabel->setFrameShape(QFrame::Box);
+ sliceImageZLabel->setFrameShape(QFrame::Box);
+ sliceImageXLabel->setScaledContents(true);
+ sliceImageYLabel->setScaledContents(true);
+ sliceImageZLabel->setScaledContents(true);
+
vLayout->addWidget(fpsLabel);
vLayout->addWidget(sliceXCheckBox);
vLayout->addWidget(sliceXSlider);
+ vLayout->addWidget(sliceImageXLabel);
vLayout->addWidget(sliceYCheckBox);
vLayout->addWidget(sliceYSlider);
+ vLayout->addWidget(sliceImageYLabel);
vLayout->addWidget(sliceZCheckBox);
- vLayout->addWidget(sliceZSlider, 1, Qt::AlignTop);
+ vLayout->addWidget(sliceZSlider);
+ vLayout->addWidget(sliceImageZLabel, 1, Qt::AlignTop);
+
VolumetricModifier *modifier = new VolumetricModifier(graph);
modifier->setFpsLabel(fpsLabel);
+ modifier->setSliceLabels(sliceImageXLabel, sliceImageYLabel, sliceImageZLabel);
QObject::connect(sliceXCheckBox, &QCheckBox::stateChanged, modifier,
&VolumetricModifier::sliceX);
diff --git a/tests/volumetrictest/volumetrictest.cpp b/tests/volumetrictest/volumetrictest.cpp
index 701cfc04..3485dd24 100644
--- a/tests/volumetrictest/volumetrictest.cpp
+++ b/tests/volumetrictest/volumetrictest.cpp
@@ -66,6 +66,8 @@ VolumetricModifier::VolumetricModifier(Q3DScatter *scatter)
m_graph->addCustomItem(m_plainItem);
//m_graph->setMeasureFps(true);
+
+
QObject::connect(m_graph, &QAbstract3DGraph::currentFpsChanged, this,
&VolumetricModifier::handleFpsChange);
// QObject::connect(m_graph->scene(), &Q3DScene::viewportChanged, this,
@@ -110,6 +112,9 @@ void VolumetricModifier::adjustSliceX(int value)
m_volumeItem->setSliceIndexX(m_sliceIndexX);
m_volumeItem2->setSliceIndexX(m_sliceIndexX);
}
+ m_sliceLabelX->setPixmap(QPixmap::fromImage(
+ m_volumeItem2->renderSlice(Qt::XAxis, m_sliceIndexX)));
+
}
void VolumetricModifier::adjustSliceY(int value)
@@ -122,6 +127,8 @@ void VolumetricModifier::adjustSliceY(int value)
m_volumeItem->setSliceIndexY(m_sliceIndexY);
m_volumeItem2->setSliceIndexY(m_sliceIndexY);
}
+ m_sliceLabelY->setPixmap(QPixmap::fromImage(
+ m_volumeItem2->renderSlice(Qt::YAxis, m_sliceIndexY)));
}
void VolumetricModifier::adjustSliceZ(int value)
@@ -134,6 +141,8 @@ void VolumetricModifier::adjustSliceZ(int value)
m_volumeItem->setSliceIndexZ(m_sliceIndexZ);
m_volumeItem2->setSliceIndexZ(m_sliceIndexZ);
}
+ m_sliceLabelZ->setPixmap(QPixmap::fromImage(
+ m_volumeItem2->renderSlice(Qt::ZAxis, m_sliceIndexZ)));
}
void VolumetricModifier::handleFpsChange()
@@ -208,8 +217,8 @@ void VolumetricModifier::createVolume()
uchar *p = data;
// Change one picture using subtexture replacement
-// QImage flipped = logo.mirrored();
-// m_volumeItem->setSubTextureData(101, flipped);
+ QImage flipped = logo.mirrored();
+ m_volumeItem->setSubTextureData(100, flipped);
// Clean up the two extra pixels
p = data + width - 1;
@@ -337,7 +346,7 @@ void VolumetricModifier::createAnotherVolume()
// Change one picture using subtexture replacement
QImage flipped = logo.mirrored();
- m_volumeItem2->setSubTextureData(101, flipped);
+ m_volumeItem2->setSubTextureData(100, flipped);
}
void VolumetricModifier::createYetAnotherVolume()
@@ -485,3 +494,13 @@ void VolumetricModifier::createYetAnotherVolume()
}
+void VolumetricModifier::setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel)
+{
+ m_sliceLabelX = xLabel;
+ m_sliceLabelY = yLabel;
+ m_sliceLabelZ = zLabel;
+
+ adjustSliceX(512);
+ adjustSliceY(512);
+ adjustSliceZ(512);
+}
diff --git a/tests/volumetrictest/volumetrictest.h b/tests/volumetrictest/volumetrictest.h
index 40d88192..f21fd528 100644
--- a/tests/volumetrictest/volumetrictest.h
+++ b/tests/volumetrictest/volumetrictest.h
@@ -35,6 +35,7 @@ public:
~VolumetricModifier();
void setFpsLabel(QLabel *fpsLabel);
+ void setSliceLabels(QLabel *xLabel, QLabel *yLabel, QLabel *zLabel);
public slots:
void sliceX(int enabled);
@@ -59,6 +60,9 @@ private:
int m_sliceIndexY;
int m_sliceIndexZ;
QLabel *m_fpsLabel;
+ QLabel *m_sliceLabelX;
+ QLabel *m_sliceLabelY;
+ QLabel *m_sliceLabelZ;
};
#endif