From 0dcccf557b3182bb0de5e813ee8c32b89e456ea0 Mon Sep 17 00:00:00 2001
From: Nicolas Pope <nwpope@utu.fi>
Date: Sat, 1 Jun 2019 18:44:05 +0300
Subject: [PATCH] Initial NanoGUI code

---
 CMakeLists.txt                                |  13 ++
 applications/gui/CMakeLists.txt               |  23 +++
 applications/gui/src/main.cpp                 | 140 ++++++++++++++++++
 components/common/cpp/include/ftl/config.h.in |   1 +
 4 files changed, 177 insertions(+)
 create mode 100644 applications/gui/CMakeLists.txt
 create mode 100644 applications/gui/src/main.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 512d8b801..d250beab3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,6 +61,15 @@ else()
 endif()
 endif()
 
+find_library( NANOGUI_LIBRARY NAMES nanogui libnanogui)
+if (NANOGUI_LIBRARY)
+	set(HAVE_NANOGUI TRUE)
+	add_library(nanogui UNKNOWN IMPORTED)
+	#set_property(TARGET nanogui PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${NANOGUI_EXTRA_INCS})
+	set_property(TARGET nanogui PROPERTY IMPORTED_LOCATION ${NANOGUI_LIBRARY})
+    message(STATUS "Found NanoGUI: ${NANOGUI_LIBRARY}")
+endif()
+
 find_program( NODE_NPM NAMES npm )
 if (NODE_NPM)
 	message(STATUS "Found NPM: ${NODE_NPM}")
@@ -160,6 +169,10 @@ if (BUILD_RECONSTRUCT AND HAVE_PCL)
 	add_subdirectory(applications/reconstruct)
 endif()
 
+if (HAVE_NANOGUI)
+	add_subdirectory(applications/gui)
+endif()
+
 ### Generate Build Configuration Files =========================================
 
 configure_file(${CMAKE_SOURCE_DIR}/components/common/cpp/include/ftl/config.h.in
diff --git a/applications/gui/CMakeLists.txt b/applications/gui/CMakeLists.txt
new file mode 100644
index 000000000..5b1ba133f
--- /dev/null
+++ b/applications/gui/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Need to include staged files and libs
+#include_directories(${PROJECT_SOURCE_DIR}/reconstruct/include)
+#include_directories(${PROJECT_BINARY_DIR})
+
+set(GUISRC
+	src/main.cpp
+)
+
+add_executable(ftl-gui ${GUISRC})
+
+target_include_directories(ftl-gui PUBLIC
+	$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+	$<INSTALL_INTERFACE:include>
+	PRIVATE src)
+
+#if (CUDA_FOUND)
+#set_property(TARGET ftl-gui PROPERTY CUDA_SEPARABLE_COMPILATION ON)
+#endif()
+
+#target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include)
+target_link_libraries(ftl-gui ftlcommon ftlrgbd Threads::Threads ${OpenCV_LIBS} glog::glog ftlnet ftlrender nanogui GL)
+
+
diff --git a/applications/gui/src/main.cpp b/applications/gui/src/main.cpp
new file mode 100644
index 000000000..6ab767c93
--- /dev/null
+++ b/applications/gui/src/main.cpp
@@ -0,0 +1,140 @@
+#include <ftl/configuration.hpp>
+#include <ftl/net/universe.hpp>
+#include <ftl/rgbd.hpp>
+
+#include <glog/logging.h>
+
+#include <opencv2/opencv.hpp>
+
+#include <nanogui/opengl.h>
+#include <nanogui/glutil.h>
+#include <nanogui/screen.h>
+#include <nanogui/window.h>
+#include <nanogui/layout.h>
+#include <nanogui/imageview.h>
+
+using ftl::config;
+using std::string;
+using ftl::rgbd::RGBDSource;
+
+class GLTexture {
+	public:
+	GLTexture() {
+		glGenTextures(1, &glid_);
+        glBindTexture(GL_TEXTURE_2D, glid_);
+		cv::Mat m(cv::Size(100,100), CV_8UC3);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m.cols, m.rows, 0, GL_RGB, GL_UNSIGNED_BYTE, m.data);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	}
+	~GLTexture() {
+		glDeleteTextures(1, &glid_);
+	}
+
+	void update(cv::Mat &m) {
+		if (m.rows == 0) return;
+		glBindTexture(GL_TEXTURE_2D, glid_);
+		// TODO Allow for other formats
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m.cols, m.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, m.data);
+		auto err = glGetError();
+		if (err != 0) LOG(ERROR) << "OpenGL Texture error: " << err;
+	}
+
+	unsigned int texture() const { return glid_; }
+
+	private:
+	unsigned int glid_;
+};
+
+struct SourceViews {
+	ftl::rgbd::RGBDSource *source;
+	GLTexture texture;
+	nanogui::ImageView *view;
+};
+
+class FTLApplication : public nanogui::Screen {
+	public:
+	explicit FTLApplication(ftl::net::Universe *net) : nanogui::Screen(Eigen::Vector2i(1024, 768), "FT-Lab GUI") {
+		using namespace nanogui;
+		net_ = net;
+
+		for (auto &src : config["sources"]) {		
+			RGBDSource *in = ftl::rgbd::RGBDSource::create(src, net); //new ftl::rgbd::NetSource(src, &net);
+			if (!in) {
+				LOG(ERROR) << "Unrecognised source: " << src;
+			} else {
+				auto &cam = sources_.emplace_back();
+				cam.source = in;
+
+				auto imageWindow = new Window(this, "Source");
+				imageWindow->setPosition(Eigen::Vector2i(710, 15));
+				imageWindow->setLayout(new GroupLayout());
+				imageWindow->setSize(Vector2i(400,400));
+
+				auto imageView = new ImageView(imageWindow, 0);
+				cam.view = imageView;
+				imageView->setGridThreshold(20);
+				//imageView->setPixelInfoThreshold(20);
+				
+				//displays.emplace_back(config["display"], src["uri"]);
+				LOG(INFO) << (string)src["uri"] << " loaded ";
+			}
+		}
+
+		setVisible(true);
+		performLayout();
+	}
+
+	virtual void draw(NVGcontext *ctx) {
+		net_->broadcast("grab");
+		for (auto &src : sources_) {
+			cv::Mat rgb, depth;
+			src.source->grab();
+			src.source->getRGBD(rgb, depth);
+			if (rgb.rows > 0) {
+				src.texture.update(rgb);
+				src.view->bindImage(src.texture.texture());
+			}
+		}
+		performLayout();
+
+		/* Draw the user interface */
+		Screen::draw(ctx);
+	}
+
+	private:
+	std::vector<SourceViews> sources_;
+	ftl::net::Universe *net_;
+};
+
+int main(int argc, char **argv) {
+	ftl::configure(argc, argv, "gui");
+	ftl::net::Universe net(config["net"]);
+
+	net.waitConnections();
+
+	try {
+		nanogui::init();
+
+		/* scoped variables */ {
+			nanogui::ref<FTLApplication> app = new FTLApplication(&net);
+			app->drawAll();
+			app->setVisible(true);
+			nanogui::mainloop();
+		}
+
+		nanogui::shutdown();
+	} catch (const std::runtime_error &e) {
+		std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
+		#if defined(_WIN32)
+			MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
+		#else
+			std::cerr << error_msg << std::endl;
+		#endif
+		return -1;
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/components/common/cpp/include/ftl/config.h.in b/components/common/cpp/include/ftl/config.h.in
index 3d2b7d296..296da9eec 100644
--- a/components/common/cpp/include/ftl/config.h.in
+++ b/components/common/cpp/include/ftl/config.h.in
@@ -19,6 +19,7 @@
 #cmakedefine HAVE_PCL
 #cmakedefine HAVE_RENDER
 #cmakedefine HAVE_LIBSGM
+#cmakedefine HAVE_NANOGUI
 
 extern const char *FTL_VERSION_LONG;
 extern const char *FTL_VERSION;
-- 
GitLab