Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit 7af1f56b authored by schultezub's avatar schultezub
Browse files

* Added saveToFile functionality to DataContainerInspectorWidget

* Fixed wrong DevIL dlls and libs

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@467 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 3a8cf4a7
......@@ -55,6 +55,6 @@ ADD_EXECUTABLE(campvis-application
${CampvisApplicationSources} ${CampvisApplicationHeaders}
${CampvisApplicationMoc}
)
ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${QT_DEFINITIONS})
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs})
TARGET_LINK_LIBRARIES(campvis-application campvis-core campvis-modules tgt ${CampvisGlobalExternalLibs} ${QT_LIBRARIES})
ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${QT_DEFINITIONS})
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs})
TARGET_LINK_LIBRARIES(campvis-application campvis-core campvis-modules tgt ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES})
......@@ -30,19 +30,31 @@
#include "datacontainerinspectorwidget.h"
#include "tgt/assert.h"
#include "tgt/filesystem.h"
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"
#include "tgt/qt/qtcontextmanager.h"
#include "tgt/qt/qtthreadedcanvas.h"
#ifdef CAMPVIS_HAS_MODULE_DEVIL
#include <IL/il.h>
#include <IL/ilu.h>
#endif
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
#include "core/datastructures/abstractdata.h"
#include "core/datastructures/datacontainer.h"
#include "core/datastructures/facegeometry.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/imagerepresentationrendertarget.h"
#include "application/gui/datacontainertreewidget.h"
#include "application/gui/qtdatahandle.h"
#include <QFileDialog>
namespace campvis {
DataContainerInspectorWidget::DataContainerInspectorWidget(QWidget* parent)
......@@ -84,7 +96,7 @@ namespace campvis {
}
QSize DataContainerInspectorWidget::sizeHint() const {
return QSize(640, 480);
return QSize(800, 600);
}
......@@ -117,6 +129,9 @@ namespace campvis {
_lblTimestamp = new QLabel("Timestamp: ", _infoWidget);
_infoWidgetLayout->addWidget(_lblTimestamp);
_btnSaveToFile = new QPushButton(tr("Save to File"), _infoWidget);
_infoWidgetLayout->addWidget(_btnSaveToFile);
_canvas = new DataContainerInspectorCanvas(_infoWidget);
_infoWidgetLayout->addWidget(_canvas, 1);
......@@ -136,6 +151,9 @@ namespace campvis {
connect(
this, SIGNAL(dataContainerChanged(const QString&, QtDataHandle)),
_dctWidget->getTreeModel(), SLOT(onDataContainerChanged(const QString&, QtDataHandle)));
connect(
_btnSaveToFile, SIGNAL(clicked()),
this, SLOT(onBtnSaveToFileClicked()));
}
void DataContainerInspectorWidget::updateInfoWidget() {
......@@ -217,4 +235,79 @@ namespace campvis {
updateInfoWidget();
}
void DataContainerInspectorWidget::onBtnSaveToFileClicked() {
// get the selection from the tree widget
const QModelIndexList& indices = _dctWidget->selectionModel()->selectedRows();
// iterate through the indices of the selection
for (QModelIndexList::const_iterator index = indices.begin(); index != indices.end(); ++index) {
if (! index->isValid())
continue;
// get DataHandle and Handle name
QVariant item = index->data(Qt::UserRole);
DataHandle handle = item.value<QtDataHandle>();
QModelIndex idxName = index->sibling(index->row(), 0);
// only consider non-empty DataHandles that are ImageData and have render target representations
if (handle.getData() != 0) {
if (const ImageData* tester = dynamic_cast<const ImageData*>(handle.getData())) {
if (const ImageRepresentationRenderTarget* repRT = tester->getRepresentation<ImageRepresentationRenderTarget>(false)) {
QString dialogCaption = "Export " + idxName.data(Qt::DisplayRole).toString() + " as Image";
QString directory = tr("");
const QString fileFilter = tr("*.png;;PNG images (*.png)");
QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);
if (! filename.isEmpty()) {
// Texture access needs OpenGL context - dispatch method call:
GLJobProc.enqueueJob(
_canvas,
makeJobOnHeap(&DataContainerInspectorWidget::saveToFile, handle, filename.toStdString()),
OpenGLJobProcessor::SerialJob);
}
}
}
}
}
}
void DataContainerInspectorWidget::saveToFile(DataHandle handle, std::string filename) {
#ifdef CAMPVIS_HAS_MODULE_DEVIL
if (tgt::FileSystem::fileExtension(filename).empty()) {
LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Filename has no extension");
return;
}
// we did the test before, hence, static_cast ist safe
const ImageRepresentationRenderTarget* repRT = static_cast<const ImageData*>(handle.getData())->getRepresentation<ImageRepresentationRenderTarget>(false);
tgtAssert(repRT != 0, "DataHandle must be of type ImageData having an ImageRepresentationRenderTarget inside - otherwise you're not allowed to call this method!");
// get color buffer content
GLubyte* colorBuffer = repRT->getColorTexture()->downloadTextureToBuffer(GL_RGBA, GL_UNSIGNED_SHORT);
tgt::ivec2 size = repRT->getSize().xy();
// create Devil image from image data and write it to file
ILuint img;
ilGenImages(1, &img);
ilBindImage(img);
// put pixels into IL-Image
ilTexImage(size.x, size.y, 1, 4, IL_RGBA, IL_UNSIGNED_SHORT, colorBuffer);
ilEnable(IL_FILE_OVERWRITE);
ilResetWrite();
ILboolean success = ilSaveImage(filename.c_str());
ilDeleteImages(1, &img);
delete[] colorBuffer;
if (!success) {
LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Could not save image to file: " << ilGetError());
}
#else
return;
#endif
}
}
\ No newline at end of file
......@@ -46,6 +46,7 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QString>
#include <QPushButton>
class QModelIndex;
class QItemSelection;
......@@ -118,6 +119,11 @@ namespace campvis {
*/
void onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
/**
* Slot being called when the user clicks on the "Save to File" button.
*/
void onBtnSaveToFileClicked();
protected:
/**
* Setup the GUI stuff
......@@ -129,6 +135,14 @@ namespace campvis {
*/
void updateInfoWidget();
/**
* Saves the Image in \a handle to the file \a filename.
* \note This method must be called with a valid OpenGL context!
* \param handle DataHandle containing the image to save. Must be of type ImageData having an ImageRepresentationRenderTarget inside!
* \param filename Filename for the file to save.
*/
static void saveToFile(DataHandle handle, std::string filename);
/**
* Returns a string with \a numBytes humanized (i.e. "numBytes/1024^n [KMG]Byte")
* \param numBytes Number of bytes to be converted.
......@@ -150,6 +164,7 @@ namespace campvis {
QLabel* _lblLocalMemoryFootprint;
QLabel* _lblVideoMemoryFootprint;
QLabel* _lblTimestamp;
QPushButton* _btnSaveToFile;
};
}
......
......@@ -217,6 +217,7 @@ namespace campvis {
break;
}
shader->setIgnoreUniformLocationError(tmp);
LGL_ERROR;
}
const tgt::Texture* ImageRepresentationGL::getTexture() const {
......
......@@ -167,6 +167,44 @@ namespace campvis {
void (*_callee)(A1); ///< Function to call
A1 _arg1; ///< Argument to pass to \a callee
};
/**
* Specific job, that is calling a member function pasing a single argument.
*/
template<class A1, class A2>
class CallFunc2ArgJob : public AbstractJob {
public:
/**
* Creates an new job, that is calling \a callee on \a target pasing \a arg1 as single argument.
* \param target Target object
* \param callee Member function to call
* \param arg1 Argument to pass to \a callee
*/
CallFunc2ArgJob(void (*callee)(A1, A2), A1 arg1, A2 arg2)
: _callee(callee)
, _arg1(arg1)
, _arg2(arg2)
{
tgtAssert(_callee != 0, "Target member function pointer must not be 0.");
}
/**
* Destructor, nothing to do here
*/
~CallFunc2ArgJob() {};
/**
* Executes this job by calling the member function.
*/
virtual void execute() {
(*_callee)(_arg1, _arg2);
}
protected:
void (*_callee)(A1, A2); ///< Function to call
A1 _arg1; ///< First Argument to pass to \a callee
A2 _arg2; ///< Second Argument to pass to \a callee
};
// = Helper functions for easier creation of jobs =================================================
......@@ -219,12 +257,12 @@ namespace campvis {
}
/**
* Creates a new CallMemberFunc1ArgJob on the heap for the object \a target.
* Creates a new CallFunc1ArgJob on the heap for the object \a target.
* \note The caller takes ownership of the returned pointer.
* \param target Target object to call method from.
* \param callee Pointer to method to call.
* \param arg1 First argument to pass to \callee.
* \return Pointer to the newly created CallMemberFunc1ArgJob. Caller has ownership!
* \return Pointer to the newly created CallFunc1ArgJob. Caller has ownership!
*/
template<class A1>
CallFunc1ArgJob<A1>* makeJobOnHeap(void (*callee)(A1), A1 arg1) {
......@@ -232,17 +270,42 @@ namespace campvis {
}
/**
* Creates a new CallMemberFunc1ArgJob on the stack for the object \a target.
* Creates a new CallFunc1ArgJob on the stack for the object \a target.
* \param target Target object to call method from.
* \param callee Pointer to method to call.
* \param arg1 First argument to pass to \callee.
* \return The newly created CallMemberFunc1ArgJob.
* \return The newly created CallFunc1ArgJob.
*/
template<class A1>
CallFunc1ArgJob<A1> makeJob(void (*callee)(A1), A1 arg1) {
return CallFunc1ArgJob<A1>(callee, arg1);
}
/**
* Creates a new CallFunc2ArgJob on the heap for the object \a target.
* \note The caller takes ownership of the returned pointer.
* \param target Target object to call method from.
* \param callee Pointer to method to call.
* \param arg1 First argument to pass to \callee.
* \param arg2 Second argument to pass to \callee.
* \return Pointer to the newly created CallFunc2ArgJob. Caller has ownership!
*/
template<class A1, class A2>
CallFunc2ArgJob<A1, A2>* makeJobOnHeap(void (*callee)(A1, A2), A1 arg1, A2 arg2) {
return new CallFunc2ArgJob<A1, A2>(callee, arg1, arg2);
}
/**
* Creates a new CallFunc2ArgJob on the stack for the object \a target.
* \param target Target object to call method from.
* \param callee Pointer to method to call.
* \param arg2 Second argument to pass to \callee.
* \return The newly created CallFunc2ArgJob.
*/
template<class A1, class A2>
CallFunc2ArgJob<A1, A2> makeJob(void (*callee)(A1, A2), A1 arg1, A2 arg2) {
return CallFunc2ArgJob<A1, A2>(callee, arg1, arg2);
}
}
#endif // JOB_H__
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment