Skip to content
Snippets Groups Projects
Commit 76e46ab5 authored by Nicolas Pope's avatar Nicolas Pope
Browse files

Remove old GUI

parent 6a34c44b
No related branches found
No related tags found
No related merge requests found
Pipeline #28605 passed
Showing
with 0 additions and 3428 deletions
# Need to include staged files and libs
#include_directories(${PROJECT_SOURCE_DIR}/reconstruct/include)
#include_directories(${PROJECT_BINARY_DIR})
set(GUISRC
src/main.cpp
#src/ctrl_window.cpp
src/src_window.cpp
src/config_window.cpp
src/pose_window.cpp
src/screen.cpp
src/gltexture.cpp
src/camera.cpp
src/media_panel.cpp
src/thumbview.cpp
src/record_window.cpp
src/frameset_mgr.cpp
)
if (HAVE_OPENVR)
list(APPEND GUISRC "src/vr.cpp")
endif()
# Various preprocessor definitions have been generated by NanoGUI
add_definitions(${NANOGUI_EXTRA_DEFS})
# On top of adding the path to nanogui/include, you may need extras
include_directories(${NANOGUI_EXTRA_INCS})
add_executable(ftl-gui ${GUISRC})
install(TARGETS ftl-gui DESTINATION bin COMPONENT gui)
target_include_directories(ftl-gui PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/ext/nanogui/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 ftlctrl ftlrgbd ftlstreams ftlrender Threads::Threads ${OpenCV_LIBS} openvr ftlnet nanogui ${NANOGUI_EXTRA_LIBS})
if (BUILD_TESTS)
add_subdirectory(test)
endif()
This diff is collapsed.
#ifndef _FTL_GUI_CAMERA_HPP_
#define _FTL_GUI_CAMERA_HPP_
#include <ftl/rgbd/frameset.hpp>
#include <ftl/render/CUDARender.hpp>
#include <ftl/render/overlay.hpp>
#include <ftl/codecs/writer.hpp>
#include "gltexture.hpp"
#include <ftl/streams/filestream.hpp>
#include <ftl/streams/netstream.hpp>
#include <ftl/streams/sender.hpp>
#include <ftl/codecs/faces.hpp>
#include <string>
#include <array>
#ifdef HAVE_OPENVR
#include <openvr/openvr.h>
#endif
class StatisticsImage;
namespace ftl {
namespace gui {
class Screen;
class PoseWindow;
class Camera {
public:
Camera(ftl::gui::Screen *screen, int fsmask, int fid, ftl::codecs::Channel chan=ftl::codecs::Channel::Colour);
~Camera();
Camera(const Camera &)=delete;
int width() const { return width_; }
int height() const { return height_; }
int getFramesetMask() const { return fsmask_; }
bool usesFrameset(int id) const { return fsmask_ & (1 << id); }
void setPose(const Eigen::Matrix4d &p);
void mouseMovement(int rx, int ry, int button);
void keyMovement(int key, int modifiers);
void showPoseWindow();
void showSettings();
void setChannel(ftl::codecs::Channel c);
const ftl::codecs::Channel getChannel() { return channel_; }
void togglePause();
void isPaused();
inline bool isVirtual() const { return fid_ == 255; }
const ftl::codecs::Channels<0> &availableChannels() { return channels_; }
inline bool isStereo() const { return stereo_; }
void setStereo(bool v);
/**
* Main function to obtain latest frames.
*/
void update(std::vector<ftl::rgbd::FrameSet *> &fss);
/**
* Update the available channels.
*/
void update(int fsid, const ftl::codecs::Channels<0> &c);
/**
* Draw virtual camera only if the frameset has been updated since last
* draw.
*/
void drawUpdated(std::vector<ftl::rgbd::FrameSet*> &fss);
void draw(std::vector<ftl::rgbd::FrameSet*> &fss);
void drawOverlay(const Eigen::Vector2f &);
inline int64_t getFrameTimeMS() const { return int64_t(delta_ * 1000.0f); }
const ftl::rgbd::Camera &getIntrinsics() const { return state_.getLeft(); }
const Eigen::Matrix4d getPose() const { UNIQUE_LOCK(mutex_, lk); return state_.getPose(); }
/**
* @internal. Used to inform the camera if it is the active camera or not.
*/
void active(bool);
const void captureFrame();
const GLTexture &getLeft() const { return texture1_; }
const GLTexture &getRight() const { return texture2_; }
const GLTexture &getDepth() const { return depth1_; }
void snapshot(const std::string &filename);
void startVideoRecording(const std::string &filename, const std::string &uri);
void stopVideoRecording();
//nlohmann::json getMetaData();
const std::string &name() const { return name_; }
StatisticsImage *stats_ = nullptr;
float getDepth(int x, int y);
float getDepth(float x, float y) { return getDepth((int) round(x), (int) round(y)); }
cv::Point3f getPoint(int x, int y);
cv::Point3f getPoint(float x, float y) { return getPoint((int) round(x), (int) round(y)); }
//cv::Point3f getNormal(int x, int y);
//cv::Point3f getNormal(float x, float y) { return getNormal((int) round(x), (int) round(y)); }
void setTransform(const Eigen::Matrix4d &T);
Eigen::Matrix4d getTransform() const;
const std::vector<std::string> &getMessages() const { return msgs_; }
#ifdef HAVE_OPENVR
bool isVR() { return vr_mode_; }
bool setVR(bool on);
#else
bool isVR() { return false; }
#endif
private:
Screen *screen_;
unsigned int fsmask_; // Frameset Mask
int fid_;
int width_;
int height_;
GLTexture texture1_; // first channel (always left at the moment)
GLTexture texture2_; // second channel ("right")
GLTexture depth1_;
ftl::gui::PoseWindow *posewin_;
//nlohmann::json meta_;
Eigen::Vector4d neye_;
Eigen::Vector3d eye_;
//Eigen::Vector3f orientation_;
Eigen::Matrix4d rotmat_;
float ftime_;
float delta_;
float lerpSpeed_;
bool sdepth_;
bool pause_;
bool do_snapshot_ = false;
std::string pose_source_;
std::string snapshot_filename_;
ftl::codecs::Channel channel_;
ftl::codecs::Channels<0> channels_;
cv::cuda::HostMem im_depth_;
//cv::cuda::HostMem im_normals_;
cv::Mat im_normals_f_;
cv::Mat overlay_; // first channel (left)
bool stereo_;
std::atomic_flag stale_frame_;
int rx_;
int ry_;
std::vector<ftl::rgbd::FrameSet*> *framesets_;
ftl::render::CUDARender *renderer_;
ftl::render::CUDARender *renderer2_;
ftl::render::Colouriser *colouriser_;
ftl::overlay::Overlay *overlayer_;
ftl::Configurable *intrinsics_;
ftl::operators::Graph *post_pipe_;
ftl::rgbd::Frame frame_;
ftl::rgbd::FrameState state_;
ftl::stream::File *file_stream_;
ftl::stream::Net *net_stream_;
ftl::stream::Broadcast *record_stream_;
ftl::stream::Sender *record_sender_;
std::string name_;
std::vector<std::string> msgs_;
int transform_ix_;
std::array<Eigen::Matrix4d,ftl::stream::kMaxStreams> transforms_; // Frameset transforms for virtual cam
Eigen::Matrix4d T_ = Eigen::Matrix4d::Identity();
mutable MUTEX mutex_;
#ifdef HAVE_OPENVR
vr::TrackedDevicePose_t rTrackedDevicePose_[ vr::k_unMaxTrackedDeviceCount ];
bool vr_mode_;
float baseline_;
#endif
void _downloadFrames(ftl::cuda::TextureObject<uchar4> &, ftl::cuda::TextureObject<uchar4> &);
void _downloadFrames(ftl::cuda::TextureObject<uchar4> &);
void _downloadFrames();
void _draw(std::vector<ftl::rgbd::FrameSet*> &fss);
void _applyPoseEffects(std::vector<ftl::rgbd::FrameSet*> &fss);
std::pair<const ftl::rgbd::Frame *, const ftl::codecs::Face *> _selectFace(std::vector<ftl::rgbd::FrameSet*> &fss);
void _generateWindow(const ftl::rgbd::Frame &, const ftl::codecs::Face &face, Eigen::Matrix4d &pose_adjust, ftl::render::ViewPort &vp);
};
}
}
#endif // _FTL_GUI_CAMERA_HPP_
#include "config_window.hpp"
#include "../screen.hpp"
#include <nanogui/layout.h>
#include <nanogui/label.h>
#include <nanogui/button.h>
#include <nanogui/entypo.h>
#include <nanogui/formhelper.h>
#include <nanogui/vscrollpanel.h>
#include <nanogui/opengl.h>
#include <nlohmann/json.hpp>
#include <vector>
#include <string>
using ftl::gui::ConfigWindow;
using std::string;
using std::vector;
using ftl::config::json_t;
class SearchBox : public nanogui::TextBox {
private:
std::vector<std::string> configurables_;
Widget *buttons_;
std::string previous;
void _setVisible(const std::string &str) {
// Check whether the search string has changed to prevent
// unnecessary searching.
if (str != previous) {
for (int i = configurables_.size()-1; i >= 0; --i) {
if (configurables_[i].find(mValueTemp) != std::string::npos) {
buttons_->childAt(i)->setVisible(true);
} else {
buttons_->childAt(i)->setVisible(false);
}
}
previous = str;
}
}
public:
SearchBox(Widget *parent, std::vector<std::string> &configurables) : nanogui::TextBox(parent, ""), configurables_(configurables) {
setAlignment(TextBox::Alignment::Left);
setEditable(true);
setPlaceholder("Search");
}
~SearchBox() {
}
bool keyboardEvent(int key, int scancode, int action, int modifier) {
TextBox::keyboardEvent(key, scancode, action, modifier);
_setVisible(mValueTemp);
return true;
}
void setButtons(Widget *buttons) {
buttons_ = buttons;
}
};
static std::string titleForURI(const ftl::URI &uri) {
auto *cfg = ftl::config::find(uri.getBaseURI());
if (cfg && cfg->get<std::string>("title")) {
return *cfg->get<std::string>("title");
} else if (uri.getPath().size() > 0) {
return uri.getPathSegment(-1);
} else {
return uri.getHost();
}
}
ConfigWindow::ConfigWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl)
: nanogui::Window(parent, "Settings"), ctrl_(ctrl) {
using namespace nanogui;
setLayout(new GroupLayout());
setPosition(Vector2i(parent->width()/2.0f - 100.0f, parent->height()/2.0f - 100.0f));
//setModal(true);
auto configurables = ftl::config::list();
const auto size = configurables.size();
new Label(this, "Select Configurable","sans-bold");
auto searchBox = new SearchBox(this, configurables);
auto vscroll = new VScrollPanel(this);
vscroll->setFixedHeight(300);
auto buttons = new Widget(vscroll);
buttons->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill));
searchBox->setButtons(buttons);
std::vector<std::string> configurable_titles(size);
for (size_t i = 0; i < size; ++i) {
ftl::URI uri(configurables[i]);
std::string label = uri.getFragment();
size_t pos = label.find_last_of("/");
if (pos != std::string::npos) label = label.substr(pos+1);
std::string parentName = configurables[i];
size_t pos2 = parentName.find_last_of("/");
if (pos2 != std::string::npos) parentName = parentName.substr(0,pos2);
// FIXME: Does not indicated parent indentation ... needs sorting?
if (i > 0 && parentName == configurables[i-1]) {
ftl::URI uri(configurables[i-1]);
configurable_titles[i-1] = std::string("[") + titleForURI(uri) + std::string("] ") + uri.getFragment();
auto *prev = dynamic_cast<Button*>(buttons->childAt(buttons->childCount()-1));
prev->setCaption(configurable_titles[i-1]);
prev->setBackgroundColor(nanogui::Color(0.3f,0.3f,0.3f,1.0f));
prev->setTextColor(nanogui::Color(1.0f,1.0f,1.0f,1.0f));
prev->setIconPosition(Button::IconPosition::Left);
prev->setIcon(ENTYPO_ICON_FOLDER);
}
configurable_titles[i] = label;
auto itembutton = new nanogui::Button(buttons, configurable_titles[i]);
std::string c = configurables[i];
itembutton->setTooltip(c);
itembutton->setBackgroundColor(nanogui::Color(0.9f,0.9f,0.9f,0.9f));
itembutton->setCallback([this,c]() {
//LOG(INFO) << "Change configurable: " << c;
_buildForm(c);
setVisible(false);
//this->parent()->removeChild(this);
//delete this;
//screen()->removeChild(this);
});
}
}
ConfigWindow::~ConfigWindow() {
}
void ConfigWindow::_addElements(nanogui::FormHelper *form, const std::string &suri) {
using namespace nanogui;
Configurable *configurable = ftl::config::find(suri);
ftl::config::json_t data;
if (configurable) {
configurable->refresh();
data = configurable->getConfig();
}
for (auto i=data.begin(); i!=data.end(); ++i) {
if (i.key() == "$id") continue;
if (i.key() == "$ref" && i.value().is_string()) {
//LOG(INFO) << "Follow $ref: " << i.value();
const std::string suri = std::string(i.value().get<string>());
_addElements(form, suri);
continue;
}
if (i.value().is_boolean()) {
string key = i.key();
form->addVariable<bool>(i.key(), [this,data,key,suri](const bool &b){
ftl::config::update(suri+"/"+key, b);
}, [data,key]() -> bool {
return data[key].get<bool>();
});
} else if (i.value().is_number_integer()) {
string key = i.key();
form->addVariable<int>(i.key(), [this,data,key,suri](const int &f){
ftl::config::update(suri+"/"+key, f);
}, [data,key]() -> int {
return data[key].get<int>();
});
} else if (i.value().is_number_float()) {
string key = i.key();
form->addVariable<float>(i.key(), [this,data,key,suri](const float &f){
ftl::config::update(suri+"/"+key, f);
}, [data,key]() -> float {
return data[key].get<float>();
});
} else if (i.value().is_string()) {
string key = i.key();
form->addVariable<string>(i.key(), [this,data,key,suri](const string &f){
ftl::config::update(suri+"/"+key, f);
}, [data,key]() -> string {
return data[key].get<string>();
});
} else if (i.value().is_object()) {
string key = i.key();
// Checking the URI with exists() prevents unloaded local configurations from being shown.
if (suri.find('#') != string::npos && exists(suri+string("/")+key)) {
form->addButton(key, [this,suri,key]() {
_buildForm(suri+string("/")+key);
})->setIcon(ENTYPO_ICON_FOLDER);
} else if (exists(suri+string("#")+key)) {
form->addButton(key, [this,suri,key]() {
_buildForm(suri+string("#")+key);
})->setIcon(ENTYPO_ICON_FOLDER);
}
}
}
}
void ConfigWindow::_buildForm(const std::string &suri) {
using namespace nanogui;
ftl::URI uri(suri);
FormHelper *form = new FormHelper(this->screen());
//form->setWindow(this);
form->addWindow(Vector2i(100,50), uri.getFragment());
auto* theme = dynamic_cast<ftl::gui2::Screen*>(screen())->getTheme("window_light");
form->window()->setTheme(theme);
_addElements(form, suri);
auto closebutton = form->addButton("Close", [this,form]() {
form->window()->setVisible(false);
delete form;
});
closebutton->setIcon(ENTYPO_ICON_CROSS);
}
bool ConfigWindow::exists(const std::string &uri) {
return ftl::config::find(uri) != nullptr;
}
#ifndef _FTL_GUI_CFGWINDOW_HPP_
#define _FTL_GUI_CFGWINDOW_HPP_
#include <nanogui/window.h>
#include <nanogui/formhelper.h>
#include <ftl/master.hpp>
#include <ftl/uuid.hpp>
#include <ftl/net_configurable.hpp>
namespace ftl {
namespace gui {
/**
* Allow configurable editing.
*/
class ConfigWindow : public nanogui::Window {
public:
ConfigWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl);
~ConfigWindow();
private:
ftl::ctrl::Master *ctrl_;
void _buildForm(const std::string &uri);
void _addElements(nanogui::FormHelper *form, const std::string &suri);
bool exists(const std::string &uri);
};
}
}
#endif // _FTL_GUI_CFGWINDOW_HPP_
#include "ctrl_window.hpp"
#include "config_window.hpp"
#include <nanogui/layout.h>
#include <nanogui/label.h>
#include <nanogui/combobox.h>
#include <nanogui/button.h>
#include <nanogui/entypo.h>
#include <vector>
#include <string>
using ftl::gui::ControlWindow;
using ftl::gui::ConfigWindow;
using std::string;
using std::vector;
ControlWindow::ControlWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl)
: nanogui::Window(parent, "Network Connections"), ctrl_(ctrl) {
setLayout(new nanogui::GroupLayout());
using namespace nanogui;
_updateDetails();
auto tools = new Widget(this);
tools->setLayout(new BoxLayout( Orientation::Horizontal,
Alignment::Middle, 0, 6));
auto button = new Button(tools, "", ENTYPO_ICON_PLUS);
button->setCallback([this] {
// Show new connection dialog
_addNode();
});
button->setTooltip("Add new node");
// commented-out buttons not working/useful
/*
button = new Button(tools, "", ENTYPO_ICON_CYCLE);
button->setCallback([this] {
ctrl_->restart();
});
button = new Button(tools, "", ENTYPO_ICON_CONTROLLER_PAUS);
button->setCallback([this] {
ctrl_->pause();
});
button->setTooltip("Pause all nodes");*/
new Label(this, "Select Node","sans-bold");
auto select = new ComboBox(this, node_titles_);
select->setCallback([this](int ix) {
//LOG(INFO) << "Change node: " << ix;
_changeActive(ix);
});
new Label(this, "Node Options","sans-bold");
tools = new Widget(this);
tools->setLayout(new BoxLayout( Orientation::Horizontal,
Alignment::Middle, 0, 6));
/*button = new Button(tools, "", ENTYPO_ICON_INFO);
button->setCallback([this] {
});
button->setTooltip("Node status information");*/
button = new Button(tools, "", ENTYPO_ICON_COG);
button->setCallback([this,parent] {
auto cfgwin = new ConfigWindow(parent, ctrl_);
cfgwin->setTheme(theme());
});
button->setTooltip("Edit node configuration");
/*button = new Button(tools, "", ENTYPO_ICON_CYCLE);
button->setCallback([this] {
ctrl_->restart(_getActiveID());
});
button->setTooltip("Restart this node");*/
/*button = new Button(tools, "", ENTYPO_ICON_CONTROLLER_PAUS);
button->setCallback([this] {
ctrl_->pause(_getActiveID());
});
button->setTooltip("Pause node processing");*/
ctrl->getNet()->onConnect([this,select](ftl::net::Peer *p) {
_updateDetails();
select->setItems(node_titles_);
});
_changeActive(0);
}
ControlWindow::~ControlWindow() {
}
void ControlWindow::_addNode() {
using namespace nanogui;
FormHelper *form = new FormHelper(this->screen());
form->addWindow(Vector2i(100,100), "Add Node");
auto var = form->addVariable("URI", add_node_uri_);
var->setValue("tcp://localhost:9001");
var->setFixedWidth(200);
form->addButton("Add", [this,form](){
ctrl_->getNet()->connect(add_node_uri_);
form->window()->setVisible(false);
delete form;
})->setIcon(ENTYPO_ICON_PLUS);
form->addButton("Close", [form]() {
form->window()->setVisible(false);
delete form;
})->setIcon(ENTYPO_ICON_CROSS);
}
void ControlWindow::_updateDetails() {
node_details_ = ctrl_->getControllers();
node_titles_.clear();
for (auto &d : node_details_) {
node_titles_.push_back(d["title"].get<string>());
}
}
void ControlWindow::_changeActive(int ix) {
active_ix_ = ix;
}
ftl::UUID ControlWindow::_getActiveID() {
return ftl::UUID(node_details_[active_ix_]["id"].get<string>());
}
#ifndef _FTL_GUI_CTRLWINDOW_HPP_
#define _FTL_GUI_CTRLWINDOW_HPP_
#include <nanogui/window.h>
#include <ftl/master.hpp>
#include <ftl/uuid.hpp>
namespace ftl {
namespace gui {
/**
* Manage connected nodes and add new connections.
*/
class ControlWindow : public nanogui::Window {
public:
ControlWindow(nanogui::Widget *parent, ftl::ctrl::Master *ctrl);
~ControlWindow();
private:
ftl::ctrl::Master *ctrl_;
std::vector<ftl::config::json_t> node_details_;
std::vector<std::string> node_titles_;
int active_ix_;
std::string add_node_uri_;
void _updateDetails();
void _changeActive(int);
ftl::UUID _getActiveID();
void _addNode();
};
}
}
#endif // _FTL_GUI_CTRLWINDOW_HPP_
#include "frameset_mgr.hpp"
#include <ftl/uri.hpp>
static int frameset_counter = 0;
int ftl::gui::mapToFrameset(const std::string &uri) {
//ftl::URI u(uri);
return frameset_counter++;
}
#ifndef _FTL_GUI_FRAMESET_MANAGER_HPP_
#define _FTL_GUI_FRAMESET_MANAGER_HPP_
#include <string>
namespace ftl {
namespace gui {
/**
* Given a stream URI, allocate a frameset number to that stream.
*/
int mapToFrameset(const std::string &uri);
}
}
#endif
#include "gltexture.hpp"
#include <nanogui/opengl.h>
#include <loguru.hpp>
#include <ftl/cuda_common.hpp>
#include <cuda_gl_interop.h>
#include <ftl/exception.hpp>
using ftl::gui::GLTexture;
GLTexture::GLTexture(GLTexture::Type type) {
glid_ = std::numeric_limits<unsigned int>::max();
glbuf_ = std::numeric_limits<unsigned int>::max();
cuda_res_ = nullptr;
width_ = 0;
height_ = 0;
changed_ = true;
type_ = type;
}
GLTexture::~GLTexture() {
//glDeleteTextures(1, &glid_);
}
void GLTexture::update(cv::Mat &m) {
LOG(INFO) << "DEPRECATED";
if (m.rows == 0) return;
if (glid_ == std::numeric_limits<unsigned int>::max()) {
glGenTextures(1, &glid_);
glBindTexture(GL_TEXTURE_2D, glid_);
//cv::Mat m(cv::Size(100,100), CV_8UC3);
if (type_ == Type::BGRA) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m.cols, m.rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, m.data);
} else if (type_ == Type::Float) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, m.cols, m.rows, 0, GL_RED, GL_FLOAT, 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);
} else {
//glBindTexture(GL_TEXTURE_2D, glid_);
// TODO Allow for other formats
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m.cols, m.rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, m.data);
}
auto err = glGetError();
if (err != 0) LOG(ERROR) << "OpenGL Texture error: " << err;
}
void GLTexture::make(int width, int height) {
if (width != width_ || height != height_) {
free();
}
static constexpr int ALIGNMENT = 128;
width_ = width;
height_ = height;
stride_ = ((width*4) % ALIGNMENT != 0) ? ((width*4) + (ALIGNMENT - ((width*4) % ALIGNMENT))) / 4 : width;
if (width == 0 || height == 0) {
throw FTL_Error("Invalid texture size");
}
if (glid_ == std::numeric_limits<unsigned int>::max()) {
glGenTextures(1, &glid_);
glBindTexture(GL_TEXTURE_2D, glid_);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_);
//cv::Mat m(cv::Size(100,100), CV_8UC3);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
if (type_ == Type::BGRA) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
} else if (type_ == Type::Float) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, nullptr);
}
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);
auto err = glGetError();
if (err != 0) LOG(ERROR) << "OpenGL Texture error: " << err;
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glGenBuffers(1, &glbuf_);
// Make this the current UNPACK buffer (OpenGL is state-based)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glbuf_);
// Allocate data for the buffer. 4-channel 8-bit image
glBufferData(GL_PIXEL_UNPACK_BUFFER, stride_ * height * 4, NULL, GL_DYNAMIC_COPY);
cudaSafeCall(cudaGraphicsGLRegisterBuffer(&cuda_res_, glbuf_, cudaGraphicsRegisterFlagsWriteDiscard));
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
}
void GLTexture::free() {
if (glid_ != std::numeric_limits<unsigned int>::max()) {
glDeleteTextures(1, &glid_);
glid_ = std::numeric_limits<unsigned int>::max();
}
if (glbuf_ != std::numeric_limits<unsigned int>::max()) {
cudaSafeCall(cudaGraphicsUnregisterResource( cuda_res_ ));
cuda_res_ = nullptr;
glDeleteBuffers(1, &glbuf_);
glbuf_ = std::numeric_limits<unsigned int>::max();
}
}
cv::cuda::GpuMat GLTexture::map(cudaStream_t stream) {
void *devptr;
size_t size;
cudaSafeCall(cudaGraphicsMapResources(1, &cuda_res_, stream));
cudaSafeCall(cudaGraphicsResourceGetMappedPointer(&devptr, &size, cuda_res_));
return cv::cuda::GpuMat(height_, width_, (type_ == Type::BGRA) ? CV_8UC4 : CV_32F, devptr, stride_*4);
}
void GLTexture::unmap(cudaStream_t stream) {
cudaSafeCall(cudaGraphicsUnmapResources(1, &cuda_res_, stream));
changed_ = true;
//glActiveTexture(GL_TEXTURE0);
glBindBuffer( GL_PIXEL_UNPACK_BUFFER, glbuf_);
// Select the appropriate texture
glBindTexture( GL_TEXTURE_2D, glid_);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride_);
// Make a texture from the buffer
if (type_ == Type::BGRA) {
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
} else {
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RED, GL_FLOAT, NULL);
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0);
}
unsigned int GLTexture::texture() const {
if (glbuf_ < std::numeric_limits<unsigned int>::max()) {
/*//glActiveTexture(GL_TEXTURE0);
glBindBuffer( GL_PIXEL_UNPACK_BUFFER, glbuf_);
// Select the appropriate texture
glBindTexture( GL_TEXTURE_2D, glid_);
// Make a texture from the buffer
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0);*/
return glid_;
} else {
return glid_;
}
}
#ifndef _FTL_GUI_GLTEXTURE_HPP_
#define _FTL_GUI_GLTEXTURE_HPP_
#include <opencv2/core/mat.hpp>
#include <cuda_runtime.h>
struct cudaGraphicsResource;
namespace ftl {
namespace gui {
class GLTexture {
public:
enum class Type {
RGBA,
BGRA,
Float
};
explicit GLTexture(Type);
~GLTexture();
void update(cv::Mat &m);
void make(int width, int height);
unsigned int texture() const;
bool isValid() const { return glid_ != std::numeric_limits<unsigned int>::max(); }
cv::cuda::GpuMat map(cudaStream_t stream);
void unmap(cudaStream_t stream);
void free();
int width() const { return width_; }
int height() const { return height_; }
private:
unsigned int glid_;
unsigned int glbuf_;
int width_;
int height_;
int stride_;
bool changed_;
Type type_;
cudaGraphicsResource *cuda_res_;
};
}
}
#endif // _FTL_GUI_GLTEXTURE_HPP_
#include <ftl/configuration.hpp>
#include <ftl/net/universe.hpp>
#include <ftl/rgbd.hpp>
#include <ftl/master.hpp>
#include <ftl/net_configurable.hpp>
#include <loguru.hpp>
#include "screen.hpp"
#include <cuda_gl_interop.h>
#ifdef HAVE_PYLON
#include <pylon/PylonIncludes.h>
#endif
int main(int argc, char **argv) {
#ifdef HAVE_PYLON
Pylon::PylonAutoInitTerm autoInitTerm;
#endif
auto root = ftl::configure(argc, argv, "gui_default");
ftl::net::Universe *net = ftl::create<ftl::net::Universe>(root, "net");
int cuda_device;
cudaSafeCall(cudaGetDevice(&cuda_device));
//cudaSafeCall(cudaGLSetGLDevice(cuda_device));
ftl::ctrl::Master *controller = new ftl::ctrl::Master(root, net);
controller->onLog([](const ftl::ctrl::LogEvent &e){
const int v = e.verbosity;
switch (v) {
case -2: LOG(ERROR) << "Remote log: " << e.message; break;
case -1: LOG(WARNING) << "Remote log: " << e.message; break;
case 0: LOG(INFO) << "Remote log: " << e.message; break;
}
});
net->start();
net->waitConnections();
/*auto available = net.findAll<string>("list_streams");
for (auto &a : available) {
std::cout << " -- " << a << std::endl;
}*/
ftl::timer::start();
try {
nanogui::init();
{
nanogui::ref<ftl::gui::Screen> app = new ftl::gui::Screen(root, net, controller);
app->drawAll();
app->setVisible(true);
//nanogui::mainloop(20);
float last_draw_time = 0.0f;
while (ftl::running) {
if (!app->visible()) {
ftl::running = false;
} else if (glfwWindowShouldClose(app->glfwWindow())) {
app->setVisible(false);
ftl::running = false;
} else {
float now = (float)glfwGetTime();
float delta = now - last_draw_time;
// Generate poses and render and virtual frame here
// at full FPS (25 without VR and 90 with VR currently)
app->drawFast();
// Only draw the GUI at 25fps
if (delta >= 0.04f) {
last_draw_time = now;
app->drawAll();
}
}
/* Wait for mouse/keyboard or empty refresh events */
//glfwWaitEvents();
glfwPollEvents();
}
/* Process events once more */
glfwPollEvents();
LOG(INFO) << "Stopping...";
ftl::timer::stop(false);
ftl::pool.stop(true);
LOG(INFO) << "All threads stopped.";
}
nanogui::shutdown();
} catch (const ftl::exception &e) {
LOG(ERROR) << "Fatal error: " << e.what();
LOG(ERROR) << e.trace();
} 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
LOG(ERROR) << error_msg;
#endif
return -1;
}
net->shutdown();
delete controller;
delete net;
delete root;
return 0;
}
#include "media_panel.hpp"
#include "screen.hpp"
#include "record_window.hpp"
#include <nanogui/layout.h>
#include <nanogui/button.h>
#include <nanogui/popupbutton.h>
#include <nanogui/entypo.h>
#ifdef HAVE_LIBARCHIVE
#include "ftl/rgbd/snapshot.hpp"
#endif
using ftl::gui::MediaPanel;
using ftl::codecs::Channel;
MediaPanel::MediaPanel(ftl::gui::Screen *screen, ftl::gui::SourceWindow *sourceWindow) : nanogui::Window(screen, ""), screen_(screen), sourceWindow_(sourceWindow) {
using namespace nanogui;
paused_ = false;
disable_switch_channels_ = false;
record_mode_ = RecordMode::None;
setLayout(new BoxLayout(Orientation::Horizontal,
Alignment::Middle, 5, 10));
auto size = Vector2i(400, 60);
//setFixedSize(size);
setPosition(Vector2i(screen->width() / 2 - size[0]/2, screen->height() - 30 - size[1]));
auto button = new Button(this, "", ENTYPO_ICON_EDIT);
button->setTooltip("Edit camera properties");
button->setCallback([this]() {
auto *cam = screen_->activeCamera();
if (cam) cam->showPoseWindow();
});
recordbutton_ = new PopupButton(this, "", ENTYPO_ICON_CONTROLLER_RECORD);
recordbutton_->setTooltip("Record");
recordbutton_->setSide(Popup::Side::Right);
recordbutton_->setChevronIcon(0);
auto recordpopup = recordbutton_->popup();
recordpopup->setLayout(new GroupLayout());
recordpopup->setTheme(screen->toolbuttheme);
recordpopup->setAnchorHeight(180);
auto itembutton = new Button(recordpopup, "2D snapshot (.png)");
itembutton->setCallback([this]() {
_startRecording(RecordMode::Snapshot2D);
recordbutton_->setPushed(false);
});
itembutton = new Button(recordpopup, "Virtual camera recording (.ftl)");
itembutton->setCallback([this]() {
_startRecording(RecordMode::Video2D);
recordbutton_->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f));
recordbutton_->setPushed(false);
});
itembutton = new Button(recordpopup, "Virtual camera Live");
itembutton->setCallback([this]() {
_startRecording(RecordMode::Live2D);
recordbutton_->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f));
recordbutton_->setPushed(false);
});
itembutton = new Button(recordpopup, "3D scene snapshot (.ftl)");
itembutton->setCallback([this]() {
_startRecording(RecordMode::Snapshot3D);
recordbutton_->setPushed(false);
});
itembutton = new Button(recordpopup, "3D scene recording (.ftl)");
itembutton->setCallback([this]() {
_startRecording(RecordMode::Video3D);
recordbutton_->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f));
recordbutton_->setPushed(false);
});
itembutton = new Button(recordpopup, "Detailed recording options");
itembutton->setCallback([this,sourceWindow] {
auto record_window = new RecordWindow(screen_, screen_, sourceWindow->getCameras(), this);
record_window->setTheme(screen_->windowtheme);
recordbutton_->setPushed(false);
recordbutton_->setEnabled(false);
});
recordbutton_->setCallback([this](){
if (record_mode_ != RecordMode::None) {
_stopRecording();
recordbutton_->setTextColor(nanogui::Color(1.0f,1.0f,1.0f,1.0f));
recordbutton_->setPushed(false);
}
});
button = new Button(this, "", ENTYPO_ICON_CONTROLLER_STOP);
button->setCallback([this]() {
screen_->setActiveCamera(nullptr);
});
button = new Button(this, "", ENTYPO_ICON_CONTROLLER_PAUS);
button->setCallback([this,button,sourceWindow]() {
//paused_ = !paused_;
//paused_ = !(bool)ftl::config::get("[reconstruction]/controls/paused");
//ftl::config::update("[reconstruction]/controls/paused", paused_);
paused_ = !paused_;
sourceWindow->paused(paused_);
if (paused_) {
button->setIcon(ENTYPO_ICON_CONTROLLER_PLAY);
} else {
button->setIcon(ENTYPO_ICON_CONTROLLER_PAUS);
}
});
// not very useful (l/r)
/*auto button_dual = new Button(this, "", ENTYPO_ICON_MAP);
button_dual->setCallback([this]() {
screen_->setDualView(!screen_->getDualView());
});
*/
#ifdef HAVE_OPENVR
if (this->screen_->isHmdPresent()) {
auto button_vr = new Button(this, "VR");
button_vr->setFlags(Button::ToggleButton);
button_vr->setChangeCallback([this, button_vr](bool state) {
if (!screen_->isVR()) {
if (screen_->switchVR(true) == true) {
button_vr->setTextColor(nanogui::Color(0.5f,0.5f,1.0f,1.0f));
//this->button_channels_->setEnabled(false);
}
}
else {
if (screen_->switchVR(false) == false) {
button_vr->setTextColor(nanogui::Color(1.0f,1.0f,1.0f,1.0f));
//this->button_channels_->setEnabled(true);
}
}
});
}
#endif
button_channels_ = new PopupButton(this, "", ENTYPO_ICON_LAYERS);
button_channels_->setSide(Popup::Side::Right);
button_channels_->setChevronIcon(ENTYPO_ICON_CHEVRON_SMALL_RIGHT);
Popup *popup = button_channels_->popup();
popup->setLayout(new GroupLayout());
popup->setTheme(screen->toolbuttheme);
popup->setAnchorHeight(150);
for (int i=0; i<=2; ++i) {
ftl::codecs::Channel c = static_cast<ftl::codecs::Channel>(i);
button = new Button(popup, ftl::codecs::name(c));
button->setFlags(Button::RadioButton);
//button->setPushed(true);
button->setVisible(false);
button->setCallback([this,c]() {
ftl::gui::Camera *cam = screen_->activeCamera();
if (cam) {
cam->setChannel(c);
}
});
channel_buttons_[i] = button;
}
auto *stereobut = new Button(popup, "Stereo On");
stereobut->setCallback([this,stereobut]() {
ftl::gui::Camera *cam = screen_->activeCamera();
if (cam) {
cam->setStereo(!cam->isStereo());
if (cam->isStereo()) {
stereobut->setCaption("Stereo Off");
} else {
stereobut->setCaption("Stereo On");
}
}
});
auto *popbutton = new PopupButton(popup, "More");
popbutton->setSide(Popup::Side::Right);
popbutton->setChevronIcon(ENTYPO_ICON_CHEVRON_SMALL_RIGHT);
popup = popbutton->popup();
popup->setLayout(new GroupLayout());
popup->setTheme(screen->toolbuttheme);
//popup->setAnchorHeight(150);
more_button_ = popup;
for (int i=3; i<32; ++i) {
ftl::codecs::Channel c = static_cast<ftl::codecs::Channel>(i);
button = new Button(popup, ftl::codecs::name(c));
button->setFlags(Button::RadioButton);
//button->setPushed(true);
button->setVisible(false);
button->setCallback([this,c]() {
ftl::gui::Camera *cam = screen_->activeCamera();
if (cam) {
cam->setChannel(c);
}
});
channel_buttons_[i] = button;
}
}
MediaPanel::~MediaPanel() {
}
void MediaPanel::_startRecording(MediaPanel::RecordMode mode) {
char timestamp[18];
std::time_t t=std::time(NULL);
std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t));
std::string filename(timestamp);
switch(mode) {
case RecordMode::Snapshot2D : filename += ".png"; break;
case RecordMode::Snapshot3D :
case RecordMode::Video3D : filename += ".ftl"; break;
case RecordMode::Video2D : filename += ".ftl"; break;
case RecordMode::Live2D : break;
default: return;
}
if (mode == RecordMode::Video3D) {
record_mode_ = mode;
sourceWindow_->recordVideo(filename);
} else if (mode == RecordMode::Snapshot2D) {
screen_->activeCamera()->snapshot(filename);
} else if (mode == RecordMode::Video2D) {
record_mode_ = mode;
screen_->activeCamera()->startVideoRecording(filename, "");
} else if (mode == RecordMode::Live2D) {
record_mode_ = mode;
screen_->activeCamera()->startVideoRecording("", "ftl://live.utu.fi");
}
}
void MediaPanel::_stopRecording() {
if (record_mode_ == RecordMode::Video3D) {
sourceWindow_->stopRecordingVideo();
} else if (record_mode_ == RecordMode::Video2D || record_mode_ == RecordMode::Live2D) {
screen_->activeCamera()->stopVideoRecording();
}
record_mode_ = RecordMode::None;
}
// Update button enabled status
void MediaPanel::cameraChanged() {
ftl::gui::Camera *cam = screen_->activeCamera();
if (cam) {
auto channels = cam->availableChannels();
for (int i=0; i<32; ++i) {
if (channels.has(static_cast<ftl::codecs::Channel>(i))) {
channel_buttons_[i]->setVisible(true);
} else {
channel_buttons_[i]->setVisible(false);
}
if (cam->getChannel() == static_cast<ftl::codecs::Channel>(i)) {
channel_buttons_[i]->setPushed(true);
} else {
channel_buttons_[i]->setPushed(false);
}
}
}
}
void MediaPanel::performLayout(NVGcontext *ctx) {
nanogui::Window::performLayout(ctx);
more_button_->setAnchorHeight(more_button_->height()-20);
}
void MediaPanel::recordWindowClosed() {
recordbutton_->setEnabled(true);
}
\ No newline at end of file
#ifndef _FTL_GUI_MEDIAPANEL_HPP_
#define _FTL_GUI_MEDIAPANEL_HPP_
#include "camera.hpp"
#include <nanogui/window.h>
#include "src_window.hpp"
#include <array>
namespace ftl {
namespace rgbd {
class SnapshotStreamWriter;
}
namespace gui {
class Screen;
class MediaPanel : public nanogui::Window {
public:
explicit MediaPanel(ftl::gui::Screen *, ftl::gui::SourceWindow *);
~MediaPanel();
void cameraChanged();
//void startRecording2D(ftl::gui::Camera *camera, const std::string &filename);
//void snapshot3D(ftl::gui::Camera *camera, const std::string &filename);
//void startRecording3D(ftl::gui::Camera *camera, const std::string &filename);
void recordWindowClosed();
void performLayout(NVGcontext *ctx) override;
private:
ftl::gui::Screen *screen_;
ftl::gui::SourceWindow *sourceWindow_;
bool paused_;
bool disable_switch_channels_;
ftl::rgbd::SnapshotStreamWriter *writer_;
nanogui::PopupButton *button_channels_;
//nanogui::Button *right_button_;
//nanogui::Button *depth_button_;
nanogui::Popup *more_button_;
nanogui::PopupButton *recordbutton_;
std::array<nanogui::Button*,32> channel_buttons_={};
enum class RecordMode {
None,
Snapshot2D,
Snapshot3D,
Video2D,
Video3D,
Live2D,
Live3D
};
RecordMode record_mode_;
void _startRecording(RecordMode mode);
void _stopRecording();
/**
* These members indicate which type of recording is active, if any.
* They also include a pointer to an object which is used
* to end the recording. Only one of these members should have a value
* at any given time.
*/
//std::optional<ftl::gui::Camera*> virtualCameraRecording_;
//std::optional<ftl::Configurable*> sceneRecording_;
};
}
}
#endif // _FTL_GUI_MEDIAPANEL_HPP_
#include "pose_window.hpp"
#include "screen.hpp"
#include "camera.hpp"
#include <nanogui/combobox.h>
#include <nanogui/label.h>
#include <nanogui/layout.h>
#include <nanogui/button.h>
using ftl::gui::PoseWindow;
using ftl::gui::Screen;
using std::string;
static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) {
Eigen::Affine3d rx =
Eigen::Affine3d(Eigen::AngleAxisd(ax, Eigen::Vector3d(1, 0, 0)));
Eigen::Affine3d ry =
Eigen::Affine3d(Eigen::AngleAxisd(ay, Eigen::Vector3d(0, 1, 0)));
Eigen::Affine3d rz =
Eigen::Affine3d(Eigen::AngleAxisd(az, Eigen::Vector3d(0, 0, 1)));
return ry * rz * rx;
}
PoseWindow::PoseWindow(ftl::gui::Screen *screen, const std::string &src)
: nanogui::Window(screen, "Pose Adjust"), src_(src), screen_(screen) {
using namespace nanogui;
//setLayout(new nanogui::GroupLayout());
setLayout(new BoxLayout(Orientation::Vertical,
Alignment::Middle, 0, 6));
pose_param_ = kPoseTranslation;
pose_precision_ = 0.1;
pose_ = screen_->control()->getPose(src_);
//Widget *tools = new Widget(this);
// tools->setLayout(new BoxLayout(Orientation::Horizontal,
// Alignment::Middle, 0, 6));
auto grouping = new Widget(this);
grouping->setLayout(new GroupLayout());
new Label(grouping, "Select source","sans-bold");
available_ = screen_->net()->findAll<string>("list_streams");
auto select = new ComboBox(grouping, available_);
select->setSelectedIndex(std::distance(available_.begin(), std::find(available_.begin(), available_.end(), src_)));
select->setCallback([this,select](int ix) {
src_ = available_[ix];
pose_ = screen_->control()->getPose(src_);
});
screen_->net()->onConnect([this,select](ftl::net::Peer *p) {
available_ = screen_->control()->getNet()->findAll<string>("list_streams");
select->setItems(available_);
});
new Label(grouping, "Pose Options","sans-bold");
auto tools = new Widget(grouping);
tools->setLayout(new BoxLayout(Orientation::Horizontal,
Alignment::Middle, 0, 6));
auto button_opt = new Button(tools, "", ENTYPO_ICON_EYE);
button_opt->setTooltip("Virtual view to this pose");
//button_opt->setFlags(Button::ToggleButton);
//button_opt->setPushed(false);
button_opt->setCallback([this]() {
screen_->activeCamera()->setPose(pose_);
});
button_opt = new Button(tools, "", ENTYPO_ICON_LINK);
button_opt->setTooltip("Link virtual current pose to this pose");
button_opt->setFlags(Button::ToggleButton);
button_opt->setPushed(false);
button_opt->setChangeCallback([this](bool state) { });
tools = new Widget(grouping);
tools->setLayout(new BoxLayout(Orientation::Horizontal,
Alignment::Middle, 0, 6));
auto button_rgb = new Button(tools, "Translation");
button_rgb->setTooltip("Adjust camera location");
button_rgb->setFlags(Button::RadioButton);
button_rgb->setPushed(true);
button_rgb->setCallback([this]() { pose_param_ = kPoseTranslation; });
auto button_depth = new Button(tools, "Rotation");
button_depth->setFlags(Button::RadioButton);
button_depth->setCallback([this]() { pose_param_ = kPoseRotation; });
auto button_stddev = new Button(tools, "Raw");
button_stddev->setTooltip("Edit the numbers directly");
button_stddev->setFlags(Button::RadioButton);
button_stddev->setChangeCallback([this](bool state) { pose_param_ = kPoseRaw; });
tools = new Widget(grouping);
tools->setLayout(new BoxLayout(Orientation::Horizontal,
Alignment::Middle, 0, 6));
auto button = new Button(tools, "0.1m");
button->setFlags(Button::RadioButton);
button->setPushed(true);
button->setCallback([this](){
pose_precision_ = 0.1f;
});
button = new Button(tools, "0.01m");
button->setFlags(Button::RadioButton);
button->setCallback([this](){
pose_precision_ = 0.01f;
});
button = new Button(tools, "0.001m");
button->setFlags(Button::RadioButton);
button->setCallback([this](){
pose_precision_ = 0.001f;
});
tools = new Widget(this);
auto grid = new GridLayout(Orientation::Horizontal, 3, Alignment::Middle, 5, 4);
tools->setLayout(grid);
tools->setFixedWidth(150);
button = new Button(tools, "Up");
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(0.0,-pose_precision_,0.0));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(pose_precision_, 0.0, 0.0);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
button = new Button(tools, "", ENTYPO_ICON_CHEVRON_UP);
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(0.0,0.0,-pose_precision_));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(0.0, 0.0, pose_precision_);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
button = new Button(tools, "Down");
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(0.0,pose_precision_,0.0));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(-pose_precision_, 0.0, 0.0);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
button = new Button(tools, "", ENTYPO_ICON_CHEVRON_LEFT);
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(-pose_precision_,0.0,0.0));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(0.0, pose_precision_, 0.0);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
new Widget(tools);
button = new Button(tools, "", ENTYPO_ICON_CHEVRON_RIGHT);
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(pose_precision_,0.0,0.0));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(0.0, -pose_precision_, 0.0);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
new Widget(tools);
button = new Button(tools, "", ENTYPO_ICON_CHEVRON_DOWN);
button->setCallback([this]() {
if (pose_param_ == kPoseTranslation) {
Eigen::Affine3d transform(Eigen::Translation3d(0.0,0.0,pose_precision_));
Eigen::Matrix4d matrix = transform.matrix();
pose_ *= matrix;
} else if (pose_param_ == kPoseRotation) {
Eigen::Affine3d r = create_rotation_matrix(0.0, 0.0, -pose_precision_);
pose_ = r.matrix() * pose_;
}
screen_->control()->setPose(src_, pose_);
});
}
PoseWindow::~PoseWindow() {
}
#ifndef _FTL_GUI_POSEWINDOW_HPP_
#define _FTL_GUI_POSEWINDOW_HPP_
#include <nanogui/window.h>
#include <ftl/master.hpp>
#include <ftl/uuid.hpp>
namespace ftl {
namespace gui {
class Screen;
/**
* Manage connected nodes and add new connections.
*/
class PoseWindow : public nanogui::Window {
public:
PoseWindow(ftl::gui::Screen *screen, const std::string &src);
~PoseWindow();
private:
std::vector<std::string> available_;
std::string src_;
enum poseparameter_t {
kPoseTranslation,
kPoseRotation,
kPoseRaw
};
poseparameter_t pose_param_;
float pose_precision_;
Eigen::Matrix4d pose_;
ftl::gui::Screen *screen_;
bool poselink_;
};
}
}
#endif // _FTL_GUI_POSEWINDOW_HPP_
#include "record_window.hpp"
#include "screen.hpp"
#include <ftl/codecs/channels.hpp>
#include <nanogui/layout.h>
#include <nanogui/button.h>
#include <nanogui/combobox.h>
#include <nanogui/label.h>
#include <nanogui/textbox.h>
#include <nanogui/tabwidget.h>
using ftl::gui::RecordWindow;
RecordWindow::RecordWindow(nanogui::Widget *parent, ftl::gui::Screen *screen, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel)
: nanogui::Window(parent, "Recording options") {
using namespace nanogui;
setLayout(new GroupLayout());
new Label(this, "File name", "sans-bold");
char timestamp[18];
std::time_t t = std::time(NULL);
std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t));
Widget *fileNameBox = new Widget(this);
fileNameBox->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 6));
auto fileName = new TextBox(fileNameBox, std::string(timestamp));
fileName->setFixedWidth(350);
fileName->setEditable(true);
auto extension = new Label(fileNameBox, ".png", "sans-bold");
new Label(this, "Select stream", "sans-bold");
auto streamNames = std::vector<std::string>();
streamNames.reserve(streams.size());
std::optional<int> ix;
int i=1;
for (const auto s : streams) {
if (s == screen->activeCamera()) {
ix = std::optional<int>(streamNames.size());
}
streamNames.push_back(std::string("Stream")+std::to_string(i++));
}
auto streamSelect = new ComboBox(this, streamNames);
TabWidget *tabWidget = add<TabWidget>();
tabWidget->setFixedWidth(400);
auto snapshot2D = tabWidget->createTab("2D snapshot");
auto recording2D = tabWidget->createTab("2D recording");
auto snapshot3D = tabWidget->createTab("3D snapshot");
auto recording3D = tabWidget->createTab("3D recording");
snapshot2D->setLayout(new GroupLayout());
recording2D->setLayout(new GroupLayout());
snapshot3D->setLayout(new GroupLayout());
recording3D->setLayout(new GroupLayout());
// Set the file name extension based on the type of recording chosen.
tabWidget->setCallback([tabWidget,snapshot2D,extension](int ix) {
if (tabWidget->tab(ix) == snapshot2D) {
extension->setCaption(".png");
} else {
extension->setCaption(".ftl");
}
});
tabWidget->setActiveTab(0);
new Label(recording2D, "Select channel (in addition to Left)", "sans-bold");
auto recordingChannel = recording2D->add<ComboBox>();
auto streamCallback = [this,streams,recordingChannel](int ix) {
channels_ = std::vector<ftl::codecs::Channel>();
channel_names_ = std::vector<std::string>();
ftl::codecs::Channels availableChannels = streams[ix]->availableChannels();
for (auto c : availableChannels) {
channels_.push_back(c);
channel_names_.push_back(ftl::codecs::name(c));
}
recordingChannel->setItems(channel_names_);
};
streamSelect->setCallback(streamCallback);
// Set the selection to the active stream and set the channel list
// to be the channels available in that stream. The callback must
// be called explicitly, since setSelectedIndex() does not trigger it.
if (ix) {
streamSelect->setSelectedIndex(ix.value());
streamCallback(ix.value());
}
Widget *actionButtons = new Widget(this);
actionButtons->setLayout(new BoxLayout(Orientation::Horizontal));
auto button = new Button(actionButtons, "Start");
button->setCallback([this,streams,streamSelect,screen,media_panel,fileName,extension,tabWidget,snapshot2D,recording2D,snapshot3D,recording3D,recordingChannel]() {
// Check the chosen stream type and channels, then record them.
std::string name = fileName->value() + extension->caption();
auto stream = streams[streamSelect->selectedIndex()];
auto tab = tabWidget->tab(tabWidget->activeTab());
if (tab == snapshot2D) {
stream->snapshot(name);
} else if (tab == recording2D) {
stream->setChannel(channels_[recordingChannel->selectedIndex()]);
screen->setActiveCamera(stream);
//media_panel->startRecording2D(stream, name);
} else if (tab == snapshot3D) {
//media_panel->snapshot3D(stream, name);
} else if (tab == recording3D) {
//media_panel->startRecording3D(stream, name);
}
dispose();
media_panel->recordWindowClosed();
});
button = new Button(actionButtons, "Cancel");
button->setCallback([this,media_panel]() {
dispose();
media_panel->recordWindowClosed();
});
}
RecordWindow::~RecordWindow() {
}
#include <nanogui/window.h>
#include "camera.hpp"
#include "media_panel.hpp"
namespace ftl {
namespace gui {
class RecordWindow : public nanogui::Window {
public:
explicit RecordWindow(nanogui::Widget *parent, ftl::gui::Screen *screen, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel);
~RecordWindow();
private:
std::vector<ftl::codecs::Channel> channels_;
std::vector<std::string> channel_names_;
};
}
}
\ No newline at end of file
#ifndef _FTL_GUI_SCENE_HPP_
#define _FTL_GUI_SCENE_HPP_
#include <ftl/streams/receiver.hpp>
namespace ftl {
namespace gui {
class Camera;
class Scene {
public:
explicit Scene(ftl::stream::Receiver *);
~Scene();
inline const std::vector<ftl::gui::Camera*> cameras() const { return cameras_; };
private:
std::vector<ftl::gui::Camera*> cameras_;
};
}
}
#endif // _FTL_GUI_SCENE_HPP_
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment