diff --git a/.gitignore b/.gitignore index d3d56577..6feaa150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build ./data gh-pages +*.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index 26343569..d9eba0ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_BUILD_TYPE "Release" CACHE STRING ) if(NOT WIN32) - set(CMAKE_CXX_FLAGS "-Wall -std=c++0x" CACHE STRING "Flags used by the compiler during all build types.") + set(CMAKE_CXX_FLAGS "-Wall -Wno-deprecated-register -std=c++0x" CACHE STRING "Flags used by the compiler during all build types.") endif() project(displaz) diff --git a/src/gui/PointViewerMainWindow.cpp b/src/gui/PointViewerMainWindow.cpp index 8c65ca35..9ec9bd62 100644 --- a/src/gui/PointViewerMainWindow.cpp +++ b/src/gui/PointViewerMainWindow.cpp @@ -390,6 +390,15 @@ void PointViewerMainWindow::handleMessage(QByteArray message) } m_geometries->unloadFiles(regex); } + else if (commandTokens[0] == "SAVE_SCREENSHOT") + { + if (commandTokens.size()-1 != 1) + { + tfm::format(std::cerr, "Expected screenshot filename\n"); + return; + } + saveScreenShot(commandTokens[1]); + } else if (commandTokens[0] == "SET_VIEW_POSITION") { if (commandTokens.size()-1 != 3) @@ -619,6 +628,12 @@ void PointViewerMainWindow::screenShot() sshot.save(fileName); } +void PointViewerMainWindow::saveScreenShot(const QString & fileName) +{ + QImage sshot = m_pointView->renderScreenShot(); + sshot.save(fileName); + g_logger.info("Saved screenshot to file '%s'", fileName.toStdString()); +} void PointViewerMainWindow::aboutDialog() { diff --git a/src/gui/PointViewerMainWindow.h b/src/gui/PointViewerMainWindow.h index f0673f5e..ff9403c4 100644 --- a/src/gui/PointViewerMainWindow.h +++ b/src/gui/PointViewerMainWindow.h @@ -74,6 +74,7 @@ class PointViewerMainWindow : public QMainWindow void handleIpcConnection(); private: + void saveScreenShot(const QString & fileName); // Gui objects QProgressBar* m_progressBar; View3D* m_pointView; diff --git a/src/main.cpp b/src/main.cpp index 335daaf7..cefba5a5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ int main(int argc, char *argv[]) std::string shaderName; std::string unloadFiles; + std::string saveScreenShot; bool noServer = false; bool clearFiles = false; @@ -98,6 +99,7 @@ int main(int argc, char *argv[]) "-querycursor", &queryCursor, "Query 3D cursor location from displaz instance", "-script", &script, "Script mode: enable several settings which are useful when calling displaz from a script:" " (a) do not wait for displaz GUI to exit before returning,", + "-screenshot %s", &saveScreenShot, "Remote: save current view as image to given file", "", "\nAdditional information:", "-version", &printVersion, "Print version number", @@ -223,6 +225,10 @@ int main(int argc, char *argv[]) { channel->sendMessage(QByteArray("UNLOAD_FILES\n") + unloadFiles.c_str()); } + if (!saveScreenShot.empty()) + { + channel->sendMessage(QByteArray("SAVE_SCREENSHOT\n") + saveScreenShot.c_str()); + } if (posX != -DBL_MAX) { channel->sendMessage("SET_VIEW_POSITION\n" + diff --git a/src/render/View3D.cpp b/src/render/View3D.cpp index cccbc5b0..bd85978f 100644 --- a/src/render/View3D.cpp +++ b/src/render/View3D.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "config.h" #include "fileloader.h" @@ -309,8 +310,7 @@ void View3D::initializeGL() setFocus(); } - -void View3D::resizeGL(int w, int h) +void View3D::resizeViewport(int w, int h) { //Note: This function receives "device pixel sizes" for correct OpenGL viewport setup // Under OS X with retina display, this becomes important as it is 2x the width() or height() @@ -325,6 +325,14 @@ void View3D::resizeGL(int w, int h) double dPR = getDevicePixelRatio(); m_camera.setViewport(QRect(0,0,double(w)/dPR,double(h)/dPR)); +} + +void View3D::resizeGL(int w, int h) +{ + if (m_badOpenGL) + return; + + resizeViewport(w, h); m_incrementalFramebuffer = allocIncrementalFramebuffer(w,h); @@ -372,6 +380,23 @@ unsigned int View3D::allocIncrementalFramebuffer(int w, int h) const return fb; } +void View3D::clearBuffers() const +{ + glClearDepth(1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glClearColor(m_backgroundColor.redF(), m_backgroundColor.greenF(), + m_backgroundColor.blueF(), 1.0f); + if (!m_incrementalDraw) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +TransformState View3D::makeTransformState(int w, int h) const +{ + return TransformState(Imath::V2i(w, h), + m_camera.projectionMatrix(), + m_camera.viewMatrix()); +} void View3D::paintGL() { @@ -397,18 +422,9 @@ void View3D::paintGL() //-------------------------------------------------- // Draw main scene - TransformState transState(Imath::V2i(w, h), - m_camera.projectionMatrix(), - m_camera.viewMatrix()); - - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - glClearColor(m_backgroundColor.redF(), m_backgroundColor.greenF(), - m_backgroundColor.blueF(), 1.0f); - if (!m_incrementalDraw) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + TransformState transState = makeTransformState(w, h); + clearBuffers(); std::vector geoms = selectedGeometry(); // Draw bounding boxes @@ -498,6 +514,42 @@ void View3D::paintGL() glCheckError(); } + +QImage View3D::renderScreenShot(int width, int height) +{ + if (m_badOpenGL) + return QImage(); + + double dPR = getDevicePixelRatio(); + if (width < 0) + width = this->width(); + + if (height < 0) + height = this->height(); + + // Note: the reason for the following two lines and the subsequent downsampling of the + // resulting image is to make the radius of rendered points consistent between the + // gui and screenshot on displas with dPR != 1. + width *= dPR; + height *= dPR; + + QOpenGLFramebufferObject framebuffer(QSize(width, height), QOpenGLFramebufferObject::Depth); + framebuffer.bind(); + resizeViewport(width, height); + clearBuffers(); + + // Render points only + drawPoints(makeTransformState(width, height), + selectedGeometry(), + DBL_MAX, + false); + glFinish(); + + QImage img = framebuffer.toImage(); + return img.scaledToWidth(width / dPR, Qt::SmoothTransformation); +} + + void View3D::drawMeshes(const TransformState& transState, const std::vector& geoms) const { diff --git a/src/render/View3D.h b/src/render/View3D.h index 6076a8f7..af1c9181 100644 --- a/src/render/View3D.h +++ b/src/render/View3D.h @@ -52,6 +52,9 @@ class View3D : public QGLWidget QItemSelectionModel* selectionModel() { return m_selectionModel; } void setSelectionModel(QItemSelectionModel* selectionModel); + // Render pointcloud to offscreen buffer of given size and return as a QImage. + // Negative dimensions are replaced with current gui 3d viewport size. + QImage renderScreenShot(int width = -1, int height = -1); public slots: /// Set the backgroud color void setBackground(QColor col); @@ -85,6 +88,8 @@ class View3D : public QGLWidget void geometryInserted(const QModelIndex&, int firstRow, int lastRow); private: + void resizeViewport(int w, int h); + void clearBuffers() const; double getDevicePixelRatio(); unsigned int allocIncrementalFramebuffer(int w, int h) const; @@ -101,6 +106,8 @@ class View3D : public QGLWidget const std::vector& geoms, double quality, bool incrementalDraw); + TransformState makeTransformState(int w, int h) const; + void drawMeshes(const TransformState& transState, const std::vector& geoms) const;