diff --git a/applications/gui/src/config_window.cpp b/applications/gui/src/config_window.cpp index 6dd1b4d8a6a7311668a0dd7f35b23dfa6117b700..54480a617d4b56a069ab5866e603d8f1c2a1c6d7 100644 --- a/applications/gui/src/config_window.cpp +++ b/applications/gui/src/config_window.cpp @@ -1,4 +1,5 @@ #include "config_window.hpp" +#include "../screen.hpp" #include <nanogui/layout.h> #include <nanogui/label.h> @@ -190,7 +191,7 @@ void ConfigWindow::_addElements(nanogui::FormHelper *form, const std::string &su }); } 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]() { @@ -213,7 +214,8 @@ void ConfigWindow::_buildForm(const std::string &suri) { FormHelper *form = new FormHelper(this->screen()); //form->setWindow(this); form->addWindow(Vector2i(100,50), uri.getFragment()); - form->window()->setTheme(theme()); + auto* theme = dynamic_cast<ftl::gui2::Screen*>(screen())->getTheme("window"); + form->window()->setTheme(theme); _addElements(form, suri); diff --git a/applications/gui2/CMakeLists.txt b/applications/gui2/CMakeLists.txt index 2a1b58a26f6d922b74b6bdaec5e4d520c9f94378..8f6e81cdbd8f67e8756d89954a0af3e8184132b3 100644 --- a/applications/gui2/CMakeLists.txt +++ b/applications/gui2/CMakeLists.txt @@ -3,7 +3,10 @@ #include_directories(${PROJECT_BINARY_DIR}) function(add_gui_module NAME) - list(APPEND GUI2SRC "src/modules/${NAME}.cpp") + get_filename_component(FULLPATH "src/modules/${NAME}.cpp" ABSOLUTE) + if (EXISTS ${FULLPATH}) + list(APPEND GUI2SRC "src/modules/${NAME}.cpp") + endif() get_filename_component(FULLPATH "src/views/${NAME}.cpp" ABSOLUTE) if (EXISTS ${FULLPATH}) @@ -22,8 +25,10 @@ set(GUI2SRC src/frameview.cpp ) +add_gui_module("themes") add_gui_module("config") add_gui_module("camera") +add_gui_module("camera3d") add_gui_module("thumbnails") add_gui_module("soundctrl") diff --git a/applications/gui2/src/frameview.cpp b/applications/gui2/src/frameview.cpp index 06250a08f197871f3200dd7da2ae14f6d00836b0..5de6193df9c51cd2fb3bb7b37c521bb360638a8e 100644 --- a/applications/gui2/src/frameview.cpp +++ b/applications/gui2/src/frameview.cpp @@ -135,7 +135,7 @@ void buildFrameViewShader(nanogui::GLShader &shader, std::string name, std::stri // ============================================================================= FrameView::FrameView(nanogui::Widget *parent) : - Widget(parent), texture(ftl::gui2::GLTexture::Type::BGRA) { + Widget(parent), texture(ftl::gui2::GLTexture::Type::BGRA), fs_(nullptr) { if (glfwGetCurrentContext() == nullptr) { throw FTL_Error("No current OpenGL context"); @@ -144,6 +144,13 @@ FrameView::FrameView(nanogui::Widget *parent) : buildShader(Channel::Colour); } +void FrameView::reset() { + std::atomic_store(&fs_, {}); + if (texture.isValid()) { + texture.free(); + } +} + void FrameView::draw(NVGcontext *ctx) { Widget::draw(ctx); diff --git a/applications/gui2/src/frameview.hpp b/applications/gui2/src/frameview.hpp index ac52045aaaecd681f7e1d841f5f1f0253f7dac4b..1b53d1511c52f86082f756d9c2a693e26178bf9c 100644 --- a/applications/gui2/src/frameview.hpp +++ b/applications/gui2/src/frameview.hpp @@ -18,9 +18,8 @@ class FrameView : public nanogui::Widget { private: GLTexture texture; nanogui::GLShader mShader; - bool flush_ = true; - std::shared_ptr<ftl::data::FrameSet> fs_; + bool flush_ = true; int fid_ = 0; ftl::codecs::Channel channel_ = ftl::codecs::Channel::Colour; cudaStream_t stream_; @@ -32,6 +31,7 @@ private: /** loads a new shader if necessary */ void buildShader(ftl::codecs::Channel c); + public: FrameView(nanogui::Widget* parent); virtual void draw(NVGcontext *ctx) override; @@ -41,6 +41,7 @@ public: void setVmin(float v) { vmax_ = v; } float vmax() { return vmax_; } float vmin() { return vmin_; } + void reset(); /** Set frame. If copy == true, buffer will be copied to OpenGL framebuffer * at next draw() call. Can be called from any thread. Saves parameters diff --git a/applications/gui2/src/main.cpp b/applications/gui2/src/main.cpp index c02130d2620a8d7723fc8c0cdf1340ee094ab0b6..8d61ab0e3585e0a657910c9438c6d20c9c396f92 100644 --- a/applications/gui2/src/main.cpp +++ b/applications/gui2/src/main.cpp @@ -64,6 +64,7 @@ FTLGui::FTLGui(int argc, char **argv) { net_->start(); net_->waitConnections(); + loadModule<Themes>("themes"); loadModule<ThumbnailsController>("home")->activate(); loadModule<Camera>("camera"); loadModule<ConfigCtrl>("configwindow"); diff --git a/applications/gui2/src/modules.hpp b/applications/gui2/src/modules.hpp index 253a88cabc96961684becb7a5b99a35053a9d8b2..db1cd52b53cbe356e810f742f2f76a2788b6630a 100644 --- a/applications/gui2/src/modules.hpp +++ b/applications/gui2/src/modules.hpp @@ -4,3 +4,4 @@ #include "modules/camera.hpp" #include "modules/config.hpp" #include "modules/soundctrl.hpp" +#include "modules/themes.hpp" diff --git a/applications/gui2/src/modules/camera.cpp b/applications/gui2/src/modules/camera.cpp index 1a7ab41d87758c4b9f7d2036ea2f15731bd493e6..1c7c656be0ee1e9d8cb6bd2450f23b0925d1ce88 100644 --- a/applications/gui2/src/modules/camera.cpp +++ b/applications/gui2/src/modules/camera.cpp @@ -1,23 +1,35 @@ #include "camera.hpp" +#include "../views/camera3d.hpp" + using ftl::gui2::Camera; using ftl::codecs::Channel; void Camera::activate() { - view = new ftl::gui2::CameraView(screen); + panel = new ftl::gui2::MediaPanel(screen, this); filter = io->feed()->filter({Channel::Left, Channel::Right, Channel::Depth}); - std::unordered_set<Channel> available = filter->availableChannels(); - panel->setAvailableChannels(available); - filter->on( [this](const ftl::data::FrameSetPtr& fs){ + if (paused || !view) { return true; } + std::atomic_store(&active_fs, fs); view->update(fs, source_idx); screen->redraw(); return true; } ); +} + +void Camera::setSource(int idx) { + source_idx = idx; + + if (idx == 0) { + view = new ftl::gui2::CameraView(screen); + } + else { + view = new ftl::gui2::CameraView3D(screen); + } view->onClose([filter = this->filter, panel=this->panel](){ filter->remove(); @@ -28,6 +40,8 @@ void Camera::activate() { } }); + std::unordered_set<Channel> available = filter->availableChannels(); + panel->setAvailableChannels(available); if (available.count(channel) > 0) { setChannel(channel); } @@ -36,14 +50,26 @@ void Camera::activate() { } screen->setView(view); -} -void Camera::setSource(int idx) { - source_idx = idx; + if (active_fs && !(*active_fs)[source_idx].hasChannel(channel)) { + view->reset(); + } + + if (paused && active_fs) { + view->update(active_fs, source_idx); + } } void Camera::setChannel(Channel c) { channel = c; view->setChannel(c); panel->setActiveChannel(channel); + + if (active_fs && !(*active_fs)[source_idx].hasChannel(channel)) { + view->reset(); + } + + if (paused && active_fs) { + view->update(active_fs, source_idx); + } } diff --git a/applications/gui2/src/modules/camera.hpp b/applications/gui2/src/modules/camera.hpp index f7a1db023465c3b46cfbfa43bf8f627cedfa9c55..203478ef49262d6e234a880ac02a8e7ebca24740 100644 --- a/applications/gui2/src/modules/camera.hpp +++ b/applications/gui2/src/modules/camera.hpp @@ -15,11 +15,17 @@ public: void setSource(int); void setChannel(ftl::codecs::Channel c); + void setPaused(bool set) { paused = set; }; + bool isPaused() { return paused; } private: int source_idx = -1; + std::atomic_bool paused = false; // TODO: implement in InputOutput + ftl::codecs::Channel channel = ftl::codecs::Channel::Colour; ftl::stream::Feed::Filter *filter = nullptr; + ftl::data::FrameSetPtr active_fs; + CameraView* view = nullptr; MediaPanel* panel = nullptr; }; diff --git a/applications/gui2/src/modules/soundctrl.cpp b/applications/gui2/src/modules/soundctrl.cpp index 76ebd209be6eadb837db36780197801cfbdef78e..64402d3f6fd69148514bcfbe0f8492a3e2e3c2f3 100644 --- a/applications/gui2/src/modules/soundctrl.cpp +++ b/applications/gui2/src/modules/soundctrl.cpp @@ -10,15 +10,30 @@ using ftl::gui2::SoundCtrl; void SoundCtrl::init() { - auto button = screen->addButton<nanogui::PopupButton>("", ENTYPO_ICON_CONTROLLER_VOLUME); + auto button = screen->addButton<nanogui::PopupButton>("", ENTYPO_ICON_SOUND); + if (io->speaker()->volume() == 0.0f) { + button->setIcon(ENTYPO_ICON_SOUND_MUTE); + } + button->setChevronIcon(-1); + auto popup = button->popup(); popup->setLayout(new nanogui::GroupLayout(15, 6, 14, 0)); new nanogui::Label(popup, "Volume"); auto slider = new nanogui::Slider(popup); + slider->setHighlightColor(screen->getColor("highlight1")); + slider->setHighlightedRange({0.0f, io->speaker()->volume()}); slider->setHeight(20); slider->setValue(io->speaker()->volume()); - slider->setCallback([io=io](float v){ + slider->setCallback([io=io, button, slider](float v){ io->speaker()->setVolume(v); + slider->setHighlightedRange({0.0f, io->speaker()->volume()}); + if (io->speaker()->volume() == 0.0f) { + button->setIcon(ENTYPO_ICON_SOUND_MUTE); + } + else { + button->setIcon(ENTYPO_ICON_SOUND); + } + }); popup->setFixedWidth(200); diff --git a/applications/gui2/src/modules/themes.cpp b/applications/gui2/src/modules/themes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f32612d201a450c76bcee5d62a03a8a2d7cd55f5 --- /dev/null +++ b/applications/gui2/src/modules/themes.cpp @@ -0,0 +1,56 @@ +#include "themes.hpp" +#include "nanogui/theme.h" +#include "../screen.hpp" + +using ftl::gui2::Themes; +using nanogui::Theme; + +void Themes::init() { + auto* toolbuttheme = screen->getTheme("toolbutton"); + toolbuttheme->mBorderDark = nanogui::Color(0,0); + toolbuttheme->mBorderLight = nanogui::Color(0,0); + toolbuttheme->mButtonGradientBotFocused = nanogui::Color(60,255); + toolbuttheme->mButtonGradientBotUnfocused = nanogui::Color(0,0); + toolbuttheme->mButtonGradientTopFocused = nanogui::Color(60,255); + toolbuttheme->mButtonGradientTopUnfocused = nanogui::Color(0,0); + toolbuttheme->mButtonGradientTopPushed = nanogui::Color(60,180); + toolbuttheme->mButtonGradientBotPushed = nanogui::Color(60,180); + toolbuttheme->mTextColor = nanogui::Color(0.9f,0.9f,0.9f,0.9f); + toolbuttheme->mWindowDropShadowSize = 0; + toolbuttheme->mDropShadow = nanogui::Color(0,0); + + auto* windowtheme = screen->getTheme("window"); + windowtheme->mWindowHeaderGradientBot = nanogui::Color(0,0); + windowtheme->mWindowHeaderGradientTop = nanogui::Color(0,0); + windowtheme->mTextColor = nanogui::Color(20,255); + windowtheme->mWindowCornerRadius = 0; + windowtheme->mBorderDark = nanogui::Color(0,0); + windowtheme->mBorderMedium = nanogui::Color(0,0); + windowtheme->mBorderLight = nanogui::Color(0,0); + windowtheme->mWindowFillFocused = nanogui::Color(64, 0); + windowtheme->mWindowFillUnfocused= nanogui::Color(64, 0); + windowtheme->mWindowDropShadowSize = 0; + windowtheme->mDropShadow = nanogui::Color(0, 0); + + auto* mediatheme = screen->getTheme("media"); + mediatheme->mIconScale = 1.2f; + mediatheme->mWindowDropShadowSize = 0; + mediatheme->mWindowFillFocused = nanogui::Color(45, 150); + mediatheme->mWindowFillUnfocused = nanogui::Color(45, 80); + mediatheme->mButtonGradientTopUnfocused = nanogui::Color(0,0); + mediatheme->mButtonGradientBotUnfocused = nanogui::Color(0,0); + mediatheme->mButtonGradientTopFocused = nanogui::Color(80,230); + mediatheme->mButtonGradientBotFocused = nanogui::Color(80,230); + mediatheme->mIconColor = nanogui::Color(255,255); + mediatheme->mTextColor = nanogui::Color(1.0f,1.0f,1.0f,1.0f); + mediatheme->mBorderDark = nanogui::Color(0,0); + mediatheme->mBorderMedium = nanogui::Color(0,0); + mediatheme->mBorderLight = nanogui::Color(0,0); + mediatheme->mDropShadow = nanogui::Color(0,0); + mediatheme->mButtonFontSize = 30; + mediatheme->mStandardFontSize = 20; + + // https://flatuicolors.com/palette/defo + screen->setColor("highlight1", nanogui::Color(231, 76, 60, 255)); // red + screen->setColor("highlight2", nanogui::Color(52, 152, 219, 255)); // blue +} diff --git a/applications/gui2/src/modules/themes.hpp b/applications/gui2/src/modules/themes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..af5d7337ba4ecbbb20992f765f959de7da9ea049 --- /dev/null +++ b/applications/gui2/src/modules/themes.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "../module.hpp" + +namespace ftl +{ +namespace gui2 +{ + +class Themes : public Module { +public: + using Module::Module; + virtual void init() override; +}; +} +} diff --git a/applications/gui2/src/modules/thumbnails.cpp b/applications/gui2/src/modules/thumbnails.cpp index 442635ba61e973fe4bf554e2d6aa687bb4bcca8a..c8ed2e6c4ff7260e8a02c3ee36d38470a7144fb8 100644 --- a/applications/gui2/src/modules/thumbnails.cpp +++ b/applications/gui2/src/modules/thumbnails.cpp @@ -11,7 +11,7 @@ using ftl::codecs::Channel; using ftl::gui2::ThumbnailsController; void ThumbnailsController::init() { - button = screen->addButton(ENTYPO_ICON_CAMERA); + button = screen->addButton(ENTYPO_ICON_HOME); button->setCallback([this](){ button->setPushed(false); activate(); @@ -47,6 +47,6 @@ void ThumbnailsController::show_thumbnails() { void ThumbnailsController::show_camera(int frame_idx) { auto* camera = screen->getModule<ftl::gui2::Camera>(); - camera->setSource(frame_idx); camera->activate(); + camera->setSource(frame_idx); } diff --git a/applications/gui2/src/screen.cpp b/applications/gui2/src/screen.cpp index 80faf86aeb8d0161e0fcb774190ba305dde5690c..a971b3149d7e1c5d8045eb7473e5d3d3acb06936 100644 --- a/applications/gui2/src/screen.cpp +++ b/applications/gui2/src/screen.cpp @@ -34,55 +34,6 @@ Screen::Screen() : setSize(wsize); - // themes - auto toolbuttheme = new Theme(*theme()); - toolbuttheme->mBorderDark = nanogui::Color(0,0); - toolbuttheme->mBorderLight = nanogui::Color(0,0); - toolbuttheme->mButtonGradientBotFocused = nanogui::Color(60,255); - toolbuttheme->mButtonGradientBotUnfocused = nanogui::Color(0,0); - toolbuttheme->mButtonGradientTopFocused = nanogui::Color(60,255); - toolbuttheme->mButtonGradientTopUnfocused = nanogui::Color(0,0); - toolbuttheme->mButtonGradientTopPushed = nanogui::Color(60,180); - toolbuttheme->mButtonGradientBotPushed = nanogui::Color(60,180); - toolbuttheme->mTextColor = nanogui::Color(0.9f,0.9f,0.9f,0.9f); - toolbuttheme->mWindowDropShadowSize = 0; - toolbuttheme->mDropShadow = nanogui::Color(0,0); - - auto windowtheme = new Theme(*theme()); - windowtheme->mWindowHeaderGradientBot = nanogui::Color(0,0); - windowtheme->mWindowHeaderGradientTop = nanogui::Color(0,0); - windowtheme->mTextColor = nanogui::Color(20,255); - windowtheme->mWindowCornerRadius = 0; - windowtheme->mBorderDark = nanogui::Color(0,0); - windowtheme->mBorderMedium = nanogui::Color(0,0); - windowtheme->mBorderLight = nanogui::Color(0,0); - windowtheme->mWindowFillFocused = nanogui::Color(64, 0); - windowtheme->mWindowFillUnfocused= nanogui::Color(64, 0); - windowtheme->mWindowDropShadowSize = 0; - windowtheme->mDropShadow = nanogui::Color(0, 0); - - auto mediatheme = new Theme(*theme()); - mediatheme->mIconScale = 1.2f; - mediatheme->mWindowDropShadowSize = 0; - mediatheme->mWindowFillFocused = nanogui::Color(45, 150); - mediatheme->mWindowFillUnfocused = nanogui::Color(45, 80); - mediatheme->mButtonGradientTopUnfocused = nanogui::Color(0,0); - mediatheme->mButtonGradientBotUnfocused = nanogui::Color(0,0); - mediatheme->mButtonGradientTopFocused = nanogui::Color(80,230); - mediatheme->mButtonGradientBotFocused = nanogui::Color(80,230); - mediatheme->mIconColor = nanogui::Color(255,255); - mediatheme->mTextColor = nanogui::Color(1.0f,1.0f,1.0f,1.0f); - mediatheme->mBorderDark = nanogui::Color(0,0); - mediatheme->mBorderMedium = nanogui::Color(0,0); - mediatheme->mBorderLight = nanogui::Color(0,0); - mediatheme->mDropShadow = nanogui::Color(0,0); - mediatheme->mButtonFontSize = 30; - mediatheme->mStandardFontSize = 20; - - themes_["toolbutton"] = toolbuttheme; - themes_["window"] = windowtheme; - themes_["media"] = mediatheme; - toolbar_ = new FixedWindow(this); toolbar_->setPosition(Vector2i(0,0)); toolbar_->setFixedWidth(toolbar_w); @@ -114,6 +65,25 @@ Screen::~Screen() { } } + +nanogui::Theme* Screen::getTheme(const std::string &name) { + if (themes_.count(name) == 0) { + themes_[name] = new nanogui::Theme(*theme()); + } + return themes_[name]; +} + +nanogui::Color Screen::getColor(const std::string &name) { + if (colors_.count(name) == 0) { + return nanogui::Color(0, 0, 0, 0); + } + return colors_[name]; +} + +void Screen::setColor(const std::string &name, const nanogui::Color &c) { + colors_[name] = c; +} + void Screen::redraw() { // glfwPostEmptyEvent() is safe to call from any thread // https://www.glfw.org/docs/3.3/intro_guide.html#thread_safety @@ -170,3 +140,33 @@ ftl::gui2::Module* Screen::addModule_(const std::string &name, ftl::gui2::Module modules_[name] = ptr; return ptr; } + + +bool Screen::keyboardEvent(int key, int scancode, int action, int modifiers) { + + if (nanogui::Screen::keyboardEvent(key, scancode, action, modifiers)) { + return true; + } + + if (active_view_) { + // event not processed in any focused widget + return active_view_->keyboardEvent(key, scancode, action, modifiers); + } + + return false; +} + +bool Screen::keyboardCharacterEvent(unsigned int codepoint) { + + if (nanogui::Screen::keyboardCharacterEvent(codepoint)) { + return true; + } + + if (active_view_) { + // event not processed in any focused widget + return active_view_->keyboardCharacterEvent(codepoint); + } + + return false; +} + diff --git a/applications/gui2/src/screen.hpp b/applications/gui2/src/screen.hpp index fe0648a34c5a4a86f569872d18e327cf677920a1..485f4ad5c9aff3d193d2334f64fb35dcf6cd9ac6 100644 --- a/applications/gui2/src/screen.hpp +++ b/applications/gui2/src/screen.hpp @@ -20,9 +20,12 @@ namespace gui2 { * unless otherwise documented. */ class Screen : public nanogui::Screen { - public: +public: explicit Screen(); - ~Screen(); + virtual ~Screen(); + + virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override; + virtual bool keyboardCharacterEvent(unsigned int codepoint) override; void render(); // necessary? /** Redraw the screen (triggers an empty event). Thread safe. */ @@ -63,16 +66,18 @@ class Screen : public nanogui::Screen { template<typename T=nanogui::ToolButton, typename ... Args> T* addButton(Args ... args); - nanogui::Theme* getTheme(const std::string &name) { - return themes_[name]; - } + /** themes/colors */ + nanogui::Theme* getTheme(const std::string &name); + nanogui::Color getColor(const std::string &name); + void setColor(const std::string &name, const nanogui::Color &c); - private: +private: Module* addModule_(const std::string &name, Module* ptr); //std::mutex mtx_; // not used: do not modify gui outside gui (main) thread std::map<std::string, ftl::gui2::Module*> modules_; std::map<std::string, nanogui::ref<nanogui::Theme>> themes_; + std::map<std::string, nanogui::Color> colors_; nanogui::Widget *toolbar_; nanogui::Widget *tools_; diff --git a/applications/gui2/src/view.cpp b/applications/gui2/src/view.cpp index 9e65837bc5a143ed7106d365776d56dbb4fcae56..aeb818b769264713b4bdd1cf8fac5ac87d5f3a57 100644 --- a/applications/gui2/src/view.cpp +++ b/applications/gui2/src/view.cpp @@ -1,4 +1,3 @@ #include "view.hpp" using ftl::gui2::View; - diff --git a/applications/gui2/src/views/camera.cpp b/applications/gui2/src/views/camera.cpp index 33d6057d93c01d72a5c7f2b7330406b57da16dba..519431e8696dc34f5d50d496b5d4e51958ea0053 100644 --- a/applications/gui2/src/views/camera.cpp +++ b/applications/gui2/src/views/camera.cpp @@ -6,8 +6,8 @@ #include "camera.hpp" #include "../modules/camera.hpp" -using ftl::gui2::CameraView; using ftl::gui2::MediaPanel; +using ftl::gui2::CameraView; using ftl::codecs::Channel; @@ -24,6 +24,27 @@ MediaPanel::MediaPanel(nanogui::Widget *parent, ftl::gui2::Camera* ctrl) : auto theme = dynamic_cast<ftl::gui2::Screen*>(screen())->getTheme("media"); this->setTheme(theme); + // Pause/Unpause + // TODO: implement in InputOutput + + auto button_pause = new Button(this, "", ENTYPO_ICON_CONTROLLER_PAUS); + if (ctrl->isPaused()) { + button_pause->setIcon(ENTYPO_ICON_CONTROLLER_PLAY); + } + + button_pause->setCallback([ctrl = ctrl_ ,button_pause]() { + ctrl->setPaused(!ctrl->isPaused()); + + if (ctrl->isPaused()) { + button_pause->setIcon(ENTYPO_ICON_CONTROLLER_PLAY); + } else { + button_pause->setIcon(ENTYPO_ICON_CONTROLLER_PAUS); + } + }); + + // Channel select. Creates buttons for 32 channels and sets available ones + // visible (a bit of a hack, only used here and setAvailableChannels()) + button_channels = new PopupButton(this, "", ENTYPO_ICON_LAYERS); button_channels->setSide(Popup::Side::Right); button_channels->setChevronIcon(ENTYPO_ICON_CHEVRON_SMALL_RIGHT); @@ -47,14 +68,17 @@ MediaPanel::MediaPanel(nanogui::Widget *parent, ftl::gui2::Camera* ctrl) : MediaPanel::~MediaPanel() { auto popup = button_channels->popup(); popup->setVisible(false); - if (parent()->getRefCount() > 0 ) { // this should be patched in nanogui - popup->dispose(); // nanogui doesn't dispose + if (parent()->getRefCount() > 0 ) { // this and dispose should be patched + popup->dispose(); // in nanogui; nanogui doesn't dispose } } void MediaPanel::draw(NVGcontext *ctx) { auto size = this->size(); - setPosition(nanogui::Vector2i(screen()->width() / 2 - size[0]/2, screen()->height() - 30 - size[1])); + setPosition( + nanogui::Vector2i( screen()->width() / 2 - size[0]/2, + screen()->height() - 30 - size[1])); + FixedWindow::draw(ctx); } @@ -119,6 +143,10 @@ void CameraView::update(const ftl::data::FrameSetPtr& fs, int fid) { fview->set(fs, fid, channel, 0, true); } +void CameraView::reset() { + fview->reset(); +} + void CameraView::setChannel(ftl::codecs::Channel c) { channel = c; } diff --git a/applications/gui2/src/views/camera.hpp b/applications/gui2/src/views/camera.hpp index b18d50f6d8472c8b0ec2be1a6857f033c6e69438..46101be02560249a11e8a879288856c88468246b 100644 --- a/applications/gui2/src/views/camera.hpp +++ b/applications/gui2/src/views/camera.hpp @@ -35,7 +35,11 @@ public: void update(const ftl::data::FrameSetPtr& fs, int fid); void setChannel(ftl::codecs::Channel c); -private: + + /** reset buffer */ + void reset(); + +protected: ftl::gui2::FrameView *fview = nullptr; ftl::codecs::Channel channel = ftl::codecs::Channel::Colour; }; diff --git a/applications/gui2/src/views/camera3d.cpp b/applications/gui2/src/views/camera3d.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a89f32a92655fd788118a9fc3a8f0d68f5c34fa --- /dev/null +++ b/applications/gui2/src/views/camera3d.cpp @@ -0,0 +1,96 @@ +#include "camera3d.hpp" + +using ftl::gui2::CameraView3D; + +// ============================================================================= + +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 rz * rx * ry; +} + +// ==== CameraView3D =========================================================== + +CameraView3D::CameraView3D(nanogui::Widget *parent) : CameraView(parent) { + eye_ = Eigen::Vector3d::Zero(); + neye_ = Eigen::Vector4d::Zero(); + rotmat_.setIdentity(); + lerp_speed_ = 0.999f; +} + +bool CameraView3D::keyboardEvent(int key, int scancode, int action, int modifiers) { + if (key == 263 || key == 262) { + float mag = (modifiers & 0x1) ? 0.01f : 0.1f; + float scalar = (key == 263) ? -mag : mag; + neye_ += rotmat_*Eigen::Vector4d(scalar, 0.0, 0.0, 1.0); + } + else if (key == 264 || key == 265) { + float mag = (modifiers & 0x1) ? 0.01f : 0.1f; + float scalar = (key == 264) ? -mag : mag; + neye_ += rotmat_*Eigen::Vector4d(0.0, 0.0, scalar, 1.0); + } + else if (key == 266 || key == 267) { + float mag = (modifiers & 0x1) ? 0.01f : 0.1f; + float scalar = (key == 266) ? -mag : mag; + neye_ += rotmat_*Eigen::Vector4d(0.0, scalar, 0.0, 1.0); + } + else if (key >= '0' && key <= '5' && modifiers == 2) { // Ctrl+NUMBER + //int ix = key - (int)('0'); + //transform_ix_ = ix-1; + } + + return true; +} + +bool CameraView3D::mouseButtonEvent(const Eigen::Vector2i &p, int button, bool down, int modifiers) { + LOG(INFO) << "mouseButtonEvent: " << p; + return true; +} + +bool CameraView3D::mouseMotionEvent(const Eigen::Vector2i &p, const Eigen::Vector2i &rel, int button, int modifiers) { + if (button != 1) { + return false; + } + + rx_ += rel[0]; + ry_ += rel[1]; + + return true; +} + +bool CameraView3D::keyboardCharacterEvent(unsigned int codepoint) { + LOG(INFO) << "keyboardCharacterEvent: " << codepoint; + LOG(INFO) << getPose(); + return true; +} + +Eigen::Matrix4d CameraView3D::getUpdatedPose() { + double now = glfwGetTime(); + delta_ = now - ftime_; + ftime_ = now; + + float rrx = ((float)ry_ * 0.2f * delta_); + float rry = (float)rx_ * 0.2f * delta_; + float rrz = 0.0; + + Eigen::Affine3d r = create_rotation_matrix(rrx, -rry, rrz); + rotmat_ = rotmat_ * r.matrix(); + + rx_ = 0; + ry_ = 0; + + eye_[0] += (neye_[0] - eye_[0]) * lerp_speed_ * delta_; + eye_[1] += (neye_[1] - eye_[1]) * lerp_speed_ * delta_; + eye_[2] += (neye_[2] - eye_[2]) * lerp_speed_ * delta_; + + Eigen::Translation3d trans(eye_); + Eigen::Affine3d t(trans); + return t.matrix() * rotmat_; +} + +// ==== CameraView3DVR ========================================================= diff --git a/applications/gui2/src/views/camera3d.hpp b/applications/gui2/src/views/camera3d.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e6e65b9781f92a3c6a0ee7573fc8cf46e92d1894 --- /dev/null +++ b/applications/gui2/src/views/camera3d.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../window.hpp" +#include "../view.hpp" +#include "../gltexture.hpp" +#include "../frameview.hpp" + +#include "camera.hpp" + +namespace ftl { +namespace gui2 { + +class CameraView3D : public CameraView { +public: + CameraView3D(nanogui::Widget *parent); + + virtual bool keyboardEvent(int key, int scancode, int action, int modifiers) override; + virtual bool keyboardCharacterEvent(unsigned int codepoint) override; + virtual bool mouseMotionEvent(const Eigen::Vector2i &p, const Eigen::Vector2i &rel, int button, int modifiers) override; + virtual bool mouseButtonEvent(const Eigen::Vector2i &p, int button, bool down, int modifiers) override; + + Eigen::Matrix4d getUpdatedPose(); + +protected: + // updates from keyboard + Eigen::Vector4d neye_; + + // updates from mouse + double rx_; + double ry_; + + // current + Eigen::Vector3d eye_; + Eigen::Matrix4d rotmat_; + + // times for pose update + double ftime_; + double delta_; + + double lerp_speed_; +}; + +} +} diff --git a/components/audio/src/speaker.cpp b/components/audio/src/speaker.cpp index f6b20e546f43f1b258b2eb5201db0e7e66ef0837..b9abfb6d6ec5a59a00579e344f927580260d8f6b 100644 --- a/components/audio/src/speaker.cpp +++ b/components/audio/src/speaker.cpp @@ -139,11 +139,16 @@ void Speaker::queue(int64_t ts, ftl::audio::Frame &frame) { //LOG(INFO) << "Buffer Fullness (" << ts << "): " << buffer_->size() << " - " << audio.size(); for (const auto &d : audio) { - auto data = d.data(); - for (auto &v : data) { - v = v * volume_; + if (volume_ != 1.0) { + auto data = d.data(); + for (auto &v : data) { + v = v * volume_; + } + buffer_->write(data); + } + else { + buffer_->write(d.data()); } - buffer_->write(data); } //LOG(INFO) << "Audio delay: " << buffer_.delay() << "s"; } @@ -159,7 +164,8 @@ void Speaker::setDelay(int64_t ms) { } void Speaker::setVolume(float value) { - volume_ = value; + // TODO: adjust volume using system mixer + volume_ = std::max(0.0f, std::min(1.0f, value)); } float Speaker::volume() {