From cbdae0d4cfb26461612e41cad93dacc58699d831 Mon Sep 17 00:00:00 2001 From: Kevin Masson Date: Thu, 19 Mar 2020 22:21:51 +0100 Subject: [PATCH] split tabs into multiple files (opengl and finalrender) --- ...=> lightpaths_toolbar_next_light_path.png} | Bin ...aths_toolbar_next_light_path_disabled.png} | Bin ...htpaths_toolbar_next_light_path_hover.png} | Bin ...=> lightpaths_toolbar_prev_light_path.png} | Bin ...aths_toolbar_prev_light_path_disabled.png} | Bin ...htpaths_toolbar_prev_light_path_hover.png} | Bin ...> lightpaths_toolbar_save_light_paths.png} | Bin ...ths_toolbar_save_light_paths_disabled.png} | Bin ...tpaths_toolbar_save_light_paths_hover.png} | Bin ...pengl_viewport_tab_synchronize_camera.png} | Bin ...viewport_tab_synchronize_camera_hover.png} | Bin ..._viewport_tab_toggle_backface_culling.png} | Bin ...ort_tab_toggle_backface_culling_hover.png} | Bin sandbox/settings/appleseed.studio.xml | 5 + src/appleseed.studio/CMakeLists.txt | 14 +- .../mainwindow/mainwindow.cpp | 185 ++++-- src/appleseed.studio/mainwindow/mainwindow.h | 19 +- .../rendering/finalrenderviewporttab.cpp | 542 ++++++++++++++++++ .../rendering/finalrenderviewporttab.h | 138 +++++ .../mainwindow/rendering/lightpathslayer.cpp | 140 +---- .../mainwindow/rendering/lightpathslayer.h | 29 +- .../rendering/lightpathsmanager.cpp | 241 ++++++++ .../mainwindow/rendering/lightpathsmanager.h | 107 ++++ .../rendering/lightpathspickinghandler.cpp | 75 ++- .../rendering/lightpathspickinghandler.h | 18 +- .../rendering/lightpathsviewportmanager.cpp | 386 ------------- .../rendering/lightpathsviewporttoolbar.cpp | 240 ++++++++ ...tmanager.h => lightpathsviewporttoolbar.h} | 47 +- .../rendering/openglviewporttab.cpp | 268 +++++++++ .../mainwindow/rendering/openglviewporttab.h | 124 ++++ .../mainwindow/rendering/qttilecallback.cpp | 14 +- .../mainwindow/rendering/qttilecallback.h | 6 +- .../mainwindow/rendering/renderingmanager.cpp | 28 +- .../mainwindow/rendering/renderingmanager.h | 6 +- ...{viewportwidget.cpp => viewportcanvas.cpp} | 78 ++- .../{viewportwidget.h => viewportcanvas.h} | 17 +- .../mainwindow/rendering/viewporttab.cpp | 482 +--------------- .../mainwindow/rendering/viewporttab.h | 83 +-- .../resources/shaders/lightpaths.vert | 71 +-- 39 files changed, 2044 insertions(+), 1319 deletions(-) rename sandbox/icons/{lightpathstab_next_light_path.png => lightpaths_toolbar_next_light_path.png} (100%) rename sandbox/icons/{lightpathstab_next_light_path_disabled.png => lightpaths_toolbar_next_light_path_disabled.png} (100%) rename sandbox/icons/{lightpathstab_next_light_path_hover.png => lightpaths_toolbar_next_light_path_hover.png} (100%) rename sandbox/icons/{lightpathstab_prev_light_path.png => lightpaths_toolbar_prev_light_path.png} (100%) rename sandbox/icons/{lightpathstab_prev_light_path_disabled.png => lightpaths_toolbar_prev_light_path_disabled.png} (100%) rename sandbox/icons/{lightpathstab_prev_light_path_hover.png => lightpaths_toolbar_prev_light_path_hover.png} (100%) rename sandbox/icons/{lightpathstab_save_light_paths.png => lightpaths_toolbar_save_light_paths.png} (100%) rename sandbox/icons/{lightpathstab_save_light_paths_disabled.png => lightpaths_toolbar_save_light_paths_disabled.png} (100%) rename sandbox/icons/{lightpathstab_save_light_paths_hover.png => lightpaths_toolbar_save_light_paths_hover.png} (100%) rename sandbox/icons/{lightpathstab_synchronize_camera.png => opengl_viewport_tab_synchronize_camera.png} (100%) rename sandbox/icons/{lightpathstab_synchronize_camera_hover.png => opengl_viewport_tab_synchronize_camera_hover.png} (100%) rename sandbox/icons/{lightpathstab_toggle_backface_culling.png => opengl_viewport_tab_toggle_backface_culling.png} (100%) rename sandbox/icons/{lightpathstab_toggle_backface_culling_hover.png => opengl_viewport_tab_toggle_backface_culling_hover.png} (100%) create mode 100644 src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.cpp create mode 100644 src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.h create mode 100644 src/appleseed.studio/mainwindow/rendering/lightpathsmanager.cpp create mode 100644 src/appleseed.studio/mainwindow/rendering/lightpathsmanager.h delete mode 100644 src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp create mode 100644 src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.cpp rename src/appleseed.studio/mainwindow/rendering/{lightpathsviewportmanager.h => lightpathsviewporttoolbar.h} (66%) create mode 100644 src/appleseed.studio/mainwindow/rendering/openglviewporttab.cpp create mode 100644 src/appleseed.studio/mainwindow/rendering/openglviewporttab.h rename src/appleseed.studio/mainwindow/rendering/{viewportwidget.cpp => viewportcanvas.cpp} (88%) rename src/appleseed.studio/mainwindow/rendering/{viewportwidget.h => viewportcanvas.h} (90%) diff --git a/sandbox/icons/lightpathstab_next_light_path.png b/sandbox/icons/lightpaths_toolbar_next_light_path.png similarity index 100% rename from sandbox/icons/lightpathstab_next_light_path.png rename to sandbox/icons/lightpaths_toolbar_next_light_path.png diff --git a/sandbox/icons/lightpathstab_next_light_path_disabled.png b/sandbox/icons/lightpaths_toolbar_next_light_path_disabled.png similarity index 100% rename from sandbox/icons/lightpathstab_next_light_path_disabled.png rename to sandbox/icons/lightpaths_toolbar_next_light_path_disabled.png diff --git a/sandbox/icons/lightpathstab_next_light_path_hover.png b/sandbox/icons/lightpaths_toolbar_next_light_path_hover.png similarity index 100% rename from sandbox/icons/lightpathstab_next_light_path_hover.png rename to sandbox/icons/lightpaths_toolbar_next_light_path_hover.png diff --git a/sandbox/icons/lightpathstab_prev_light_path.png b/sandbox/icons/lightpaths_toolbar_prev_light_path.png similarity index 100% rename from sandbox/icons/lightpathstab_prev_light_path.png rename to sandbox/icons/lightpaths_toolbar_prev_light_path.png diff --git a/sandbox/icons/lightpathstab_prev_light_path_disabled.png b/sandbox/icons/lightpaths_toolbar_prev_light_path_disabled.png similarity index 100% rename from sandbox/icons/lightpathstab_prev_light_path_disabled.png rename to sandbox/icons/lightpaths_toolbar_prev_light_path_disabled.png diff --git a/sandbox/icons/lightpathstab_prev_light_path_hover.png b/sandbox/icons/lightpaths_toolbar_prev_light_path_hover.png similarity index 100% rename from sandbox/icons/lightpathstab_prev_light_path_hover.png rename to sandbox/icons/lightpaths_toolbar_prev_light_path_hover.png diff --git a/sandbox/icons/lightpathstab_save_light_paths.png b/sandbox/icons/lightpaths_toolbar_save_light_paths.png similarity index 100% rename from sandbox/icons/lightpathstab_save_light_paths.png rename to sandbox/icons/lightpaths_toolbar_save_light_paths.png diff --git a/sandbox/icons/lightpathstab_save_light_paths_disabled.png b/sandbox/icons/lightpaths_toolbar_save_light_paths_disabled.png similarity index 100% rename from sandbox/icons/lightpathstab_save_light_paths_disabled.png rename to sandbox/icons/lightpaths_toolbar_save_light_paths_disabled.png diff --git a/sandbox/icons/lightpathstab_save_light_paths_hover.png b/sandbox/icons/lightpaths_toolbar_save_light_paths_hover.png similarity index 100% rename from sandbox/icons/lightpathstab_save_light_paths_hover.png rename to sandbox/icons/lightpaths_toolbar_save_light_paths_hover.png diff --git a/sandbox/icons/lightpathstab_synchronize_camera.png b/sandbox/icons/opengl_viewport_tab_synchronize_camera.png similarity index 100% rename from sandbox/icons/lightpathstab_synchronize_camera.png rename to sandbox/icons/opengl_viewport_tab_synchronize_camera.png diff --git a/sandbox/icons/lightpathstab_synchronize_camera_hover.png b/sandbox/icons/opengl_viewport_tab_synchronize_camera_hover.png similarity index 100% rename from sandbox/icons/lightpathstab_synchronize_camera_hover.png rename to sandbox/icons/opengl_viewport_tab_synchronize_camera_hover.png diff --git a/sandbox/icons/lightpathstab_toggle_backface_culling.png b/sandbox/icons/opengl_viewport_tab_toggle_backface_culling.png similarity index 100% rename from sandbox/icons/lightpathstab_toggle_backface_culling.png rename to sandbox/icons/opengl_viewport_tab_toggle_backface_culling.png diff --git a/sandbox/icons/lightpathstab_toggle_backface_culling_hover.png b/sandbox/icons/opengl_viewport_tab_toggle_backface_culling_hover.png similarity index 100% rename from sandbox/icons/lightpathstab_toggle_backface_culling_hover.png rename to sandbox/icons/opengl_viewport_tab_toggle_backface_culling_hover.png diff --git a/sandbox/settings/appleseed.studio.xml b/sandbox/settings/appleseed.studio.xml index c6c30570ff..a212665c90 100644 --- a/sandbox/settings/appleseed.studio.xml +++ b/sandbox/settings/appleseed.studio.xml @@ -10,6 +10,11 @@ + + + + + diff --git a/src/appleseed.studio/CMakeLists.txt b/src/appleseed.studio/CMakeLists.txt index e347d4c82a..644b9d9402 100644 --- a/src/appleseed.studio/CMakeLists.txt +++ b/src/appleseed.studio/CMakeLists.txt @@ -252,16 +252,22 @@ source_group ("mainwindow\\pythonconsole" FILES set (mainwindow_rendering_sources mainwindow/rendering/cameracontroller.cpp mainwindow/rendering/cameracontroller.h + mainwindow/rendering/finalrenderviewporttab.cpp + mainwindow/rendering/finalrenderviewporttab.h mainwindow/rendering/glscenelayer.cpp mainwindow/rendering/glscenelayer.h mainwindow/rendering/lightpathslayer.cpp mainwindow/rendering/lightpathslayer.h + mainwindow/rendering/lightpathsmanager.cpp + mainwindow/rendering/lightpathsmanager.h mainwindow/rendering/lightpathspickinghandler.cpp mainwindow/rendering/lightpathspickinghandler.h - mainwindow/rendering/lightpathsviewportmanager.cpp - mainwindow/rendering/lightpathsviewportmanager.h + mainwindow/rendering/lightpathsviewporttoolbar.cpp + mainwindow/rendering/lightpathsviewporttoolbar.h mainwindow/rendering/materialdrophandler.cpp mainwindow/rendering/materialdrophandler.h + mainwindow/rendering/openglviewporttab.cpp + mainwindow/rendering/openglviewporttab.h mainwindow/rendering/pixelcolortracker.cpp mainwindow/rendering/pixelcolortracker.h mainwindow/rendering/pixelinspectorhandler.cpp @@ -282,8 +288,8 @@ set (mainwindow_rendering_sources mainwindow/rendering/viewportregionselectionhandler.h mainwindow/rendering/viewporttab.cpp mainwindow/rendering/viewporttab.h - mainwindow/rendering/viewportwidget.cpp - mainwindow/rendering/viewportwidget.h + mainwindow/rendering/viewportcanvas.cpp + mainwindow/rendering/viewportcanvas.h ) list (APPEND appleseed.studio_sources ${mainwindow_rendering_sources} diff --git a/src/appleseed.studio/mainwindow/mainwindow.cpp b/src/appleseed.studio/mainwindow/mainwindow.cpp index 6bf6081bc9..461510a069 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.cpp +++ b/src/appleseed.studio/mainwindow/mainwindow.cpp @@ -39,9 +39,12 @@ #include "mainwindow/project/attributeeditor.h" #include "mainwindow/project/projectexplorer.h" #include "mainwindow/pythonconsole/pythonconsolewidget.h" +#include "mainwindow/rendering/finalrenderviewporttab.h" +#include "mainwindow/rendering/lightpathsmanager.h" #include "mainwindow/rendering/materialdrophandler.h" +#include "mainwindow/rendering/openglviewporttab.h" #include "mainwindow/rendering/renderlayer.h" -#include "mainwindow/rendering/viewportwidget.h" +#include "mainwindow/rendering/viewportcanvas.h" #include "utility/settingskeys.h" // appleseed.qtcommon headers. @@ -131,7 +134,6 @@ MainWindow::MainWindow(QWidget* parent) , m_project_explorer(nullptr) , m_attribute_editor(nullptr) , m_project_file_watcher(nullptr) - , m_light_paths_tab(nullptr) { initialize_ocio(); @@ -728,6 +730,10 @@ void MainWindow::build_connections() connect( &m_rendering_manager, SIGNAL(signal_rendering_end()), SLOT(slot_rendering_end())); + + connect( + m_ui->tab_render_channels, &QTabWidget::currentChanged, + this, &MainWindow::slot_current_tab_changed); } void MainWindow::update_workspace() @@ -741,14 +747,6 @@ void MainWindow::update_workspace() set_diagnostics_widgets_enabled(true, RenderingMode::NotRendering); update_pause_resume_checkbox(false); m_ui->attribute_editor_scrollarea_contents->setEnabled(true); - - // Enable/disable light paths - const bool enable_light_paths_toogle = - m_project_manager.is_project_open() && - m_project_manager.get_project()->get_light_path_recorder().get_light_path_count() > 0; - - for (const std::pair& kvp : m_viewport_tabs) - kvp.second->set_light_paths_toggle_enabled(enable_light_paths_toogle); } void MainWindow::update_project_explorer() @@ -890,23 +888,21 @@ void MainWindow::set_rendering_widgets_enabled(const bool is_enabled, const Rend const int current_tab_index = m_ui->tab_render_channels->currentIndex(); if (current_tab_index != -1) { - const auto viewport_tab_it = m_tab_index_to_viewport_tab.find(current_tab_index); - if (viewport_tab_it != m_tab_index_to_viewport_tab.end()) - { - ViewportTab* viewport_tab = viewport_tab_it->second; + // Clear frame. + m_final_render_viewport_tab->set_clear_frame_button_enabled( + is_enabled && is_project_open && rendering_mode == RenderingMode::NotRendering); - // Clear frame. - viewport_tab->set_clear_frame_button_enabled( - is_enabled && is_project_open && rendering_mode == RenderingMode::NotRendering); + // Set/clear rendering region. + m_final_render_viewport_tab->set_render_region_buttons_enabled( + is_enabled && is_project_open && rendering_mode != RenderingMode::FinalRendering); - // Set/clear rendering region. - viewport_tab->set_render_region_buttons_enabled( - is_enabled && is_project_open && rendering_mode != RenderingMode::FinalRendering); + // Scene picker. + m_final_render_viewport_tab->get_scene_picking_handler()->set_enabled( + is_enabled && is_project_open && rendering_mode != RenderingMode::FinalRendering); - // Scene picker. - viewport_tab->get_scene_picking_handler()->set_enabled( - is_enabled && is_project_open && rendering_mode != RenderingMode::FinalRendering); - } + // Light paths overlay. + const bool enable_light_paths_overlay = is_enabled && is_project_open && rendering_mode == RenderingMode::NotRendering; + m_final_render_viewport_tab->set_light_paths_toggle_enabled(enable_light_paths_overlay); } } @@ -952,76 +948,134 @@ void MainWindow::recreate_viewport_tabs() if (m_project_manager.is_project_open()) { - add_viewport_tab("Beauty", ViewportWidget::BaseLayer::FinalRender); - add_viewport_tab("OpenGL", ViewportWidget::BaseLayer::OpenGL); + m_light_paths_manager.reset( + new LightPathsManager( + *m_project_manager.get_project(), + m_application_settings)); + + create_final_render_tab(); + create_opengl_tab(); + + // Connect tabs together once they are all created. + connect_tabs(); } } void MainWindow::remove_viewport_tabs() { + while (m_ui->tab_render_channels->count() > 0) + m_ui->tab_render_channels->removeTab(0); + for (const_each i = m_viewport_tabs; i; ++i) delete i->second; m_viewport_tabs.clear(); m_tab_index_to_viewport_tab.clear(); - while (m_ui->tab_render_channels->count() > 0) - m_ui->tab_render_channels->removeTab(0); + m_final_render_viewport_tab = 0; + m_opengl_viewport_tab = 0; } -void MainWindow::add_viewport_tab(const QString& label, const ViewportWidget::BaseLayer base_layer) +void MainWindow::create_final_render_tab() { - // Create render tab. - ViewportTab* viewport_tab = - new ViewportTab( - base_layer, + m_final_render_viewport_tab = + new FinalRenderViewportTab( *m_project_explorer, *m_project_manager.get_project(), m_rendering_manager, + *m_light_paths_manager, m_ocio_config, m_application_settings); - // Connect the render tab to the main window and the rendering manager. + // Connect the beauty viewport tab to the main window and the rendering manager. connect( - viewport_tab, SIGNAL(signal_viewport_widget_context_menu(const QPoint&)), - SLOT(slot_viewport_widget_context_menu(const QPoint&))); - connect( - viewport_tab, SIGNAL(signal_set_render_region(const QRect&)), + m_final_render_viewport_tab, SIGNAL(signal_set_render_region(const QRect&)), SLOT(slot_set_render_region(const QRect&))); connect( - viewport_tab, SIGNAL(signal_clear_render_region()), + m_final_render_viewport_tab, SIGNAL(signal_viewport_canvas_context_menu(const QPoint&)), + SLOT(slot_viewport_canvas_context_menu(const QPoint&))); + connect( + m_final_render_viewport_tab, SIGNAL(signal_clear_render_region()), SLOT(slot_clear_render_region())); connect( - viewport_tab, SIGNAL(signal_save_frame_and_aovs()), + m_final_render_viewport_tab, SIGNAL(signal_save_frame_and_aovs()), SLOT(slot_save_frame_and_aovs())); connect( - viewport_tab, SIGNAL(signal_quicksave_frame_and_aovs()), + m_final_render_viewport_tab, SIGNAL(signal_quicksave_frame_and_aovs()), SLOT(slot_quicksave_frame_and_aovs())); connect( - viewport_tab, SIGNAL(signal_reset_zoom()), + m_final_render_viewport_tab, SIGNAL(signal_reset_zoom()), SLOT(slot_reset_zoom())); connect( - viewport_tab, SIGNAL(signal_clear_frame()), + m_final_render_viewport_tab, SIGNAL(signal_clear_frame()), SLOT(slot_clear_frame())); connect( - viewport_tab, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), + m_final_render_viewport_tab, SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), SLOT(slot_clear_filter())); connect( - viewport_tab, SIGNAL(signal_camera_change_begin()), + m_final_render_viewport_tab, SIGNAL(signal_camera_change_begin()), &m_rendering_manager, SLOT(slot_camera_change_begin())); connect( - viewport_tab, SIGNAL(signal_camera_change_end()), + m_final_render_viewport_tab, SIGNAL(signal_camera_change_end()), &m_rendering_manager, SLOT(slot_camera_change_end())); connect( - viewport_tab, SIGNAL(signal_camera_changed()), + m_final_render_viewport_tab, SIGNAL(signal_camera_changed()), &m_rendering_manager, SLOT(slot_camera_changed())); - // Add the render tab to the tab bar. - const int tab_index = m_ui->tab_render_channels->addTab(viewport_tab, label); + m_final_render_viewport_tab_index = add_viewport_tab(m_final_render_viewport_tab, "Beauty"); +} + +void MainWindow::create_opengl_tab() +{ + m_opengl_viewport_tab = + new OpenGLViewportTab( + *m_project_explorer, + *m_project_manager.get_project(), + m_rendering_manager, + *m_light_paths_manager, + m_ocio_config, + m_application_settings); + + // Connect the opengl viewport tab to the main window and the rendering manager. + connect( + m_opengl_viewport_tab, SIGNAL(signal_viewport_canvas_context_menu(const QPoint&)), + SLOT(slot_viewport_canvas_context_menu(const QPoint&))); + connect( + m_opengl_viewport_tab, SIGNAL(signal_reset_zoom()), + SLOT(slot_reset_zoom())); + + m_opengl_viewport_tab_index = add_viewport_tab(m_opengl_viewport_tab, "OpenGL"); +} + +int MainWindow::add_viewport_tab(ViewportTab* viewport_tab, const QString& label) +{ + const int tab_index = static_cast(m_viewport_tabs.size()); - // Update mappings. + // Update mappings before inserting the tab. + // When inserting a tab, it may show the tab and + // trigger QTabWidget::currentChanged signal. + // We want to make sure our mappings are ready + // before running our slots. m_viewport_tabs[label.toStdString()] = viewport_tab; m_tab_index_to_viewport_tab[tab_index] = viewport_tab; + + // Add the viewport tab to the tab bar. + const int final_tab_index = m_ui->tab_render_channels->insertTab(tab_index, viewport_tab, label); + + assert(final_tab_index == tab_index); + + return final_tab_index; +} + +void MainWindow::connect_tabs() +{ + assert(m_final_render_viewport_tab); + assert(m_opengl_viewport_tab); + + // Connect final render tab light paths selection to opengl tab. + //connect( + //m_final_render_viewport_tab, &FinalRenderViewportTab::signal_entity_picked, + //m_opengl_viewport_tab, &OpenGLViewportTab::slot_entity_picked); } ParamArray MainWindow::get_project_params(const char* configuration_name) const @@ -1193,6 +1247,9 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) m_false_colors_window.reset(); + // Switch to the final render viewport tab. + m_ui->tab_render_channels->setCurrentIndex(m_final_render_viewport_tab_index); + // Enable/disable menus and widgets appropriately. set_file_widgets_enabled(false, rendering_mode); set_project_explorer_enabled(rendering_mode == RenderingMode::InteractiveRendering); @@ -1210,6 +1267,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) Project* project = m_project_manager.get_project(); Frame* frame = project->get_frame(); + project->get_light_path_recorder().clear(); frame->clear_main_and_aov_images(); // Darken render widgets. @@ -1230,7 +1288,7 @@ void MainWindow::start_rendering(const RenderingMode rendering_mode) rendering_mode == RenderingMode::InteractiveRendering ? RenderingManager::RenderingMode::InteractiveRendering : RenderingManager::RenderingMode::FinalRendering, - m_viewport_tabs["Beauty"]); + m_final_render_viewport_tab); } void MainWindow::apply_false_colors_settings() @@ -1270,8 +1328,8 @@ void MainWindow::apply_false_colors_settings() // Blit the regular frame into the render widget. for (const_each i = m_viewport_tabs; i; ++i) { - i->second->get_viewport_widget()->get_render_layer()->blit_frame(*frame); - i->second->get_viewport_widget()->get_render_layer()->update(); + i->second->get_viewport_canvas()->get_render_layer()->blit_frame(*frame); + i->second->get_viewport_canvas()->get_render_layer()->update(); } } } @@ -1293,8 +1351,8 @@ void MainWindow::apply_post_processing_stage( // Blit the frame copy into the render widget. for (const_each i = m_viewport_tabs; i; ++i) { - i->second->get_viewport_widget()->get_render_layer()->blit_frame(working_frame); - i->second->get_viewport_widget()->get_render_layer()->update(); + i->second->get_viewport_canvas()->get_render_layer()->blit_frame(working_frame); + i->second->get_viewport_canvas()->get_render_layer()->update(); } } } @@ -1898,7 +1956,7 @@ void MainWindow::slot_set_render_region(const QRect& rect) } } -void MainWindow::slot_viewport_widget_context_menu(const QPoint& point) +void MainWindow::slot_viewport_canvas_context_menu(const QPoint& point) { if (!(QApplication::keyboardModifiers() & Qt::ShiftModifier)) return; @@ -2038,7 +2096,7 @@ void MainWindow::slot_save_render_widget_content() return; // todo: this is sketchy. The render tab should be retrieved from the signal. - m_viewport_tabs["Beauty"]->get_viewport_widget()->get_render_layer()->capture().save(filepath); + m_viewport_tabs["Beauty"]->get_viewport_canvas()->get_render_layer()->capture().save(filepath); RENDERER_LOG_INFO("wrote image file %s.", filepath.toStdString().c_str()); } @@ -2051,9 +2109,7 @@ void MainWindow::slot_clear_frame() // Clear all render widgets to black. for (const std::pair& kvp : m_viewport_tabs) { - const auto viewport_widget = kvp.second->get_viewport_widget(); - viewport_widget->get_render_layer()->clear(); - viewport_widget->repaint(); + kvp.second->clear(); } } @@ -2116,6 +2172,15 @@ void MainWindow::slot_check_fullscreen() m_action_fullscreen->setChecked(is_fullscreen); } +void MainWindow::slot_current_tab_changed(int index) +{ + if (index == -1) return; + + ViewportTab* tab = m_tab_index_to_viewport_tab[index]; + + tab->on_tab_selected(); +} + void MainWindow::slot_show_application_settings_window() { if (m_application_settings_window.get() == nullptr) diff --git a/src/appleseed.studio/mainwindow/mainwindow.h b/src/appleseed.studio/mainwindow/mainwindow.h index 86527fd523..4904c9f73c 100644 --- a/src/appleseed.studio/mainwindow/mainwindow.h +++ b/src/appleseed.studio/mainwindow/mainwindow.h @@ -35,6 +35,8 @@ #include "mainwindow/applicationsettingswindow.h" #include "mainwindow/falsecolorswindow.h" #include "mainwindow/rendering/renderingmanager.h" +#include "mainwindow/rendering/finalrenderviewporttab.h" +#include "mainwindow/rendering/openglviewporttab.h" #include "mainwindow/rendering/viewporttab.h" #include "mainwindow/renderingsettingswindow.h" #include "mainwindow/statusbar.h" @@ -62,8 +64,8 @@ namespace OCIO = OCIO_NAMESPACE; // Forward declarations. namespace appleseed { namespace studio { class AttributeEditor; } } -namespace appleseed { namespace studio { class LightPathsTab; } } namespace appleseed { namespace studio { class MinimizeButton; } } +namespace appleseed { namespace studio { class LightPathsManager; } } namespace appleseed { namespace studio { class ProjectExplorer; } } namespace renderer { class Project; } namespace Ui { class MainWindow; } @@ -166,7 +168,12 @@ class MainWindow ViewportTabCollection m_viewport_tabs; std::map m_tab_index_to_viewport_tab; - LightPathsTab* m_light_paths_tab; + + FinalRenderViewportTab* m_final_render_viewport_tab; + int m_final_render_viewport_tab_index; + OpenGLViewportTab* m_opengl_viewport_tab; + int m_opengl_viewport_tab_index; + std::unique_ptr m_light_paths_manager; struct StateBeforeProjectOpen { @@ -210,7 +217,10 @@ class MainWindow // Render tabs. void recreate_viewport_tabs(); void remove_viewport_tabs(); - void add_viewport_tab(const QString& label, const ViewportWidget::BaseLayer base_layer); + void create_final_render_tab(); + void create_opengl_tab(); + int add_viewport_tab(ViewportTab* viewport_tab, const QString& label); + void connect_tabs(); // Project file handling. renderer::ParamArray get_project_params(const char* configuration_name) const; @@ -287,7 +297,7 @@ class MainWindow void slot_set_render_region(const QRect& rect); // Render widget actions. - void slot_viewport_widget_context_menu(const QPoint& point); + void slot_viewport_canvas_context_menu(const QPoint& point); void slot_save_frame(); void slot_save_frame_and_aovs(); void slot_quicksave_frame_and_aovs(); @@ -303,6 +313,7 @@ class MainWindow // General UI actions. void slot_fullscreen(); void slot_check_fullscreen(); + void slot_current_tab_changed(int index); // Child windows. void slot_show_application_settings_window(); diff --git a/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.cpp b/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.cpp new file mode 100644 index 0000000000..5e080424c4 --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.cpp @@ -0,0 +1,542 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "finalrenderviewporttab.h" + +// appleseed.studio headers. +#include "mainwindow/project/projectexplorer.h" +#include "mainwindow/rendering/lightpathspickinghandler.h" +#include "mainwindow/rendering/renderingmanager.h" + +// appleseed.renderer headers. +#include "renderer/api/frame.h" +#include "renderer/api/project.h" + +// appleseed.qtcommon headers. +#include "utility/miscellaneous.h" + +// Qt headers. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace appleseed::qtcommon; +using namespace foundation; +using namespace renderer; +namespace OCIO = OCIO_NAMESPACE; + +namespace appleseed { +namespace studio { + +FinalRenderViewportTab::FinalRenderViewportTab( + ProjectExplorer& project_explorer, + Project& project, + RenderingManager& rendering_manager, + LightPathsManager& light_paths_manager, + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings) + : ViewportTab( + project_explorer, + project, + rendering_manager, + ocio_config, + application_settings) + , m_light_paths_manager(light_paths_manager) +{ + setObjectName("final_render_viewport_tab"); + setLayout(new QGridLayout()); + layout()->setSpacing(0); + layout()->setMargin(0); + + create_viewport_canvas(); + create_toolbar(); + create_scrollarea(); + + recreate_handlers(); + + layout()->addWidget(m_toolbar); + layout()->addWidget(m_light_paths_viewport_toolbar->toolbar()); + layout()->addWidget(m_scroll_area); + + get_viewport_canvas()->set_base_layer(ViewportCanvas::BaseLayer::FinalRender); +} + +ViewportCanvas* FinalRenderViewportTab::get_viewport_canvas() const +{ + return m_viewport_canvas; +} + +void FinalRenderViewportTab::set_clear_frame_button_enabled(const bool enabled) +{ + m_clear_frame_button->setEnabled(enabled); +} + +void FinalRenderViewportTab::set_render_region_buttons_enabled(const bool enabled) +{ + m_set_render_region_button->setEnabled(enabled); + m_clear_render_region_button->setEnabled(enabled); +} + +void FinalRenderViewportTab::render_began() +{ + ViewportTab::render_began(); + + m_light_paths_viewport_toolbar.get()->reset(&m_project); +} + +void FinalRenderViewportTab::update_size() +{ + ViewportTab::update_size(); + + m_set_render_region_button->setChecked(false); + + recreate_handlers(); +} + +void FinalRenderViewportTab::on_tab_selected() +{ + const bool display_light_paths = m_light_paths_manager.should_display_light_paths(); + m_light_paths_viewport_toolbar->set_enabled(display_light_paths); + m_light_paths_toggle_button->setChecked(display_light_paths); +} + +CameraController* FinalRenderViewportTab::get_camera_controller() const +{ + return m_camera_controller.get(); +} + +ScenePickingHandler* FinalRenderViewportTab::get_scene_picking_handler() const +{ + return m_scene_picking_handler.get(); +} + +void FinalRenderViewportTab::slot_set_render_region(const QRect& rect) +{ + m_set_render_region_button->setChecked(false); +} + +void FinalRenderViewportTab::slot_camera_changed() +{ + m_viewport_canvas->get_light_paths_layer()->set_transform(m_camera_controller->get_transform()); + m_viewport_canvas->get_gl_scene_layer()->set_transform(m_camera_controller->get_transform()); + update(); +} + +void FinalRenderViewportTab::slot_toggle_render_region(const bool checked) +{ + m_scene_picking_handler->set_enabled(!checked); + m_viewport_selection_handler->set_mode( + checked + ? ViewportRegionSelectionHandler::RenderRegionMode + : ViewportRegionSelectionHandler::RectangleSelectionMode); +} + +void FinalRenderViewportTab::slot_toggle_light_paths(const bool checked) +{ + m_light_paths_picking_handler->set_enabled(checked); + m_light_paths_viewport_toolbar->set_enabled(checked); + m_scene_picking_handler->set_enabled(!checked); + m_light_paths_manager.display_light_paths(checked); +} + +void FinalRenderViewportTab::slot_toggle_pixel_inspector(const bool checked) +{ + m_pixel_inspector_handler->set_enabled(checked); + m_pixel_inspector_handler->update_tooltip_visibility(); +} + +void FinalRenderViewportTab::slot_viewport_canvas_context_menu(const QPoint& point) +{ + emit signal_viewport_canvas_context_menu(m_viewport_canvas->mapToGlobal(point)); +} + +void FinalRenderViewportTab::slot_clear_frame() +{ + m_light_paths_toggle_button->setChecked(false); + m_light_paths_toggle_button->setEnabled(false); + m_light_paths_picking_handler->set_enabled(false); + m_light_paths_viewport_toolbar->set_enabled(false); + m_scene_picking_handler->set_enabled(false); + m_light_paths_manager.clear_light_paths_selection(); + + emit signal_clear_frame(); +} + +void FinalRenderViewportTab::create_viewport_canvas() +{ + const CanvasProperties& props = m_project.get_frame()->image().properties(); + + m_viewport_canvas = + new ViewportCanvas( + m_project, + props.m_canvas_width, + props.m_canvas_height, + m_ocio_config, + m_light_paths_manager, + this); + + m_viewport_canvas->setContextMenuPolicy(Qt::CustomContextMenu); + + connect( + m_viewport_canvas, &ViewportCanvas::customContextMenuRequested, + this, &FinalRenderViewportTab::slot_viewport_canvas_context_menu); + + m_viewport_canvas->setMouseTracking(true); +} + +void FinalRenderViewportTab::create_toolbar() +{ + // Create the render toolbar. + m_toolbar = new QToolBar(); + m_toolbar->setObjectName("render_toolbar"); + m_toolbar->setIconSize(QSize(18, 18)); + + // Display Light Paths button. + m_light_paths_toggle_button = new QToolButton(); + m_light_paths_toggle_button->setText("Display Light Paths Overlay"); + m_light_paths_toggle_button->setCheckable(true); + m_toolbar->addWidget(m_light_paths_toggle_button); + + m_toolbar->addSeparator(); + + // Save Frame and AOVs button. + QToolButton* save_aovs_button = new QToolButton(); + save_aovs_button->setIcon(load_icons("rendertab_save_all_aovs")); + save_aovs_button->setToolTip("Save Frame and AOVs..."); + connect( + save_aovs_button, &QToolButton::clicked, + this, &FinalRenderViewportTab::signal_save_frame_and_aovs); + m_toolbar->addWidget(save_aovs_button); + + // Quicksave Frame and AOVs button. + QToolButton* quicksave_aovs_button = new QToolButton(); + quicksave_aovs_button->setIcon(load_icons("rendertab_quicksave_all_aovs")); + quicksave_aovs_button->setToolTip("Quicksave Frame and AOVs"); + connect( + quicksave_aovs_button, &QToolButton::clicked, + this, &FinalRenderViewportTab::signal_quicksave_frame_and_aovs); + m_toolbar->addWidget(quicksave_aovs_button); + + m_toolbar->addSeparator(); + + // Set Render Region button. + m_set_render_region_button = new QToolButton(); + m_set_render_region_button->setIcon(load_icons("rendertab_set_render_region")); + m_set_render_region_button->setShortcut(Qt::Key_R); + m_set_render_region_button->setToolTip(combine_name_and_shortcut("Set Render Region", m_set_render_region_button->shortcut())); + m_set_render_region_button->setCheckable(true); + connect( + m_set_render_region_button, &QToolButton::toggled, + this, &FinalRenderViewportTab::slot_toggle_render_region); + m_toolbar->addWidget(m_set_render_region_button); + + // Clear Render Region button. + m_clear_render_region_button = new QToolButton(); + m_clear_render_region_button->setIcon(load_icons("rendertab_clear_render_region")); + m_clear_render_region_button->setShortcut(Qt::Key_C); + m_clear_render_region_button->setToolTip(combine_name_and_shortcut("Clear Render Region", m_clear_render_region_button->shortcut())); + connect( + m_clear_render_region_button, &QToolButton::clicked, + this, &FinalRenderViewportTab::signal_clear_render_region); + m_toolbar->addWidget(m_clear_render_region_button); + + // Clear Frame button. + m_clear_frame_button = new QToolButton(); + m_clear_frame_button->setIcon(load_icons("rendertab_clear_frame")); + m_clear_frame_button->setShortcut(Qt::Key_X); + m_clear_frame_button->setToolTip(combine_name_and_shortcut("Clear Frame", m_clear_frame_button->shortcut())); + connect( + m_clear_frame_button, &QToolButton::clicked, + this, &FinalRenderViewportTab::slot_clear_frame); + m_toolbar->addWidget(m_clear_frame_button); + + m_toolbar->addSeparator(); + + // Reset Zoom button. + QToolButton* reset_zoom_button = new QToolButton(); + reset_zoom_button->setIcon(load_icons("rendertab_reset_zoom")); + reset_zoom_button->setShortcut(Qt::Key_Asterisk); + reset_zoom_button->setToolTip(combine_name_and_shortcut("Reset Zoom", reset_zoom_button->shortcut())); + connect( + reset_zoom_button, &QToolButton::clicked, + this, &FinalRenderViewportTab::signal_reset_zoom); + m_toolbar->addWidget(reset_zoom_button); + + m_toolbar->addSeparator(); + + // Pixel Inspector button. + QToolButton* pixel_inspector_button = new QToolButton(); + pixel_inspector_button->setIcon(load_icons("rendertab_toggle_pixel_inspector")); + pixel_inspector_button->setShortcut(Qt::Key_I); + pixel_inspector_button->setToolTip(combine_name_and_shortcut("Toggle Pixel Inspector", pixel_inspector_button->shortcut())); + pixel_inspector_button->setCheckable(true); + pixel_inspector_button->setChecked(false); + connect( + pixel_inspector_button, &QToolButton::toggled, + this, &FinalRenderViewportTab::slot_toggle_pixel_inspector); + m_toolbar->addWidget(pixel_inspector_button); + + m_toolbar->addSeparator(); + + // Create the label preceding the picking mode combobox. + QLabel* picking_mode_label = new QLabel("Picking Mode:"); + picking_mode_label->setObjectName("picking_mode_label"); + m_toolbar->addWidget(picking_mode_label); + + // Create the picking mode combobox. + // The combo will be populated by the ScenePickingHandler instantiated below. + m_picking_mode_combo = new QComboBox(); + m_picking_mode_combo->setObjectName("picking_mode_combo"); + m_toolbar->addWidget(m_picking_mode_combo); + + m_toolbar->addSeparator(); + + // Create the label preceding the display combobox. + QLabel* display_label = new QLabel("Display Transform:"); + display_label->setObjectName("display_label"); + m_toolbar->addWidget(display_label); + + // Create the display combobox. + m_display_transform_combo = new QComboBox(); + m_display_transform_combo->setObjectName("display_combo"); + { + const char* display_name = m_ocio_config->getDefaultDisplay(); + const std::string default_transform = m_ocio_config->getDefaultView(display_name); + + int default_index = 0; + for (int i = 0, e = m_ocio_config->getNumViews(display_name); i < e; ++i) + { + const char* name = m_ocio_config->getView(display_name, i); + m_display_transform_combo->addItem(name); + + if (default_transform == name) + default_index = i; + } + + m_display_transform_combo->setCurrentIndex(default_index); + } + m_toolbar->addWidget(m_display_transform_combo); + connect( + m_display_transform_combo, qOverload(&QComboBox::currentIndexChanged), + m_viewport_canvas, &ViewportCanvas::slot_display_transform_changed); + + // Add stretchy spacer. + // This places interactive widgets on the left and info on the right. + QWidget* spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_toolbar->addWidget(spacer); + + // Create a label to display various information such as mouse coordinates, etc. + m_info_label = new QLabel(); + m_info_label->setObjectName("info_label"); + m_toolbar->addWidget(m_info_label); + + m_toolbar->addSeparator(); + + // Create labels to display RGBA values. + + m_r_label = new QLabel(); + m_r_label->setObjectName("r_label"); + m_r_label->setScaledContents(true); + m_toolbar->addWidget(m_r_label); + + m_g_label = new QLabel(); + m_g_label->setObjectName("g_label"); + m_g_label->setScaledContents(true); + m_toolbar->addWidget(m_g_label); + + m_b_label = new QLabel(); + m_b_label->setObjectName("b_label"); + m_b_label->setScaledContents(true); + m_toolbar->addWidget(m_b_label); + + m_a_label = new QLabel(); + m_a_label->setObjectName("a_label"); + m_a_label->setScaledContents(true); + m_toolbar->addWidget(m_a_label); +} + +void FinalRenderViewportTab::create_scrollarea() +{ + // Encapsulate the render widget into another widget that adds a margin around it. + QWidget* render_widget_wrapper = new QWidget(); + render_widget_wrapper->setObjectName("render_widget_wrapper"); + render_widget_wrapper->setLayout(new QGridLayout()); + render_widget_wrapper->layout()->setSizeConstraint(QLayout::SetFixedSize); + render_widget_wrapper->layout()->setContentsMargins(20, 20, 20, 20); + render_widget_wrapper->layout()->addWidget(m_viewport_canvas); + + // Wrap the render widget in a scroll area. + m_scroll_area = new QScrollArea(); + m_scroll_area->setObjectName("render_widget_scrollarea"); + m_scroll_area->setAlignment(Qt::AlignCenter); + m_scroll_area->setWidget(render_widget_wrapper); +} + +void FinalRenderViewportTab::recreate_handlers() +{ + // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. + m_zoom_handler.reset( + new WidgetZoomHandler( + m_scroll_area, + m_viewport_canvas)); + + // Handler for panning the render widget with the mouse. + m_pan_handler.reset( + new ScrollAreaPanHandler( + m_scroll_area)); + + // Handler for tracking and displaying mouse coordinates. + m_mouse_tracker.reset( + new MouseCoordinatesTracker( + m_viewport_canvas, + m_info_label)); + + // Handler for tracking and displaying the color of the pixel under the mouse cursor. + m_pixel_color_tracker.reset( + new PixelColorTracker( + m_viewport_canvas, + m_r_label, + m_g_label, + m_b_label, + m_a_label, + *m_mouse_tracker.get(), + m_project)); + + // Handler for pixel inspection in the render widget. + m_pixel_inspector_handler.reset( + new PixelInspectorHandler( + m_viewport_canvas, + *m_mouse_tracker.get(), + m_project)); + + // Camera handler. + m_camera_controller.reset( + new CameraController( + m_viewport_canvas, + m_project)); + connect( + m_camera_controller.get(), &CameraController::signal_camera_change_begin, + this, &FinalRenderViewportTab::signal_camera_change_begin); + connect( + m_camera_controller.get(), &CameraController::signal_camera_change_end, + this, &FinalRenderViewportTab::signal_camera_change_end); + connect( + m_camera_controller.get(), &CameraController::signal_camera_changed, + this, &FinalRenderViewportTab::signal_camera_changed); + connect( + m_camera_controller.get(), &CameraController::signal_camera_changed, + this, &FinalRenderViewportTab::slot_camera_changed); + connect( + &m_project_explorer, &ProjectExplorer::signal_frame_modified, + m_camera_controller.get(), &CameraController::slot_frame_modified); + + // Handler for picking scene entities in the render widget. + m_scene_picking_handler.reset( + new ScenePickingHandler( + m_viewport_canvas, + m_picking_mode_combo, + *m_mouse_tracker.get(), + m_project_explorer, + m_project)); + connect( + m_scene_picking_handler.get(), &ScenePickingHandler::signal_entity_picked, + this, &FinalRenderViewportTab::signal_entity_picked); + connect( + m_scene_picking_handler.get(), &ScenePickingHandler::signal_entity_picked, + m_camera_controller.get(), &CameraController::slot_entity_picked); + + // Light paths handler. + m_light_paths_viewport_toolbar.reset( + new LightPathsViewportToolbar( + this, + &m_project, + m_light_paths_manager)); + connect( + m_light_paths_toggle_button, &QToolButton::toggled, + this, &FinalRenderViewportTab::slot_toggle_light_paths); + + // Light paths picking handler. + m_light_paths_picking_handler.reset( + new LightPathsPickingHandler( + m_light_paths_manager, + m_viewport_canvas, + m_project)); + m_light_paths_picking_handler->set_enabled(false); + + // Clipboard handler. + m_clipboard_handler.reset(new RenderClipboardHandler(m_viewport_canvas, m_viewport_canvas)); + + // Material drop handler. + m_material_drop_handler.reset( + new MaterialDropHandler( + m_project, + m_rendering_manager)); + + // Handler for setting render regions with the mouse. + m_viewport_selection_handler.reset( + new ViewportRegionSelectionHandler( + m_viewport_canvas, + *m_mouse_tracker.get())); + connect( + m_viewport_selection_handler.get(), &ViewportRegionSelectionHandler::signal_rectangle_selection, + m_light_paths_picking_handler.get(), &LightPathsPickingHandler::slot_rectangle_selection); + connect( + m_viewport_selection_handler.get(), &ViewportRegionSelectionHandler::signal_render_region, + this, &FinalRenderViewportTab::slot_set_render_region); + + // Set initial state. + m_pixel_inspector_handler->set_enabled(false); + m_camera_controller->set_enabled(false); + m_scene_picking_handler->set_enabled(true); + + connect( + m_viewport_canvas, &ViewportCanvas::signal_material_dropped, + m_material_drop_handler.get(), &MaterialDropHandler::slot_material_dropped); +} + +void FinalRenderViewportTab::set_light_paths_toggle_enabled(const bool enabled) +{ + if (!enabled) + m_light_paths_toggle_button->setChecked(false); + + m_light_paths_toggle_button->setDisabled(!enabled); +} + +} // namespace studio +} // namespace appleseed + +#include "mainwindow/rendering/moc_cpp_finalrenderviewporttab.cxx" diff --git a/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.h b/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.h new file mode 100644 index 0000000000..89a02f68f7 --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/finalrenderviewporttab.h @@ -0,0 +1,138 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// appleseed.studio headers. +#include "mainwindow/rendering/lightpathsmanager.h" +#include "mainwindow/rendering/viewporttab.h" + +// OpenColorIO headers. +#include +namespace OCIO = OCIO_NAMESPACE; + +// Forward declarations. +namespace appleseed { namespace studio { class LightPathsPickingHandler; } } +namespace appleseed { namespace studio { class ProjectExplorer; } } +namespace appleseed { namespace studio { class RenderingManager; } } +namespace renderer { class Project; } +class QToolButton; + +namespace appleseed { +namespace studio { + +class FinalRenderViewportTab + : public ViewportTab +{ + Q_OBJECT + + public: + FinalRenderViewportTab( + ProjectExplorer& project_explorer, + renderer::Project& project, + RenderingManager& rendering_manager, + LightPathsManager& light_paths_manager, + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings); + + ViewportCanvas* get_viewport_canvas() const override; + + void set_light_paths_toggle_enabled(const bool enabled); + + void render_began() override; + void update_size() override; + void on_tab_selected() override; + + CameraController* get_camera_controller() const; + ScenePickingHandler* get_scene_picking_handler() const; + + void set_clear_frame_button_enabled(const bool enabled); + void set_render_region_buttons_enabled(const bool enabled); + + signals: + void signal_save_frame_and_aovs(); + void signal_quicksave_frame_and_aovs(); + void signal_clear_render_region(); + void signal_reset_zoom(); + void signal_clear_frame(); + void signal_viewport_canvas_context_menu(const QPoint& point); + + void signal_camera_change_begin(); + void signal_camera_changed(); + void signal_camera_change_end(); + + void signal_entity_picked(renderer::ScenePicker::PickingResult); + void signal_rectangle_selection(const QRect& rect); + + private slots: + void slot_set_render_region(const QRect& rect); + void slot_camera_changed(); + void slot_toggle_pixel_inspector(const bool checked); + void slot_toggle_render_region(const bool checked); + void slot_toggle_light_paths(const bool checked); + void slot_viewport_canvas_context_menu(const QPoint& point); + void slot_clear_frame(); + + private: + ViewportCanvas* m_viewport_canvas; + QToolButton* m_set_render_region_button; + QToolButton* m_clear_render_region_button; + QToolButton* m_clear_frame_button; + QScrollArea* m_scroll_area; + QToolBar* m_toolbar; + QToolButton* m_light_paths_toggle_button; + QComboBox* m_picking_mode_combo; + QComboBox* m_display_transform_combo; + QComboBox* m_base_layer_combo; + QLabel* m_info_label; + QLabel* m_r_label; + QLabel* m_g_label; + QLabel* m_b_label; + QLabel* m_a_label; + + std::unique_ptr m_material_drop_handler; + std::unique_ptr m_mouse_tracker; + std::unique_ptr m_pixel_color_tracker; + std::unique_ptr m_pixel_inspector_handler; + std::unique_ptr m_camera_controller; + std::unique_ptr m_scene_picking_handler; + std::unique_ptr m_viewport_selection_handler; + std::unique_ptr m_clipboard_handler; + + LightPathsManager& m_light_paths_manager; + std::unique_ptr m_light_paths_viewport_toolbar; + std::unique_ptr m_light_paths_picking_handler; + + void create_viewport_canvas(); + void create_toolbar(); + void create_scrollarea(); + void recreate_handlers(); +}; + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp index 0b0abdfd74..f8a527d876 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.cpp @@ -81,11 +81,12 @@ namespace LightPathsLayer::LightPathsLayer( const Project& project, + const LightPathsManager& light_paths_manager, const std::size_t width, const std::size_t height) : m_project(project) + , m_light_paths_manager(light_paths_manager) , m_camera(*m_project.get_uncached_active_camera()) - , m_selected_light_path_index(-1) , m_gl_initialized(false) , m_width(width) , m_height(height) @@ -95,6 +96,10 @@ LightPathsLayer::LightPathsLayer( { const float time = m_camera.get_shutter_middle_time(); set_transform(m_camera.transform_sequence().evaluate(time)); + + connect( + &m_light_paths_manager, &LightPathsManager::signal_light_path_selection_changed, + this, &LightPathsLayer::slot_light_path_selection_changed); } void LightPathsLayer::resize(const std::size_t width, const std::size_t height) @@ -121,71 +126,6 @@ void LightPathsLayer::set_transform(const Transformd& transform) m_gl_view_matrix = transpose(m_camera_matrix); } -void LightPathsLayer::set_light_paths(const LightPathArray& light_paths) -{ - m_light_paths = light_paths; - - if (m_light_paths.size() > 1) - { - // Sort paths by descending radiance at the camera. - const auto& light_path_recorder = m_project.get_light_path_recorder(); - std::sort( - &m_light_paths[0], - &m_light_paths[0] + m_light_paths.size(), - [&light_path_recorder](const LightPath& lhs, const LightPath& rhs) - { - LightPathVertex lhs_v; - light_path_recorder.get_light_path_vertex(lhs.m_vertex_end_index - 1, lhs_v); - - LightPathVertex rhs_v; - light_path_recorder.get_light_path_vertex(rhs.m_vertex_end_index - 1, rhs_v); - - return - sum_value(Color3f::from_array(lhs_v.m_radiance)) > - sum_value(Color3f::from_array(rhs_v.m_radiance)); - }); - } - - // Display all paths by default. - set_selected_light_path_index(-1); - load_light_paths_data(); -} - -void LightPathsLayer::set_selected_light_path_index(const int selected_light_path_index) -{ - m_selected_light_path_index = selected_light_path_index; - - dump_selected_light_path(); - - emit signal_light_path_selection_changed( - m_selected_light_path_index, - static_cast(m_light_paths.size())); -} - -void LightPathsLayer::clear_light_paths_selection() -{ - m_light_paths.clear(); - set_selected_light_path_index(-1); -} - -void LightPathsLayer::slot_display_all_light_paths() -{ - if (m_selected_light_path_index > -1) - set_selected_light_path_index(-1); -} - -void LightPathsLayer::slot_display_previous_light_path() -{ - if (m_selected_light_path_index > -1) - set_selected_light_path_index(m_selected_light_path_index - 1); -} - -void LightPathsLayer::slot_display_next_light_path() -{ - if (m_selected_light_path_index < static_cast(m_light_paths.size()) - 1) - set_selected_light_path_index(m_selected_light_path_index + 1); -} - void LightPathsLayer::slot_synchronize_camera() { m_camera.transform_sequence().clear(); @@ -194,12 +134,22 @@ void LightPathsLayer::slot_synchronize_camera() Transformd::from_local_to_parent(inverse(m_camera_matrix))); } +void LightPathsLayer::slot_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths) +{ + load_light_paths_data(); +} + void LightPathsLayer::load_light_paths_data() { m_path_terminator_vertex_indices.clear(); m_max_luminance = 0.0f; - if (!m_light_paths.empty()) + const renderer::LightPathArray& light_paths = m_light_paths_manager.light_paths(); + + if (!light_paths.empty()) { m_path_terminator_vertex_indices.push_back(0); @@ -233,13 +183,14 @@ void LightPathsLayer::load_light_paths_data() others_buffer.reserve(total_gl_vertex_count); std::array others; - for (size_t light_path_idx = 0; light_path_idx < m_light_paths.size(); light_path_idx++) + for (size_t light_path_idx = 0; light_path_idx < light_paths.size(); light_path_idx++) { - const auto& path = m_light_paths[light_path_idx]; + const auto& path = light_paths[light_path_idx]; assert(path.m_vertex_end_index - path.m_vertex_begin_index >= 2); LightPathVertex prev; light_path_recorder.get_light_path_vertex(path.m_vertex_begin_index, prev); + for (size_t vertex_idx = path.m_vertex_begin_index + 1; vertex_idx < path.m_vertex_end_index; vertex_idx++) { LightPathVertex vert; @@ -521,20 +472,20 @@ void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const if (m_total_triangle_count > 1) { - assert(m_selected_light_path_index >= -1); + const int selected_light_path_index = m_light_paths_manager.get_selected_light_paths_index(); GLint first_selected, last_selected; - if (m_selected_light_path_index == -1) + if (selected_light_path_index == -1) { first_selected = 0; last_selected = static_cast(m_path_terminator_vertex_indices[m_path_terminator_vertex_indices.size() - 1]); } else { - assert(m_path_terminator_vertex_indices.size() > m_selected_light_path_index + 1); - first_selected = static_cast(m_path_terminator_vertex_indices[m_selected_light_path_index]); - last_selected = static_cast(m_path_terminator_vertex_indices[m_selected_light_path_index + 1]); + assert(m_path_terminator_vertex_indices.size() > selected_light_path_index + 1); + first_selected = static_cast(m_path_terminator_vertex_indices[selected_light_path_index]); + last_selected = static_cast(m_path_terminator_vertex_indices[selected_light_path_index + 1]); } m_gl->glUseProgram(m_shader_program); @@ -577,46 +528,5 @@ void LightPathsLayer::render_scene(const GLfloat* gl_view_matrix) const } } -void LightPathsLayer::dump_selected_light_path() const -{ - if (m_selected_light_path_index == -1) - { - if (m_light_paths.empty()) - RENDERER_LOG_INFO("no light path to display."); - else - { - RENDERER_LOG_INFO("displaying all %s light path%s.", - pretty_uint(m_light_paths.size()).c_str(), - m_light_paths.size() > 1 ? "s" : ""); - } - } - else - { - RENDERER_LOG_INFO("displaying light path %s:", - pretty_int(m_selected_light_path_index + 1).c_str()); - - const auto& light_path_recorder = m_project.get_light_path_recorder(); - const auto& path = m_light_paths[m_selected_light_path_index]; - - for (std::size_t i = path.m_vertex_begin_index; i < path.m_vertex_end_index; ++i) - { - LightPathVertex v; - light_path_recorder.get_light_path_vertex(i, v); - - const std::string entity_name = - v.m_entity != nullptr - ? foundation::format("\"{0}\"", v.m_entity->get_path().c_str()) - : "n/a"; - - RENDERER_LOG_INFO(" vertex " FMT_SIZE_T ": entity: %s - position: (%f, %f, %f) - radiance: (%f, %f, %f) - total radiance: %f", - i - path.m_vertex_begin_index + 1, - entity_name.c_str(), - v.m_position[0], v.m_position[1], v.m_position[2], - v.m_radiance[0], v.m_radiance[1], v.m_radiance[2], - v.m_radiance[0] + v.m_radiance[1] + v.m_radiance[2]); - } - } -} - } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h index c19a70dd74..258077ffae 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathslayer.h @@ -29,6 +29,7 @@ #pragma once // appleseed.studio headers. +#include "mainwindow/rendering/lightpathsmanager.h" #include "mainwindow/rendering/renderclipboardhandler.h" // appleseed.renderer headers. @@ -74,6 +75,7 @@ class LightPathsLayer: public QObject public: LightPathsLayer( const renderer::Project& project, + const LightPathsManager& light_paths_manager, const std::size_t width, const std::size_t height); @@ -84,14 +86,6 @@ class LightPathsLayer: public QObject void set_transform( const foundation::Transformd& transform); - void set_light_paths( - const renderer::LightPathArray& light_paths); - - void set_selected_light_path_index( - const int selected_light_path_index); - - void clear_light_paths_selection(); - void set_gl_functions( QOpenGLFunctions_4_1_Core* functions); @@ -101,25 +95,22 @@ class LightPathsLayer: public QObject void draw_render_camera() const; - signals: - void signal_light_path_selection_changed( - const int selected_light_path_index, - const int total_light_paths) const; - public slots: - void slot_display_all_light_paths(); - void slot_display_previous_light_path(); - void slot_display_next_light_path(); void slot_synchronize_camera(); + private slots: + void slot_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths); + private: const renderer::Project& m_project; + const LightPathsManager& m_light_paths_manager; renderer::Camera& m_camera; foundation::Matrix4d m_camera_matrix; foundation::Matrix4d m_render_camera_matrix; - renderer::LightPathArray m_light_paths; - int m_selected_light_path_index; // The index of the show path. All paths are displayed when using -1. float m_max_luminance; float m_max_thickness; float m_min_thickness; @@ -152,8 +143,6 @@ class LightPathsLayer: public QObject void load_light_paths_data(); void render_scene(const GLfloat* gl_view_matrix) const; - - void dump_selected_light_path() const; }; } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.cpp new file mode 100644 index 0000000000..6fa644bd8f --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.cpp @@ -0,0 +1,241 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "lightpathsmanager.h" + +// appleseed.studio headers. +#include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/viewportcanvas.h" +#include "utility/settingskeys.h" + +// appleseed.qtcommon headers. +#include "utility/miscellaneous.h" + +// appleseed.renderer headers. +#include "renderer/api/frame.h" +#include "renderer/api/lighting.h" +#include "renderer/api/log.h" +#include "renderer/api/project.h" + +// appleseed.foundation headers. +#include "foundation/image/canvasproperties.h" +#include "foundation/image/image.h" +#include "foundation/math/vector.h" +#include "foundation/utility/string.h" + +// Qt headers. +#include +#include +#include +#include +#include + +// Standard headers. +#include +#include +#include + +using namespace appleseed::qtcommon; +using namespace foundation; +using namespace renderer; + +namespace appleseed { +namespace studio { + +LightPathsManager::LightPathsManager( + const renderer::Project& project, + renderer::ParamArray& application_settings) + : m_project(project) + , m_application_settings(application_settings) + , m_selected_light_path_index(-1) + , m_display_light_paths(false) +{ +} + +void LightPathsManager::set_light_paths(const LightPathArray& light_paths) +{ + m_light_paths = light_paths; + + if (m_light_paths.size() > 1) + { + // Sort paths by descending radiance at the camera. + const auto& light_path_recorder = m_project.get_light_path_recorder(); + std::sort( + &m_light_paths[0], + &m_light_paths[0] + m_light_paths.size(), + [&light_path_recorder](const LightPath& lhs, const LightPath& rhs) + { + LightPathVertex lhs_v; + light_path_recorder.get_light_path_vertex(lhs.m_vertex_end_index - 1, lhs_v); + + LightPathVertex rhs_v; + light_path_recorder.get_light_path_vertex(rhs.m_vertex_end_index - 1, rhs_v); + + return + sum_value(Color3f::from_array(lhs_v.m_radiance)) > + sum_value(Color3f::from_array(rhs_v.m_radiance)); + }); + } + + set_selected_light_path_index(-1); +} + +void LightPathsManager::clear_light_paths_selection() +{ + m_light_paths.clear(); + set_selected_light_path_index(-1); +} + +void LightPathsManager::display_light_paths(const bool on) +{ + m_display_light_paths = on; + set_selected_light_path_index(m_selected_light_path_index); +} + +bool LightPathsManager::should_display_light_paths() const +{ + return m_display_light_paths; +} + +void LightPathsManager::save_all_light_paths(QWidget* source) const +{ + QString filepath = + get_save_filename( + source, + "Save Light Paths As...", + "Light Paths Files (*.aspaths);;All Files (*.*)", + m_application_settings, + SETTINGS_FILE_DIALOG_LIGHT_PATHS); + + if (filepath.isEmpty()) + return; + + if (QFileInfo(filepath).suffix().isEmpty()) + filepath += ".aspaths"; + + // Write light paths to disk. + m_project.get_light_path_recorder().write(filepath.toUtf8().constData()); +} + +const renderer::LightPathArray& LightPathsManager::light_paths() const +{ + return m_light_paths; +} + +int LightPathsManager::get_selected_light_paths_index() const +{ + return m_selected_light_path_index; +} + +std::size_t LightPathsManager::get_selected_light_paths_count() const +{ + return m_light_paths.size(); +} + +void LightPathsManager::slot_select_all_light_paths() +{ + set_selected_light_path_index(-1); +} + +void LightPathsManager::slot_select_previous_light_path() +{ + if (m_selected_light_path_index > -1) + set_selected_light_path_index(m_selected_light_path_index - 1); +} + +void LightPathsManager::slot_select_next_light_path() +{ + if (m_selected_light_path_index < static_cast(m_light_paths.size()) - 1) + set_selected_light_path_index(m_selected_light_path_index + 1); +} + +void LightPathsManager::slot_clear_light_paths() +{ + m_light_paths.clear(); + set_selected_light_path_index(-1); + + m_project.get_light_path_recorder().clear(); +} + +void LightPathsManager::set_selected_light_path_index(int index) +{ + m_selected_light_path_index = index; + + print_selected_light_paths(); + + emit signal_light_path_selection_changed( + m_display_light_paths, + m_selected_light_path_index, + static_cast(m_light_paths.size())); +} + +void LightPathsManager::print_selected_light_paths() const +{ + if (m_selected_light_path_index == -1) + { + if (m_light_paths.empty()) + RENDERER_LOG_INFO("no light path to display."); + else + { + RENDERER_LOG_INFO("displaying %s light path%s.", + pretty_uint(m_light_paths.size()).c_str(), + m_light_paths.size() > 1 ? "s" : ""); + } + } + else + { + RENDERER_LOG_INFO("displaying light path %s/%s:", + pretty_int(m_selected_light_path_index + 1).c_str(), + pretty_int(m_light_paths.size()).c_str()); + + const auto& light_path_recorder = m_project.get_light_path_recorder(); + const auto& path = m_light_paths[m_selected_light_path_index]; + + for (std::size_t i = path.m_vertex_begin_index; i < path.m_vertex_end_index; ++i) + { + LightPathVertex v; + light_path_recorder.get_light_path_vertex(i, v); + + const std::string entity_name = + v.m_entity != nullptr + ? foundation::format("\"{0}\"", v.m_entity->get_path().c_str()) + : "n/a"; + + RENDERER_LOG_INFO(" vertex " FMT_SIZE_T ": entity: %s - position: (%f, %f, %f) - radiance: (%f, %f, %f) - total radiance: %f", + i - path.m_vertex_begin_index + 1, + entity_name.c_str(), + v.m_position[0], v.m_position[1], v.m_position[2], + v.m_radiance[0], v.m_radiance[1], v.m_radiance[2], + v.m_radiance[0] + v.m_radiance[1] + v.m_radiance[2]); + } + } +} + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.h b/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.h new file mode 100644 index 0000000000..53c2a348ab --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsmanager.h @@ -0,0 +1,107 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// appleseed.foundation headers. +#include "foundation/math/aabb.h" +#include "foundation/math/vector.h" + +// appleseed.renderer headers. +#include "renderer/api/lighting.h" +#include "renderer/utility/paramarray.h" + +// Qt headers. +#include + +// Forward declarations. +namespace appleseed { namespace studio { class LightPathsLayer; } } +namespace appleseed { namespace studio { class ViewportCanvas; } } +namespace renderer { class Project; } +class QEvent; +class QPoint; +class QWidget; + +namespace appleseed { +namespace studio { + +// +// Keep track of selected light paths. +// + +class LightPathsManager + : public QObject +{ + Q_OBJECT + + public: + LightPathsManager( + const renderer::Project& project, + renderer::ParamArray& application_settings); + + void set_light_paths( + const renderer::LightPathArray& light_paths); + + void clear_light_paths_selection(); + + void display_light_paths(const bool on); + bool should_display_light_paths() const; + + void save_all_light_paths(QWidget* source) const; + + const renderer::LightPathArray& light_paths() const; + + int get_selected_light_paths_index() const; + std::size_t get_selected_light_paths_count() const; + + signals: + void signal_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths) const; + + public slots: + void slot_select_all_light_paths(); + void slot_select_previous_light_path(); + void slot_select_next_light_path(); + void slot_clear_light_paths(); + + private: + const renderer::Project& m_project; + renderer::ParamArray& m_application_settings; + + renderer::LightPathArray m_light_paths; + int m_selected_light_path_index; // The index of the shown path. All paths are displayed when using -1. + bool m_display_light_paths; + + void set_selected_light_path_index(int index); + void print_selected_light_paths() const; +}; + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp index 40b77aae8e..8ebb35c123 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.cpp @@ -31,10 +31,7 @@ // appleseed.studio headers. #include "mainwindow/rendering/lightpathslayer.h" -#include "mainwindow/rendering/viewportwidget.h" - -// appleseed.qtcommon headers. -#include "widgets/mousecoordinatestracker.h" +#include "mainwindow/rendering/viewportcanvas.h" // appleseed.renderer headers. #include "renderer/api/frame.h" @@ -53,7 +50,6 @@ #include #include -using namespace appleseed::qtcommon; using namespace foundation; using namespace renderer; @@ -61,15 +57,15 @@ namespace appleseed { namespace studio { LightPathsPickingHandler::LightPathsPickingHandler( - ViewportWidget* viewport_widget, - const MouseCoordinatesTracker& mouse_tracker, + LightPathsManager& light_paths_manager, + ViewportCanvas* viewport_canvas, const Project& project) - : m_project(project) + : m_light_paths_manager(light_paths_manager) + , m_viewport_canvas(viewport_canvas) + , m_project(project) , m_enabled(false) - , m_viewport_widget(viewport_widget) - , m_mouse_tracker(mouse_tracker) { - m_viewport_widget->installEventFilter(this); + m_viewport_canvas->installEventFilter(this); } void LightPathsPickingHandler::set_enabled(const bool enabled) @@ -77,28 +73,40 @@ void LightPathsPickingHandler::set_enabled(const bool enabled) m_enabled = enabled; } -void LightPathsPickingHandler::pick(const AABB2i& rect) const +void LightPathsPickingHandler::slot_rectangle_selection(const QRect& rect) { + if (!m_enabled) return; + const Image& image = m_project.get_frame()->image(); const CanvasProperties& props = image.properties(); + const AABB2i rectangle_selection( + Vector2i(rect.x(), rect.y()), + Vector2i(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1)); + const AABB2i image_rect( Vector2i(0, 0), Vector2i( static_cast(props.m_canvas_width - 1), static_cast(props.m_canvas_height - 1))); - const auto final_rect = AABB2i::intersect(rect, image_rect); + const auto final_rect = AABB2i::intersect(rectangle_selection, image_rect); if (final_rect.is_valid()) { LightPathArray light_paths; - m_project.get_light_path_recorder().query( - static_cast(final_rect.min.x), - static_cast(final_rect.min.y), - static_cast(final_rect.max.x), - static_cast(final_rect.max.y), - light_paths); + + const LightPathRecorder& light_path_recorder = m_project.get_light_path_recorder(); + + if (light_path_recorder.get_light_path_count() > 0) + { + light_path_recorder.query( + static_cast(final_rect.min.x), + static_cast(final_rect.min.y), + static_cast(final_rect.max.x), + static_cast(final_rect.max.y), + light_paths); + } if (light_paths.empty()) { @@ -120,8 +128,7 @@ void LightPathsPickingHandler::pick(const AABB2i& rect) const final_rect.max.y); } - m_viewport_widget->get_light_paths_layer()->set_light_paths(light_paths); - m_viewport_widget->update(); + m_light_paths_manager.set_light_paths(light_paths); } } @@ -130,7 +137,10 @@ void LightPathsPickingHandler::pick(const QPoint& point) const const Image& image = m_project.get_frame()->image(); const CanvasProperties& props = image.properties(); - const Vector2d ndc = m_mouse_tracker.widget_to_ndc(point); + const Vector2d ndc( + static_cast(point.x()) / m_viewport_canvas->width(), + static_cast(point.y()) / m_viewport_canvas->height()); + const Vector2i pixel( ndc[0] * static_cast(props.m_canvas_width), ndc[1] * static_cast(props.m_canvas_height)); @@ -141,12 +151,18 @@ void LightPathsPickingHandler::pick(const QPoint& point) const pixel.y < static_cast(props.m_canvas_height)) { LightPathArray light_paths; - m_project.get_light_path_recorder().query( - static_cast(pixel.x), - static_cast(pixel.y), - static_cast(pixel.x), - static_cast(pixel.y), - light_paths); + + const LightPathRecorder& light_path_recorder = m_project.get_light_path_recorder(); + + if (light_path_recorder.get_light_path_count() > 0) + { + light_path_recorder.query( + static_cast(pixel.x), + static_cast(pixel.y), + static_cast(pixel.x), + static_cast(pixel.y), + light_paths); + } if (light_paths.empty()) RENDERER_LOG_INFO("no light path found at pixel (%d, %d).", pixel.x, pixel.y); @@ -160,8 +176,7 @@ void LightPathsPickingHandler::pick(const QPoint& point) const pixel.y); } - m_viewport_widget->get_light_paths_layer()->set_light_paths(light_paths); - m_viewport_widget->update(); + m_light_paths_manager.set_light_paths(light_paths); } } diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h index bf46953624..f786734e8e 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathspickinghandler.h @@ -28,6 +28,9 @@ #pragma once +// appleseed.studio headers. +#include "mainwindow/rendering/lightpathsmanager.h" + // appleseed.foundation headers. #include "foundation/math/aabb.h" #include "foundation/math/vector.h" @@ -36,9 +39,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class LightPathsLayer; } } -namespace appleseed { namespace qtcommon { class MouseCoordinatesTracker; } } -namespace appleseed { namespace studio { class ViewportWidget; } } +namespace appleseed { namespace studio { class ViewportCanvas; } } namespace renderer { class Project; } class QEvent; class QPoint; @@ -53,17 +54,18 @@ class LightPathsPickingHandler public: LightPathsPickingHandler( - ViewportWidget* viewport_widget, - const qtcommon::MouseCoordinatesTracker& mouse_tracker, + LightPathsManager& light_paths_manager, + ViewportCanvas* viewport_canvas, const renderer::Project& project); void set_enabled(const bool enabled); - void pick(const foundation::AABB2i& rect) const; + public slots: + void slot_rectangle_selection(const QRect& rect); private: - ViewportWidget* m_viewport_widget; - const qtcommon::MouseCoordinatesTracker& m_mouse_tracker; + LightPathsManager& m_light_paths_manager; + ViewportCanvas* m_viewport_canvas; const renderer::Project& m_project; bool m_enabled; diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp deleted file mode 100644 index d308fbc954..0000000000 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.cpp +++ /dev/null @@ -1,386 +0,0 @@ - -// -// This source file is part of appleseed. -// Visit https://appleseedhq.net/ for additional information and resources. -// -// This software is released under the MIT license. -// -// Copyright (c) 2018 Francois Beaune, The appleseedhq Organization -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -// Interface header. -#include "lightpathsviewportmanager.h" - -// appleseed.studio headers. -#include "mainwindow/rendering/lightpathspickinghandler.h" -#include "mainwindow/rendering/lightpathslayer.h" -#include "mainwindow/rendering/viewporttab.h" -#include "utility/settingskeys.h" - -// appleseed.qtcommon headers. -#include "utility/miscellaneous.h" -#include "widgets/mousecoordinatestracker.h" - -// appleseed.renderer headers. -#include "renderer/api/frame.h" -#include "renderer/api/lighting.h" -#include "renderer/api/project.h" - -// appleseed.foundation headers. -#include "foundation/image/canvasproperties.h" -#include "foundation/image/image.h" -#include "foundation/math/aabb.h" -#include "foundation/math/vector.h" - -// Qt headers. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Standard headers. -#include - -using namespace appleseed::qtcommon; -using namespace foundation; -using namespace renderer; - -namespace appleseed { -namespace studio { - -// -// LightPathsViewportManager class implementation. -// - -LightPathsViewportManager::LightPathsViewportManager( - ViewportTab* viewport_tab, - Project* project, - ParamArray& settings, - const MouseCoordinatesTracker& mouse_tracker) - : m_enabled(false) - , m_picking_enabled(true) - , m_paths_display_active(false) - , m_project(project) - , m_settings(settings) - , m_viewport_tab(viewport_tab) - , m_viewport_widget(m_viewport_tab->get_viewport_widget()) - , m_mouse_tracker(mouse_tracker) -{ - LightPathsLayer* light_paths_layer = m_viewport_widget->get_light_paths_layer(); - - connect( - light_paths_layer, SIGNAL(signal_light_path_selection_changed(const int, const int)), - SLOT(slot_light_path_selection_changed(const int, const int))); - connect( - this, SIGNAL(signal_display_next_light_path()), - light_paths_layer, SLOT(slot_display_next_light_path())); - connect( - this, SIGNAL(signal_display_previous_light_path()), - light_paths_layer, SLOT(slot_display_previous_light_path())); - - create_toolbar(); - - recreate_handlers(); - - m_viewport_widget->installEventFilter(this); -} - -void LightPathsViewportManager::reset(renderer::Project* project) -{ - set_display_enabled(false); - m_project = project; -} - -void LightPathsViewportManager::slot_base_layer_changed(const ViewportWidget::BaseLayer layer) -{ - if (layer == ViewportWidget::BaseLayer::FinalRender) - set_picking_enabled(true); - else - set_picking_enabled(false); - - refresh_backface_culling_button(); -} - -void LightPathsViewportManager::set_enabled(const bool enabled) -{ - m_enabled = enabled; - - if (enabled) - { - refresh_toolbar(); - m_toolbar->show(); - } - else - { - set_display_enabled(false); - m_toolbar->hide(); - } - - m_toolbar->setDisabled(!enabled); - - m_screen_space_paths_picking_handler->set_enabled(enabled && m_picking_enabled); - - emit signal_should_display(m_enabled && m_paths_display_active); -} - -void LightPathsViewportManager::set_display_enabled(const bool enabled) -{ - m_paths_display_active = enabled; - - emit signal_should_display(m_enabled && m_paths_display_active); -} - -QToolBar* LightPathsViewportManager::toolbar() const -{ - return m_toolbar; -} - -void LightPathsViewportManager::clear_light_paths() -{ - m_viewport_widget->get_light_paths_layer()->clear_light_paths_selection(); - m_project->get_light_path_recorder().clear(); - m_viewport_widget->update(); -} - -void LightPathsViewportManager::slot_light_paths_display_toggled(const bool active) -{ - set_enabled(active); -} - -void LightPathsViewportManager::slot_rectangle_selection(const QRect& rect) -{ - if (!m_picking_enabled || !m_enabled) return; - - m_screen_space_paths_picking_handler->pick( - AABB2i( - Vector2i(rect.x(), rect.y()), - Vector2i(rect.x() + rect.width() - 1, rect.y() + rect.height() - 1))); -} - -void LightPathsViewportManager::slot_light_path_selection_changed( - const int selected_light_path_index, - const int total_light_paths) -{ - if (total_light_paths > 0) - { - set_display_enabled(true); - m_prev_path_button->setEnabled(selected_light_path_index > -1); - m_next_path_button->setEnabled(selected_light_path_index < total_light_paths - 1); - } - else - { - set_display_enabled(false); - m_prev_path_button->setEnabled(false); - m_next_path_button->setEnabled(false); - } -} - -void LightPathsViewportManager::slot_save_light_paths() -{ - QString filepath = - get_save_filename( - m_viewport_tab, - "Save Light Paths As...", - "Light Paths Files (*.aspaths);;All Files (*.*)", - m_settings, - SETTINGS_FILE_DIALOG_LIGHT_PATHS); - - if (filepath.isEmpty()) - return; - - if (QFileInfo(filepath).suffix().isEmpty()) - filepath += ".aspaths"; - - // Write light paths to disk. - m_project->get_light_path_recorder().write(filepath.toUtf8().constData()); -} - -void LightPathsViewportManager::slot_camera_changed() -{ - if (!m_enabled) return; -} - -void LightPathsViewportManager::set_picking_enabled(const bool enabled) -{ - m_picking_enabled = enabled; - m_screen_space_paths_picking_handler->set_enabled(enabled); -} - -void LightPathsViewportManager::clear_selection() const -{ - m_viewport_widget->get_light_paths_layer()->clear_light_paths_selection(); - m_viewport_widget->update(); -} - -void LightPathsViewportManager::create_toolbar() -{ - ViewportWidget* viewport_widget = m_viewport_tab->get_viewport_widget(); - LightPathsLayer* light_paths_layer = viewport_widget->get_light_paths_layer(); - GLSceneLayer* gl_layer = viewport_widget->get_gl_scene_layer(); - - // Create the render toolbar. - m_toolbar = new QToolBar(); - m_toolbar->setObjectName("render_toolbar"); - m_toolbar->setIconSize(QSize(18, 18)); - - // Save Light Paths button. - m_save_light_paths_button = new QToolButton(); - m_save_light_paths_button->setIcon(load_icons("lightpathstab_save_light_paths")); - connect( - m_save_light_paths_button , SIGNAL(clicked()), - SLOT(slot_save_light_paths())); - m_toolbar->addWidget(m_save_light_paths_button); - - m_toolbar->addSeparator(); - - // Previous Light Path button. - m_prev_path_button = new QToolButton(); - m_prev_path_button->setIcon(load_icons("lightpathstab_prev_light_path")); - m_prev_path_button->setToolTip("Display previous light path"); - m_prev_path_button->setEnabled(false); - connect( - m_prev_path_button, SIGNAL(clicked()), - light_paths_layer, SLOT(slot_display_previous_light_path())); - m_toolbar->addWidget(m_prev_path_button); - - // Next Light Path button. - m_next_path_button = new QToolButton(); - m_next_path_button->setIcon(load_icons("lightpathstab_next_light_path")); - m_next_path_button->setToolTip("Display next light path"); - m_next_path_button->setEnabled(false); - connect( - m_next_path_button, SIGNAL(clicked()), - light_paths_layer, SLOT(slot_display_next_light_path())); - m_toolbar->addWidget(m_next_path_button); - - m_toolbar->addSeparator(); - - // Toggle Backface Culling button. - QToolButton* backface_culling_button = new QToolButton(); - backface_culling_button->setIcon(load_icons("lightpathstab_toggle_backface_culling")); - backface_culling_button->setToolTip("Show/hide backfacing surfaces"); - backface_culling_button->setCheckable(true); - backface_culling_button->setChecked(false); - connect( - backface_culling_button, SIGNAL(toggled(bool)), - viewport_widget, SLOT(slot_toggle_backface_culling(bool))); - m_backface_culling_action = m_toolbar->addWidget(backface_culling_button); - // todo: the backface button should only be visible in OpenGL mode. - m_backface_culling_action->setVisible(true); - - // Synchronize Camera button. - QToolButton* sync_camera_button = new QToolButton(); - sync_camera_button->setIcon(load_icons("lightpathstab_synchronize_camera")); - sync_camera_button->setToolTip("Synchronize the rendering camera with this camera"); - connect( - sync_camera_button, SIGNAL(clicked()), - light_paths_layer, SLOT(slot_synchronize_camera())); - m_toolbar->addWidget(sync_camera_button); - - // Add stretchy spacer. - // This places interactive widgets on the left and info on the right. - QWidget* spacer = new QWidget(); - spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_toolbar->addWidget(spacer); - - // Create a label to display various information such as mouse coordinates, etc. - m_info_label = new QLabel(); - m_info_label->setObjectName("info_label"); - m_toolbar->addWidget(m_info_label); - - m_toolbar->setDisabled(true); - m_toolbar->hide(); -} - -void LightPathsViewportManager::refresh_toolbar() const -{ - const auto light_path_count = m_project->get_light_path_recorder().get_light_path_count(); - - m_save_light_paths_button->setToolTip( - QString("Save %1 Light Path%2...") - .arg(QString::fromStdString(pretty_uint(light_path_count))) - .arg(light_path_count > 1 ? "s" : "")); -} - -void LightPathsViewportManager::refresh_backface_culling_button() const -{ - if (m_viewport_widget->get_active_layer() == ViewportWidget::BaseLayer::OpenGL) - { - //m_backface_culling_action->setVisible(true); - } - else - { - //m_backface_culling_action->setVisible(false); - } -} - -void LightPathsViewportManager::recreate_handlers() -{ - // The screen-space paths picking handler is used to pick paths from the render widget. - m_screen_space_paths_picking_handler.reset( - new LightPathsPickingHandler( - m_viewport_widget, - m_mouse_tracker, - *m_project)); - m_screen_space_paths_picking_handler->set_enabled(false); - - // Camera handler. - m_viewport_widget->setMouseTracking(true); -} - -bool LightPathsViewportManager::eventFilter(QObject* object, QEvent* event) -{ - if (m_enabled) - { - if (event->type() == QEvent::KeyRelease) - { - const QKeyEvent* key_event = static_cast(event); - - if (!(key_event->modifiers() & (Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier))) - { - const int key = key_event->key(); - - if (key == Qt::Key_Escape) - clear_selection(); - else if (key == Qt::Key_Left) - emit signal_display_previous_light_path(); - else if (key == Qt::Key_Right) - emit signal_display_next_light_path(); - } - } - } - - return QObject::eventFilter(object, event); -} - -} // namespace studio -} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.cpp b/src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.cpp new file mode 100644 index 0000000000..189249a62d --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.cpp @@ -0,0 +1,240 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2018 Francois Beaune, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "lightpathsviewporttoolbar.h" + +// appleseed.studio headers. +#include "mainwindow/rendering/lightpathspickinghandler.h" +#include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/viewporttab.h" +#include "utility/settingskeys.h" + +// appleseed.qtcommon headers. +#include "utility/miscellaneous.h" + +// appleseed.renderer headers. +#include "renderer/api/frame.h" +#include "renderer/api/lighting.h" +#include "renderer/api/project.h" + +// appleseed.foundation headers. +#include "foundation/image/canvasproperties.h" +#include "foundation/image/image.h" +#include "foundation/math/aabb.h" +#include "foundation/math/vector.h" + +// Qt headers. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Standard headers. +#include + +using namespace appleseed::qtcommon; +using namespace foundation; +using namespace renderer; + +namespace appleseed { +namespace studio { + +// +// LightPathsViewportToolbar class implementation. +// + +LightPathsViewportToolbar::LightPathsViewportToolbar( + ViewportTab* viewport_tab, + Project* project, + LightPathsManager& light_paths_manager) + : m_enabled(false) + , m_project(project) + , m_light_paths_manager(light_paths_manager) + , m_viewport_canvas(viewport_tab->get_viewport_canvas()) +{ + LightPathsLayer* light_paths_layer = m_viewport_canvas->get_light_paths_layer(); + + connect( + &m_light_paths_manager, &LightPathsManager::signal_light_path_selection_changed, + this, &LightPathsViewportToolbar::slot_light_path_selection_changed); + connect( + this, &LightPathsViewportToolbar::signal_display_next_light_path, + &m_light_paths_manager, &LightPathsManager::slot_select_next_light_path); + connect( + this, &LightPathsViewportToolbar::signal_display_previous_light_path, + &m_light_paths_manager, &LightPathsManager::slot_select_previous_light_path); + + create_toolbar(); + + m_viewport_canvas->installEventFilter(this); +} + +void LightPathsViewportToolbar::reset(renderer::Project* project) +{ + m_project = project; +} + +void LightPathsViewportToolbar::set_enabled(const bool enabled) +{ + m_enabled = enabled; + + if (enabled) + { + refresh_toolbar(); + m_toolbar->show(); + } + else + { + m_toolbar->hide(); + } + + m_toolbar->setDisabled(!enabled); +} + +QToolBar* LightPathsViewportToolbar::toolbar() const +{ + return m_toolbar; +} + +void LightPathsViewportToolbar::slot_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths) +{ + if (total_light_paths > 0) + { + m_prev_path_button->setEnabled(selected_light_path_index > -1); + m_next_path_button->setEnabled(selected_light_path_index < total_light_paths - 1); + } + else + { + m_prev_path_button->setEnabled(false); + m_next_path_button->setEnabled(false); + } +} + +void LightPathsViewportToolbar::slot_save_light_paths() +{ + m_light_paths_manager.save_all_light_paths(m_toolbar); +} + +void LightPathsViewportToolbar::clear_selection() const +{ + m_light_paths_manager.clear_light_paths_selection(); +} + +void LightPathsViewportToolbar::create_toolbar() +{ + // Create the render toolbar. + m_toolbar = new QToolBar(); + m_toolbar->setObjectName("light_paths_viewport_toolbar"); + m_toolbar->setIconSize(QSize(18, 18)); + + // Save Light Paths button. + m_save_light_paths_button = new QToolButton(); + m_save_light_paths_button->setIcon(load_icons("lightpaths_toolbar_save_light_paths")); + connect( + m_save_light_paths_button , &QToolButton::clicked, + this, &LightPathsViewportToolbar::slot_save_light_paths); + m_toolbar->addWidget(m_save_light_paths_button); + + m_toolbar->addSeparator(); + + // Previous Light Path button. + m_prev_path_button = new QToolButton(); + m_prev_path_button->setIcon(load_icons("lightpaths_toolbar_prev_light_path")); + m_prev_path_button->setToolTip("Display previous light path"); + m_prev_path_button->setEnabled(false); + connect( + m_prev_path_button, &QToolButton::clicked, + &m_light_paths_manager, &LightPathsManager::slot_select_previous_light_path); + m_toolbar->addWidget(m_prev_path_button); + + // Next Light Path button. + m_next_path_button = new QToolButton(); + m_next_path_button->setIcon(load_icons("lightpaths_toolbar_next_light_path")); + m_next_path_button->setToolTip("Display next light path"); + m_next_path_button->setEnabled(false); + connect( + m_next_path_button, &QToolButton::clicked, + &m_light_paths_manager, &LightPathsManager::slot_select_next_light_path); + m_toolbar->addWidget(m_next_path_button); + + m_toolbar->setDisabled(true); + m_toolbar->hide(); +} + +void LightPathsViewportToolbar::refresh_toolbar() const +{ + const auto light_path_count = m_project->get_light_path_recorder().get_light_path_count(); + + m_save_light_paths_button->setToolTip( + QString("Save %1 Light Path%2...") + .arg(QString::fromStdString(pretty_uint(light_path_count))) + .arg(light_path_count > 1 ? "s" : "")); +} + +bool LightPathsViewportToolbar::eventFilter(QObject* object, QEvent* event) +{ + if (m_enabled) + { + if (event->type() == QEvent::KeyRelease) + { + const QKeyEvent* key_event = static_cast(event); + + if (!(key_event->modifiers() & (Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier))) + { + const int key = key_event->key(); + + if (key == Qt::Key_Escape) + clear_selection(); + else if (key == Qt::Key_Left) + emit signal_display_previous_light_path(); + else if (key == Qt::Key_Right) + emit signal_display_next_light_path(); + } + } + } + + return QObject::eventFilter(object, event); +} + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h b/src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.h similarity index 66% rename from src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h rename to src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.h index 1bb5299b7f..348cd41e93 100644 --- a/src/appleseed.studio/mainwindow/rendering/lightpathsviewportmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/lightpathsviewporttoolbar.h @@ -30,9 +30,9 @@ // appleseed.studio headers. #include "mainwindow/rendering/cameracontroller.h" -#include "mainwindow/rendering/lightpathspickinghandler.h" +#include "mainwindow/rendering/lightpathsmanager.h" #include "mainwindow/rendering/renderclipboardhandler.h" -#include "mainwindow/rendering/viewportwidget.h" +#include "mainwindow/rendering/viewportcanvas.h" // appleseed.qtcommon headers. #include "widgets/scrollareapanhandler.h" @@ -45,13 +45,9 @@ #include #include -// Standard headers. -#include - // Forward declarations. -namespace appleseed { namespace qtcommon { class MouseCoordinatesTracker; } } namespace appleseed { namespace studio { class ViewportTab; } } -namespace renderer { class ParamArray; } +namespace renderer { class PamArray; } namespace renderer { class Project; } class QAction; class QEvent; @@ -66,75 +62,52 @@ namespace appleseed { namespace studio { // -// Manages the state of the light paths overlay. +// Control pannel for light paths. // -class LightPathsViewportManager +class LightPathsViewportToolbar : public QObject { Q_OBJECT public: - LightPathsViewportManager( + LightPathsViewportToolbar( ViewportTab* viewport_tab, renderer::Project* project, - renderer::ParamArray& settings, - const qtcommon::MouseCoordinatesTracker& mouse_tracker); + LightPathsManager& light_paths_manager); void reset(renderer::Project* project); QToolBar* toolbar() const; void set_enabled(const bool enabled); - void set_display_enabled(const bool enabled); - - void clear_light_paths(); signals: - void signal_should_display(const bool should_display); void signal_display_next_light_path(); void signal_display_previous_light_path(); - public slots: - void slot_rectangle_selection(const QRect& rect); - void slot_light_paths_display_toggled(const bool active); - private slots: - void slot_base_layer_changed(const ViewportWidget::BaseLayer layer); void slot_light_path_selection_changed( + const bool display_light_paths, const int selected_light_path_index, const int total_light_paths); void slot_save_light_paths(); - void slot_camera_changed(); private: bool m_enabled; - bool m_picking_enabled; - bool m_paths_display_active; renderer::Project* m_project; - renderer::ParamArray& m_settings; - ViewportTab* m_viewport_tab; - ViewportWidget* m_viewport_widget; + LightPathsManager& m_light_paths_manager; + ViewportCanvas* m_viewport_canvas; QToolBar* m_toolbar; QToolButton* m_save_light_paths_button; QToolButton* m_prev_path_button; QToolButton* m_next_path_button; - QLabel* m_info_label; - QAction* m_backface_culling_action; - - const qtcommon::MouseCoordinatesTracker& m_mouse_tracker; - - std::unique_ptr m_screen_space_paths_picking_handler; - - void set_picking_enabled(const bool enabled); void clear_selection() const; void create_toolbar(); void refresh_toolbar() const; - void refresh_backface_culling_button() const; - void recreate_handlers(); bool eventFilter(QObject* object, QEvent* event) override; }; diff --git a/src/appleseed.studio/mainwindow/rendering/openglviewporttab.cpp b/src/appleseed.studio/mainwindow/rendering/openglviewporttab.cpp new file mode 100644 index 0000000000..b66114993a --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/openglviewporttab.cpp @@ -0,0 +1,268 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +// Interface header. +#include "openglviewporttab.h" + +// appleseed.studio headers. +#include "mainwindow/project/projectexplorer.h" +#include "mainwindow/rendering/renderingmanager.h" + +// appleseed.renderer headers. +#include "renderer/api/frame.h" +#include "renderer/api/project.h" + +// appleseed.qtcommon headers. +#include "utility/miscellaneous.h" + +// Qt headers. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace appleseed::qtcommon; +using namespace foundation; +using namespace renderer; +namespace OCIO = OCIO_NAMESPACE; + +namespace appleseed { +namespace studio { + +OpenGLViewportTab::OpenGLViewportTab( + ProjectExplorer& project_explorer, + Project& project, + RenderingManager& rendering_manager, + LightPathsManager& light_paths_manager, + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings) + : ViewportTab( + project_explorer, + project, + rendering_manager, + ocio_config, + application_settings) + , m_light_paths_manager(light_paths_manager) +{ + setObjectName("opengl_viewport_tab"); + setLayout(new QGridLayout()); + layout()->setSpacing(0); + layout()->setMargin(0); + + create_viewport_canvas(); + create_toolbar(); + create_scrollarea(); + + recreate_handlers(); + + layout()->addWidget(m_toolbar); + layout()->addWidget(m_light_paths_viewport_toolbar->toolbar()); + layout()->addWidget(m_scroll_area); + + m_camera_controller->set_enabled(true); + + get_viewport_canvas()->set_base_layer(ViewportCanvas::BaseLayer::OpenGL); +} + +ViewportCanvas* OpenGLViewportTab::get_viewport_canvas() const +{ + return m_viewport_canvas; +} + +void OpenGLViewportTab::render_began() +{ + ViewportTab::render_began(); + + m_light_paths_viewport_toolbar.get()->reset(&m_project); +} + +void OpenGLViewportTab::update_size() +{ + ViewportTab::update_size(); + + recreate_handlers(); +} + +void OpenGLViewportTab::on_tab_selected() +{ + const bool display_light_paths = m_light_paths_manager.should_display_light_paths(); + m_light_paths_viewport_toolbar->set_enabled(display_light_paths); + m_light_paths_toggle_button->setChecked(display_light_paths); +} + +void OpenGLViewportTab::slot_camera_changed() +{ + m_viewport_canvas->get_light_paths_layer()->set_transform(m_camera_controller->get_transform()); + m_viewport_canvas->get_gl_scene_layer()->set_transform(m_camera_controller->get_transform()); + update(); +} + +void OpenGLViewportTab::slot_viewport_canvas_context_menu(const QPoint& point) +{ + emit signal_viewport_canvas_context_menu(m_viewport_canvas->mapToGlobal(point)); +} + +void OpenGLViewportTab::create_viewport_canvas() +{ + const CanvasProperties& props = m_project.get_frame()->image().properties(); + + m_viewport_canvas = + new ViewportCanvas( + m_project, + props.m_canvas_width, + props.m_canvas_height, + m_ocio_config, + m_light_paths_manager, + this); + + m_viewport_canvas->setContextMenuPolicy(Qt::CustomContextMenu); + + connect( + m_viewport_canvas, &ViewportCanvas::customContextMenuRequested, + this, &OpenGLViewportTab::slot_viewport_canvas_context_menu); + + m_viewport_canvas->setMouseTracking(true); +} + +void OpenGLViewportTab::create_toolbar() +{ + // Create the render toolbar. + m_toolbar = new QToolBar(); + m_toolbar->setObjectName("render_toolbar"); + m_toolbar->setIconSize(QSize(18, 18)); + + // Display Light Paths button. + m_light_paths_toggle_button = new QToolButton(); + m_light_paths_toggle_button->setText("Display Light Paths Overlay"); + m_light_paths_toggle_button->setCheckable(true); + m_toolbar->addWidget(m_light_paths_toggle_button); + + m_toolbar->addSeparator(); + + // Reset Zoom button. + QToolButton* reset_zoom_button = new QToolButton(); + reset_zoom_button->setIcon(load_icons("rendertab_reset_zoom")); + reset_zoom_button->setShortcut(Qt::Key_Asterisk); + reset_zoom_button->setToolTip(combine_name_and_shortcut("Reset Zoom", reset_zoom_button->shortcut())); + connect( + reset_zoom_button, &QToolButton::clicked, + this, &OpenGLViewportTab::signal_reset_zoom); + m_toolbar->addWidget(reset_zoom_button); + + m_toolbar->addSeparator(); + + // Toggle Backface Culling button. + QToolButton* backface_culling_button = new QToolButton(); + backface_culling_button->setIcon(load_icons("opengl_viewport_tab_toggle_backface_culling")); + backface_culling_button->setToolTip("Show/hide backfacing surfaces"); + backface_culling_button->setCheckable(true); + backface_culling_button->setChecked(false); + connect( + backface_culling_button, &QToolButton::toggled , + m_viewport_canvas, &ViewportCanvas::slot_toggle_backface_culling); + m_toolbar->addWidget(backface_culling_button); + + // Synchronize Camera button. + QToolButton* sync_camera_button = new QToolButton(); + sync_camera_button->setIcon(load_icons("opengl_viewport_tab_synchronize_camera")); + sync_camera_button->setToolTip("Synchronize the rendering camera with this camera"); + connect( + sync_camera_button, &QToolButton::clicked, + m_viewport_canvas->get_light_paths_layer(), &LightPathsLayer::slot_synchronize_camera); + m_toolbar->addWidget(sync_camera_button); +} + +void OpenGLViewportTab::create_scrollarea() +{ + // Encapsulate the render widget into another widget that adds a margin around it. + QWidget* render_widget_wrapper = new QWidget(); + render_widget_wrapper->setObjectName("render_widget_wrapper"); + render_widget_wrapper->setLayout(new QGridLayout()); + render_widget_wrapper->layout()->setSizeConstraint(QLayout::SetFixedSize); + render_widget_wrapper->layout()->setContentsMargins(20, 20, 20, 20); + render_widget_wrapper->layout()->addWidget(m_viewport_canvas); + + // Wrap the render widget in a scroll area. + m_scroll_area = new QScrollArea(); + m_scroll_area->setObjectName("render_widget_scrollarea"); + m_scroll_area->setAlignment(Qt::AlignCenter); + m_scroll_area->setWidget(render_widget_wrapper); +} + +void OpenGLViewportTab::recreate_handlers() +{ + // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. + m_zoom_handler.reset( + new WidgetZoomHandler( + m_scroll_area, + m_viewport_canvas)); + + // Handler for panning the render widget with the mouse. + m_pan_handler.reset( + new ScrollAreaPanHandler( + m_scroll_area)); + + // Camera handler. + m_camera_controller.reset( + new CameraController( + m_viewport_canvas, + m_project)); + + connect( + m_camera_controller.get(), &CameraController::signal_camera_changed, + this, &OpenGLViewportTab::slot_camera_changed); + + // Light paths handler. + m_light_paths_viewport_toolbar.reset( + new LightPathsViewportToolbar( + this, + &m_project, + m_light_paths_manager)); + connect( + m_light_paths_toggle_button, &QToolButton::toggled, + this, &OpenGLViewportTab::slot_toggle_light_paths); + + // Clipboard handler. + m_clipboard_handler.reset(new RenderClipboardHandler(m_viewport_canvas, m_viewport_canvas)); +} + +void OpenGLViewportTab::slot_toggle_light_paths(const bool checked) +{ + m_light_paths_viewport_toolbar->set_enabled(checked); + m_light_paths_manager.display_light_paths(checked); +} + +} // namespace studio +} // namespace appleseed + diff --git a/src/appleseed.studio/mainwindow/rendering/openglviewporttab.h b/src/appleseed.studio/mainwindow/rendering/openglviewporttab.h new file mode 100644 index 0000000000..a693e947d9 --- /dev/null +++ b/src/appleseed.studio/mainwindow/rendering/openglviewporttab.h @@ -0,0 +1,124 @@ + +// +// This source file is part of appleseed. +// Visit https://appleseedhq.net/ for additional information and resources. +// +// This software is released under the MIT license. +// +// Copyright (c) 2020 Kevin Masson, The appleseedhq Organization +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +// appleseed.studio headers. +#include "mainwindow/rendering/cameracontroller.h" +#include "mainwindow/rendering/lightpathsmanager.h" +#include "mainwindow/rendering/lightpathsviewporttoolbar.h" +#include "mainwindow/rendering/materialdrophandler.h" +#include "mainwindow/rendering/pixelcolortracker.h" +#include "mainwindow/rendering/pixelinspectorhandler.h" +#include "mainwindow/rendering/renderclipboardhandler.h" +#include "mainwindow/rendering/scenepickinghandler.h" +#include "mainwindow/rendering/viewportcanvas.h" +#include "mainwindow/rendering/viewportregionselectionhandler.h" +#include "mainwindow/rendering/viewporttab.h" + +// appleseed.qtcommon headers. +#include "widgets/mousecoordinatestracker.h" +#include "widgets/scrollareapanhandler.h" +#include "widgets/widgetzoomhandler.h" + +// OpenColorIO headers. +#include +namespace OCIO = OCIO_NAMESPACE; + +// Qt headers. +#include +#include + +// Standard headers. +#include + +// Forward declarations. +namespace appleseed { namespace studio { class ProjectExplorer; } } +namespace appleseed { namespace studio { class RenderingManager; } } +namespace renderer { class Entity; } +namespace renderer { class Project; } +class QComboBox; +class QLabel; +class QPoint; +class QRect; +class QScrollArea; +class QToolBar; +class QToolButton; + +namespace appleseed { +namespace studio { + +class OpenGLViewportTab + : public ViewportTab +{ + Q_OBJECT + + public: + OpenGLViewportTab( + ProjectExplorer& project_explorer, + renderer::Project& project, + RenderingManager& rendering_manager, + LightPathsManager& light_paths_manager, + OCIO::ConstConfigRcPtr ocio_config, + renderer::ParamArray application_settings); + + ViewportCanvas* get_viewport_canvas() const override; + + void render_began() override; + void update_size() override; + void on_tab_selected() override; + + signals: + void signal_reset_zoom(); + void signal_viewport_canvas_context_menu(const QPoint& point); + + private slots: + void slot_camera_changed(); + void slot_viewport_canvas_context_menu(const QPoint& point); + void slot_toggle_light_paths(const bool checked); + + private: + ViewportCanvas* m_viewport_canvas; + QScrollArea* m_scroll_area; + QToolBar* m_toolbar; + QToolButton* m_light_paths_toggle_button; + + std::unique_ptr m_camera_controller; + std::unique_ptr m_clipboard_handler; + + LightPathsManager& m_light_paths_manager; + std::unique_ptr m_light_paths_viewport_toolbar; + + void create_viewport_canvas(); + void create_toolbar(); + void create_scrollarea(); + void recreate_handlers(); +}; + +} // namespace studio +} // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp b/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp index bb79364eb1..312f42b92d 100644 --- a/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp +++ b/src/appleseed.studio/mainwindow/rendering/qttilecallback.cpp @@ -32,7 +32,7 @@ // appleseed.studio headers. #include "mainwindow/rendering/renderlayer.h" -#include "mainwindow/rendering/viewportwidget.h" +#include "mainwindow/rendering/viewportcanvas.h" // Qt headers. #include @@ -61,12 +61,12 @@ namespace Q_OBJECT public: - explicit QtTileCallback(ViewportWidget* viewport_widget) - : m_render_layer(viewport_widget->get_render_layer()) + explicit QtTileCallback(ViewportCanvas* viewport_canvas) + : m_render_layer(viewport_canvas->get_render_layer()) { connect( this, SIGNAL(signal_update()), - viewport_widget, SLOT(repaint()), + viewport_canvas, SLOT(repaint()), Qt::QueuedConnection); } @@ -120,8 +120,8 @@ namespace // QtTileCallbackFactory class implementation. // -QtTileCallbackFactory::QtTileCallbackFactory(ViewportWidget* viewport_widget) - : m_viewport_widget(viewport_widget) +QtTileCallbackFactory::QtTileCallbackFactory(ViewportCanvas* viewport_canvas) + : m_viewport_canvas(viewport_canvas) { } @@ -132,7 +132,7 @@ void QtTileCallbackFactory::release() ITileCallback* QtTileCallbackFactory::create() { - return new QtTileCallback(m_viewport_widget); + return new QtTileCallback(m_viewport_canvas); } } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/qttilecallback.h b/src/appleseed.studio/mainwindow/rendering/qttilecallback.h index 91c7e3bc3b..587ee7090b 100644 --- a/src/appleseed.studio/mainwindow/rendering/qttilecallback.h +++ b/src/appleseed.studio/mainwindow/rendering/qttilecallback.h @@ -36,7 +36,7 @@ #include "foundation/platform/compiler.h" // Forward declarations. -namespace appleseed { namespace studio { class ViewportWidget; } } +namespace appleseed { namespace studio { class ViewportCanvas; } } namespace appleseed { namespace studio { @@ -46,7 +46,7 @@ class QtTileCallbackFactory { public: // Constructor. - explicit QtTileCallbackFactory(ViewportWidget* viewport_widget); + explicit QtTileCallbackFactory(ViewportCanvas* viewport_canvas); // Delete this instance. void release() override; @@ -55,7 +55,7 @@ class QtTileCallbackFactory renderer::ITileCallback* create() override; private: - ViewportWidget* m_viewport_widget; + ViewportCanvas* m_viewport_canvas; }; } // namespace studio diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp index 3376840434..4113345c98 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.cpp @@ -32,9 +32,9 @@ // appleseed.studio headers. #include "mainwindow/rendering/cameracontroller.h" +#include "mainwindow/rendering/finalrenderviewporttab.h" #include "mainwindow/rendering/qttilecallback.h" -#include "mainwindow/rendering/viewporttab.h" -#include "mainwindow/rendering/viewportwidget.h" +#include "mainwindow/rendering/viewportcanvas.h" #include "mainwindow/statusbar.h" // appleseed.common headers. @@ -122,7 +122,7 @@ namespace RenderingManager::RenderingManager(StatusBar& status_bar) : m_status_bar(status_bar) , m_project(nullptr) - , m_viewport_tab(nullptr) + , m_final_render_viewport_tab(nullptr) { Application::initialize_resource_search_paths(m_resource_search_paths); @@ -198,21 +198,21 @@ void RenderingManager::start_rendering( Project* project, const ParamArray& params, const RenderingMode rendering_mode, - ViewportTab* viewport_tab) + FinalRenderViewportTab* final_render_viewport_tab) { m_project = project; m_params = params; m_rendering_mode = rendering_mode; - m_viewport_tab = viewport_tab; + m_final_render_viewport_tab = final_render_viewport_tab; - m_viewport_tab->get_viewport_widget()->get_render_layer()->start_render(); + m_final_render_viewport_tab->get_viewport_canvas()->get_render_layer()->start_render(); TileCallbackCollectionFactory* tile_callback_collection_factory = new TileCallbackCollectionFactory(); tile_callback_collection_factory->insert( new QtTileCallbackFactory( - m_viewport_tab->get_viewport_widget())); + m_final_render_viewport_tab->get_viewport_canvas())); tile_callback_collection_factory->insert( new ProgressTileCallbackFactory( @@ -439,7 +439,7 @@ void RenderingManager::slot_rendering_begin() run_scheduled_actions(); if (m_rendering_mode == RenderingMode::InteractiveRendering) - m_viewport_tab->get_camera_controller()->set_enabled(true); + m_final_render_viewport_tab->get_camera_controller()->set_enabled(true); m_has_camera_changed = false; @@ -466,10 +466,10 @@ void RenderingManager::slot_rendering_end() { // Disable camera interaction. if (m_rendering_mode == RenderingMode::InteractiveRendering) - m_viewport_tab->get_camera_controller()->set_enabled(false); + m_final_render_viewport_tab->get_camera_controller()->set_enabled(false); // Save the controller target point into the camera when rendering ends. - m_viewport_tab->get_camera_controller()->save_camera_target(); + m_final_render_viewport_tab->get_camera_controller()->save_camera_target(); // Stop printing rendering time in the status bar. m_status_bar.stop_rendering_time_display(); @@ -489,10 +489,10 @@ void RenderingManager::slot_rendering_failed() { // Disable camera interaction. if (m_rendering_mode == RenderingMode::InteractiveRendering) - m_viewport_tab->get_camera_controller()->set_enabled(false); + m_final_render_viewport_tab->get_camera_controller()->set_enabled(false); // Save the controller target point into the camera when rendering ends. - m_viewport_tab->get_camera_controller()->save_camera_target(); + m_final_render_viewport_tab->get_camera_controller()->save_camera_target(); // Stop printing rendering time in the status bar. m_status_bar.stop_rendering_time_display(); @@ -503,7 +503,7 @@ void RenderingManager::slot_frame_begin() // Update the scene's camera before rendering the frame. if (m_has_camera_changed) { - m_viewport_tab->get_camera_controller()->update_camera_transform(); + m_final_render_viewport_tab->get_camera_controller()->update_camera_transform(); m_has_camera_changed = false; } } @@ -511,7 +511,7 @@ void RenderingManager::slot_frame_begin() void RenderingManager::slot_frame_end() { // Ensure that the render widget is up-to-date. - m_viewport_tab->get_viewport_widget()->update(); + m_final_render_viewport_tab->get_viewport_canvas()->update(); } void RenderingManager::slot_camera_change_begin() diff --git a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h index 3235e30c60..c1d34bae9f 100644 --- a/src/appleseed.studio/mainwindow/rendering/renderingmanager.h +++ b/src/appleseed.studio/mainwindow/rendering/renderingmanager.h @@ -55,7 +55,7 @@ #include // Forward declarations. -namespace appleseed { namespace studio { class ViewportTab; } } +namespace appleseed { namespace studio { class FinalRenderViewportTab; } } namespace appleseed { namespace studio { class StatusBar; } } namespace foundation { class IAbortSwitch; } namespace renderer { class Frame; } @@ -87,7 +87,7 @@ class RenderingManager renderer::Project* project, const renderer::ParamArray& params, const RenderingMode rendering_mode, - ViewportTab* viewport_tab); + FinalRenderViewportTab* final_render_viewport_tab); // Get current rendering mode RenderingMode get_rendering_mode() const; @@ -168,7 +168,7 @@ class RenderingManager renderer::ParamArray m_params; foundation::SearchPaths m_resource_search_paths; RenderingMode m_rendering_mode; - ViewportTab* m_viewport_tab; + FinalRenderViewportTab* m_final_render_viewport_tab; std::unique_ptr m_tile_callback_factory; diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp b/src/appleseed.studio/mainwindow/rendering/viewportcanvas.cpp similarity index 88% rename from src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp rename to src/appleseed.studio/mainwindow/rendering/viewportcanvas.cpp index 424b8c384b..7371adae83 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewportcanvas.cpp @@ -27,7 +27,7 @@ // // Interface header. -#include "viewportwidget.h" +#include "viewportcanvas.h" // appleseed.studio headers. #include "utility/gl.h" @@ -67,14 +67,15 @@ namespace appleseed { namespace studio { // -// ViewportWidget class implementation. +// ViewportCanvas class implementation. // -ViewportWidget::ViewportWidget( +ViewportCanvas::ViewportCanvas( const renderer::Project& project, const size_t width, const size_t height, OCIO::ConstConfigRcPtr ocio_config, + const LightPathsManager& light_paths_manager, QWidget* parent) : QOpenGLWidget(parent) , m_project(project) @@ -93,16 +94,20 @@ ViewportWidget::ViewportWidget( setAutoFillBackground(false); setAttribute(Qt::WA_OpaquePaintEvent, true); + connect( + &light_paths_manager, &LightPathsManager::signal_light_path_selection_changed, + this, &ViewportCanvas::slot_light_path_selection_changed); + create_render_layer(ocio_config); create_gl_scene_layer(); - create_light_paths_layer(); + create_light_paths_layer(light_paths_manager); resize(width, height); setAcceptDrops(true); } -ViewportWidget::~ViewportWidget() +ViewportCanvas::~ViewportCanvas() { m_gl->glDeleteProgram(m_resolve_program); m_gl->glDeleteTextures(1, &m_accum_tex); @@ -113,18 +118,7 @@ ViewportWidget::~ViewportWidget() m_gl->glDeleteFramebuffers(1, &m_main_fb); } -QString ViewportWidget::base_layer_string(BaseLayer layer) -{ - switch (layer) - { - case BaseLayer::FinalRender: return QString("Final Render"); - case BaseLayer::OpenGL: return QString("OpenGL"); - } - assert(false); - return QString("BaseLayer"); -} - -void ViewportWidget::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) +void ViewportCanvas::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) { m_render_layer = std::unique_ptr(new RenderLayer( @@ -133,7 +127,7 @@ void ViewportWidget::create_render_layer(OCIO::ConstConfigRcPtr ocio_config) ocio_config)); } -void ViewportWidget::create_gl_scene_layer() +void ViewportCanvas::create_gl_scene_layer() { m_gl_scene_layer = std::unique_ptr(new GLSceneLayer( @@ -142,41 +136,42 @@ void ViewportWidget::create_gl_scene_layer() m_height)); } -void ViewportWidget::create_light_paths_layer() +void ViewportCanvas::create_light_paths_layer(const LightPathsManager& light_paths_manager) { m_light_paths_layer = std::unique_ptr(new LightPathsLayer( m_project, + light_paths_manager, m_width, m_height)); } -ViewportWidget::BaseLayer ViewportWidget::get_active_layer() const +ViewportCanvas::BaseLayer ViewportCanvas::get_active_layer() const { return m_active_base_layer; } -RenderLayer* ViewportWidget::get_render_layer() +RenderLayer* ViewportCanvas::get_render_layer() { return m_render_layer.get(); } -LightPathsLayer* ViewportWidget::get_light_paths_layer() +LightPathsLayer* ViewportCanvas::get_light_paths_layer() { return m_light_paths_layer.get(); } -GLSceneLayer* ViewportWidget::get_gl_scene_layer() +GLSceneLayer* ViewportCanvas::get_gl_scene_layer() { return m_gl_scene_layer.get(); } -QImage ViewportWidget::capture() +QImage ViewportCanvas::capture() { return grabFramebuffer(); } -void ViewportWidget::initializeGL() { +void ViewportCanvas::initializeGL() { RENDERER_LOG_INFO("initializing opengl."); m_gl = QOpenGLContext::currentContext()->versionFunctions(); @@ -253,7 +248,7 @@ void ViewportWidget::initializeGL() { m_light_paths_layer->init_gl(qs_format); } -void ViewportWidget::resize( +void ViewportCanvas::resize( const size_t width, const size_t height) { @@ -261,13 +256,13 @@ void ViewportWidget::resize( m_light_paths_layer->resize(width, height); } -void ViewportWidget::set_base_layer(const BaseLayer base_layer) +void ViewportCanvas::set_base_layer(const BaseLayer base_layer) { m_active_base_layer = base_layer; update(); } -void ViewportWidget::resizeGL( +void ViewportCanvas::resizeGL( int width, int height) { @@ -296,7 +291,7 @@ void ViewportWidget::resizeGL( m_gl->glBindTexture(GL_TEXTURE_2D, 0); } -void ViewportWidget::paintGL() +void ViewportCanvas::paintGL() { double dpr = static_cast(m_render_layer->image().devicePixelRatio()); @@ -382,13 +377,13 @@ void ViewportWidget::paintGL() m_gl->glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); } -void ViewportWidget::dragEnterEvent(QDragEnterEvent* event) +void ViewportCanvas::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat("text/plain")) event->acceptProposedAction(); } -void ViewportWidget::dragMoveEvent(QDragMoveEvent* event) +void ViewportCanvas::dragMoveEvent(QDragMoveEvent* event) { if (pos().x() <= event->pos().x() && pos().y() <= event->pos().y() && event->pos().x() < pos().x() + width() && event->pos().y() < pos().y() + height()) @@ -399,7 +394,7 @@ void ViewportWidget::dragMoveEvent(QDragMoveEvent* event) event->ignore(); } -void ViewportWidget::dropEvent(QDropEvent* event) +void ViewportCanvas::dropEvent(QDropEvent* event) { emit signal_material_dropped( Vector2d( @@ -408,19 +403,13 @@ void ViewportWidget::dropEvent(QDropEvent* event) event->mimeData()->text()); } -void ViewportWidget::slot_light_paths_should_display(const bool should_display) -{ - m_draw_light_paths = should_display; - update(); -} - -void ViewportWidget::slot_toggle_backface_culling(const bool checked) +void ViewportCanvas::slot_toggle_backface_culling(const bool checked) { m_gl_scene_layer->toggle_backface_culling(checked); update(); } -void ViewportWidget::slot_display_transform_changed(const QString& transform) +void ViewportCanvas::slot_display_transform_changed(const QString& transform) { m_render_layer->set_display_transform(transform); @@ -430,5 +419,14 @@ void ViewportWidget::slot_display_transform_changed(const QString& transform) } } +void ViewportCanvas::slot_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths) +{ + m_draw_light_paths = display_light_paths && total_light_paths > 0; + update(); +} + } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h b/src/appleseed.studio/mainwindow/rendering/viewportcanvas.h similarity index 90% rename from src/appleseed.studio/mainwindow/rendering/viewportwidget.h rename to src/appleseed.studio/mainwindow/rendering/viewportcanvas.h index f4823829a0..3f63b6864c 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewportwidget.h +++ b/src/appleseed.studio/mainwindow/rendering/viewportcanvas.h @@ -30,6 +30,7 @@ // appleseed.studio headers. #include "mainwindow/rendering/lightpathslayer.h" +#include "mainwindow/rendering/lightpathsmanager.h" #include "mainwindow/rendering/glscenelayer.h" #include "mainwindow/rendering/renderclipboardhandler.h" #include "mainwindow/rendering/renderlayer.h" @@ -72,7 +73,7 @@ namespace studio { // A render widget based on QImage. // -class ViewportWidget +class ViewportCanvas : public QOpenGLWidget , public ICapturableWidget { @@ -80,14 +81,15 @@ class ViewportWidget public: // Constructor. - ViewportWidget( + ViewportCanvas( const renderer::Project& project, const size_t width, const size_t height, OCIO::ConstConfigRcPtr ocio_config, + const LightPathsManager& lith_paths_manager, QWidget* parent = nullptr); - ~ViewportWidget(); + ~ViewportCanvas(); enum BaseLayer { FinalRender, @@ -95,8 +97,6 @@ class ViewportWidget BASE_LAYER_MAX_VALUE }; - static QString base_layer_string(BaseLayer layer); - // Thread-safe. QImage capture() override; @@ -118,9 +118,12 @@ class ViewportWidget const QString& material_name); public slots: - void slot_light_paths_should_display(const bool should_display); void slot_toggle_backface_culling(const bool checked); void slot_display_transform_changed(const QString& transform); + void slot_light_path_selection_changed( + const bool display_light_paths, + const int selected_light_path_index, + const int total_light_paths); private: const renderer::Project& m_project; @@ -150,7 +153,7 @@ class ViewportWidget bool m_draw_light_paths; BaseLayer m_active_base_layer; - void create_light_paths_layer(); + void create_light_paths_layer(const LightPathsManager& light_paths_manager); void create_gl_scene_layer(); void create_render_layer(OCIO::ConstConfigRcPtr ocio_config); diff --git a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp index 9b38a94037..170d278dce 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.cpp @@ -76,7 +76,6 @@ namespace studio { // ViewportTab::ViewportTab( - const ViewportWidget::BaseLayer base_layer, ProjectExplorer& project_explorer, Project& project, RenderingManager& rendering_manager, @@ -88,73 +87,20 @@ ViewportTab::ViewportTab( , m_rendering_manager(rendering_manager) , m_ocio_config(ocio_config) { - setObjectName("render_widget_tab"); - setLayout(new QGridLayout()); - layout()->setSpacing(0); - layout()->setMargin(0); - - create_viewport_widget(); - create_toolbar(); - create_scrollarea(); - - recreate_handlers(); - - layout()->addWidget(m_toolbar); - layout()->addWidget(m_light_paths_manager->toolbar()); - layout()->addWidget(m_scroll_area); - - m_viewport_widget->set_base_layer(base_layer); - - switch (base_layer) - { - case ViewportWidget::BaseLayer::FinalRender: - if (m_rendering_manager.is_rendering() - && m_rendering_manager.get_rendering_mode() == RenderingManager::RenderingMode::InteractiveRendering) - m_camera_controller.get()->set_enabled(true); - else - m_camera_controller.get()->set_enabled(false); - break; - - case ViewportWidget::BaseLayer::OpenGL: - m_camera_controller.get()->set_enabled(true); - break; - } - - get_viewport_widget()->update(); -} - -ViewportWidget* ViewportTab::get_viewport_widget() const -{ - return m_viewport_widget; -} - -CameraController* ViewportTab::get_camera_controller() const -{ - return m_camera_controller.get(); -} - -ScenePickingHandler* ViewportTab::get_scene_picking_handler() const -{ - return m_scene_picking_handler.get(); } -void ViewportTab::set_clear_frame_button_enabled(const bool enabled) +void ViewportTab::clear() { - m_clear_frame_button->setEnabled(enabled); -} - -void ViewportTab::set_render_region_buttons_enabled(const bool enabled) -{ - m_set_render_region_button->setEnabled(enabled); - m_clear_render_region_button->setEnabled(enabled); + ViewportCanvas* viewport_canvas = get_viewport_canvas(); + viewport_canvas->get_render_layer()->clear(); + viewport_canvas->repaint(); } void ViewportTab::render_began() { - m_viewport_widget->get_render_layer()->darken(); - m_viewport_widget->get_light_paths_layer()->update_render_camera_transform(); - m_light_paths_manager.get()->reset(&m_project); - update(); + ViewportCanvas* viewport_canvas = get_viewport_canvas(); + viewport_canvas->get_render_layer()->darken(); + viewport_canvas->get_light_paths_layer()->update_render_camera_transform(); } void ViewportTab::reset_zoom() @@ -164,20 +110,22 @@ void ViewportTab::reset_zoom() void ViewportTab::update() { - m_viewport_widget->update(); + ViewportCanvas* viewport_canvas = get_viewport_canvas(); + viewport_canvas->update(); } void ViewportTab::update_size() { - m_set_render_region_button->setChecked(false); - const CanvasProperties& props = m_project.get_frame()->image().properties(); - m_viewport_widget->resize( + ViewportCanvas* viewport_canvas = get_viewport_canvas(); + viewport_canvas->resize( props.m_canvas_width, props.m_canvas_height); +} - recreate_handlers(); +void ViewportTab::on_tab_selected() +{ } ViewportTab::State ViewportTab::save_state() const @@ -195,408 +143,6 @@ void ViewportTab::load_state(const State& state) m_pan_handler->load_state(state.m_pan_handler_state); } -void ViewportTab::slot_base_layer_changed(const ViewportWidget::BaseLayer base_layer) -{ -} - -void ViewportTab::slot_camera_changed() -{ - - m_viewport_widget->get_light_paths_layer()->set_transform(get_camera_controller()->get_transform()); - m_viewport_widget->get_gl_scene_layer()->set_transform(get_camera_controller()->get_transform()); - update(); -} - -void ViewportTab::slot_toggle_render_region(const bool checked) -{ - m_scene_picking_handler->set_enabled(!checked); - m_viewport_selection_handler->set_mode( - checked - ? ViewportRegionSelectionHandler::RenderRegionMode - : ViewportRegionSelectionHandler::RectangleSelectionMode); -} - -void ViewportTab::slot_toggle_light_paths(const bool checked) -{ - m_light_paths_manager->set_enabled(checked); - m_scene_picking_handler->set_enabled(!checked); -} - -void ViewportTab::slot_set_render_region(const QRect& rect) -{ - m_set_render_region_button->setChecked(false); - emit signal_set_render_region(rect); -} - -void ViewportTab::slot_toggle_pixel_inspector(const bool checked) -{ - m_pixel_inspector_handler->set_enabled(checked); - m_pixel_inspector_handler->update_tooltip_visibility(); -} - -void ViewportTab::slot_viewport_widget_context_menu(const QPoint& point) -{ - emit signal_viewport_widget_context_menu(m_viewport_widget->mapToGlobal(point)); -} - -void ViewportTab::slot_clear_light_paths() -{ - set_light_paths_toggle_enabled(false); - m_light_paths_manager->clear_light_paths(); - m_light_paths_manager->set_enabled(false); - m_scene_picking_handler->set_enabled(true); -} - -void ViewportTab::create_viewport_widget() -{ - const CanvasProperties& props = m_project.get_frame()->image().properties(); - - m_viewport_widget = - new ViewportWidget( - m_project, - props.m_canvas_width, - props.m_canvas_height, - m_ocio_config, - this); - - m_viewport_widget->setContextMenuPolicy(Qt::CustomContextMenu); - - connect( - m_viewport_widget, SIGNAL(customContextMenuRequested(const QPoint&)), - SLOT(slot_viewport_widget_context_menu(const QPoint&))); - - m_viewport_widget->setMouseTracking(true); -} - -void ViewportTab::create_toolbar() -{ - // Create the render toolbar. - m_toolbar = new QToolBar(); - m_toolbar->setObjectName("render_toolbar"); - m_toolbar->setIconSize(QSize(18, 18)); - - m_light_paths_toggle_button = new QToolButton(); - m_light_paths_toggle_button->setText("Display Light Paths Overlay"); - m_light_paths_toggle_button->setCheckable(true); - m_toolbar->addWidget(m_light_paths_toggle_button); - - m_toolbar->addSeparator(); - - // Save Frame and AOVs button. - QToolButton* save_aovs_button = new QToolButton(); - save_aovs_button->setIcon(load_icons("rendertab_save_all_aovs")); - save_aovs_button->setToolTip("Save Frame and AOVs..."); - connect( - save_aovs_button, SIGNAL(clicked()), - SIGNAL(signal_save_frame_and_aovs())); - m_toolbar->addWidget(save_aovs_button); - - // Quicksave Frame and AOVs button. - QToolButton* quicksave_aovs_button = new QToolButton(); - quicksave_aovs_button->setIcon(load_icons("rendertab_quicksave_all_aovs")); - quicksave_aovs_button->setToolTip("Quicksave Frame and AOVs"); - connect( - quicksave_aovs_button, SIGNAL(clicked()), - SIGNAL(signal_quicksave_frame_and_aovs())); - m_toolbar->addWidget(quicksave_aovs_button); - - m_toolbar->addSeparator(); - - // Set Render Region button. - m_set_render_region_button = new QToolButton(); - m_set_render_region_button->setIcon(load_icons("rendertab_set_render_region")); - m_set_render_region_button->setShortcut(Qt::Key_R); - m_set_render_region_button->setToolTip(combine_name_and_shortcut("Set Render Region", m_set_render_region_button->shortcut())); - m_set_render_region_button->setCheckable(true); - connect( - m_set_render_region_button, SIGNAL(toggled(bool)), - SLOT(slot_toggle_render_region(const bool))); - m_toolbar->addWidget(m_set_render_region_button); - - // Clear Render Region button. - m_clear_render_region_button = new QToolButton(); - m_clear_render_region_button->setIcon(load_icons("rendertab_clear_render_region")); - m_clear_render_region_button->setShortcut(Qt::Key_C); - m_clear_render_region_button->setToolTip(combine_name_and_shortcut("Clear Render Region", m_clear_render_region_button->shortcut())); - connect( - m_clear_render_region_button, SIGNAL(clicked()), - SIGNAL(signal_clear_render_region())); - m_toolbar->addWidget(m_clear_render_region_button); - - // Clear Frame button. - m_clear_frame_button = new QToolButton(); - m_clear_frame_button->setIcon(load_icons("rendertab_clear_frame")); - m_clear_frame_button->setShortcut(Qt::Key_X); - m_clear_frame_button->setToolTip(combine_name_and_shortcut("Clear Frame", m_clear_frame_button->shortcut())); - connect( - m_clear_frame_button, SIGNAL(clicked()), - SIGNAL(signal_clear_frame())); - m_toolbar->addWidget(m_clear_frame_button); - - m_toolbar->addSeparator(); - - // Reset Zoom button. - QToolButton* reset_zoom_button = new QToolButton(); - reset_zoom_button->setIcon(load_icons("rendertab_reset_zoom")); - reset_zoom_button->setShortcut(Qt::Key_Asterisk); - reset_zoom_button->setToolTip(combine_name_and_shortcut("Reset Zoom", reset_zoom_button->shortcut())); - connect( - reset_zoom_button, SIGNAL(clicked()), - SIGNAL(signal_reset_zoom())); - m_toolbar->addWidget(reset_zoom_button); - - m_toolbar->addSeparator(); - - // Pixel Inspector button. - QToolButton* pixel_inspector_button = new QToolButton(); - pixel_inspector_button->setIcon(load_icons("rendertab_toggle_pixel_inspector")); - pixel_inspector_button->setShortcut(Qt::Key_I); - pixel_inspector_button->setToolTip(combine_name_and_shortcut("Toggle Pixel Inspector", pixel_inspector_button->shortcut())); - pixel_inspector_button->setCheckable(true); - pixel_inspector_button->setChecked(false); - connect( - pixel_inspector_button, SIGNAL(toggled(bool)), - SLOT(slot_toggle_pixel_inspector(const bool))); - m_toolbar->addWidget(pixel_inspector_button); - - m_toolbar->addSeparator(); - - // Create the label preceding the picking mode combobox. - QLabel* picking_mode_label = new QLabel("Picking Mode:"); - picking_mode_label->setObjectName("picking_mode_label"); - m_toolbar->addWidget(picking_mode_label); - - // Create the picking mode combobox. - // The combo will be populated by the ScenePickingHandler instantiated below. - m_picking_mode_combo = new QComboBox(); - m_picking_mode_combo->setObjectName("picking_mode_combo"); - m_toolbar->addWidget(m_picking_mode_combo); - - m_toolbar->addSeparator(); - - // Create the label preceding the display combobox. - QLabel* display_label = new QLabel("Display Transform:"); - display_label->setObjectName("display_label"); - m_toolbar->addWidget(display_label); - - // Create the display combobox. - m_display_transform_combo = new QComboBox(); - m_display_transform_combo->setObjectName("display_combo"); - { - const char* display_name = m_ocio_config->getDefaultDisplay(); - const std::string default_transform = m_ocio_config->getDefaultView(display_name); - - int default_index = 0; - for (int i = 0, e = m_ocio_config->getNumViews(display_name); i < e; ++i) - { - const char* name = m_ocio_config->getView(display_name, i); - m_display_transform_combo->addItem(name); - - if (default_transform == name) - default_index = i; - } - - m_display_transform_combo->setCurrentIndex(default_index); - } - m_toolbar->addWidget(m_display_transform_combo); - connect( - m_display_transform_combo, SIGNAL(currentIndexChanged(QString)), - m_viewport_widget, SLOT(slot_display_transform_changed(QString))); - - // Add stretchy spacer. - // This places interactive widgets on the left and info on the right. - QWidget* spacer = new QWidget(); - spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_toolbar->addWidget(spacer); - - // Create a label to display various information such as mouse coordinates, etc. - m_info_label = new QLabel(); - m_info_label->setObjectName("info_label"); - m_toolbar->addWidget(m_info_label); - - m_toolbar->addSeparator(); - - // Create labels to display RGBA values. - - m_r_label = new QLabel(); - m_r_label->setObjectName("r_label"); - m_r_label->setScaledContents(true); - m_toolbar->addWidget(m_r_label); - - m_g_label = new QLabel(); - m_g_label->setObjectName("g_label"); - m_g_label->setScaledContents(true); - m_toolbar->addWidget(m_g_label); - - m_b_label = new QLabel(); - m_b_label->setObjectName("b_label"); - m_b_label->setScaledContents(true); - m_toolbar->addWidget(m_b_label); - - m_a_label = new QLabel(); - m_a_label->setObjectName("a_label"); - m_a_label->setScaledContents(true); - m_toolbar->addWidget(m_a_label); -} - -void ViewportTab::create_scrollarea() -{ - // Encapsulate the render widget into another widget that adds a margin around it. - QWidget* render_widget_wrapper = new QWidget(); - render_widget_wrapper->setObjectName("render_widget_wrapper"); - render_widget_wrapper->setLayout(new QGridLayout()); - render_widget_wrapper->layout()->setSizeConstraint(QLayout::SetFixedSize); - render_widget_wrapper->layout()->setContentsMargins(20, 20, 20, 20); - render_widget_wrapper->layout()->addWidget(m_viewport_widget); - - // Wrap the render widget in a scroll area. - m_scroll_area = new QScrollArea(); - m_scroll_area->setObjectName("render_widget_scrollarea"); - m_scroll_area->setAlignment(Qt::AlignCenter); - m_scroll_area->setWidget(render_widget_wrapper); -} - -void ViewportTab::recreate_handlers() -{ - // Handler for zooming the render widget in and out with the keyboard or the mouse wheel. - m_zoom_handler.reset( - new WidgetZoomHandler( - m_scroll_area, - m_viewport_widget)); - - // Handler for panning the render widget with the mouse. - m_pan_handler.reset( - new ScrollAreaPanHandler( - m_scroll_area)); - - // Handler for tracking and displaying mouse coordinates. - m_mouse_tracker.reset( - new MouseCoordinatesTracker( - m_viewport_widget, - m_info_label)); - - // Handler for tracking and displaying the color of the pixel under the mouse cursor. - m_pixel_color_tracker.reset( - new PixelColorTracker( - m_viewport_widget, - m_r_label, - m_g_label, - m_b_label, - m_a_label, - *m_mouse_tracker.get(), - m_project)); - - // Handler for pixel inspection in the render widget. - m_pixel_inspector_handler.reset( - new PixelInspectorHandler( - m_viewport_widget, - *m_mouse_tracker.get(), - m_project)); - - // Camera handler. - m_camera_controller.reset( - new CameraController( - m_viewport_widget, - m_project)); - connect( - m_camera_controller.get(), SIGNAL(signal_camera_change_begin()), - SIGNAL(signal_camera_change_begin())); - connect( - m_camera_controller.get(), SIGNAL(signal_camera_change_end()), - SIGNAL(signal_camera_change_end())); - connect( - m_camera_controller.get(), SIGNAL(signal_camera_changed()), - SIGNAL(signal_camera_changed())); - connect( - m_camera_controller.get(), SIGNAL(signal_camera_changed()), - SLOT(slot_camera_changed())); - connect( - &m_project_explorer, SIGNAL(signal_frame_modified()), - m_camera_controller.get(), SLOT(slot_frame_modified())); - - // Handler for picking scene entities in the render widget. - m_scene_picking_handler.reset( - new ScenePickingHandler( - m_viewport_widget, - m_picking_mode_combo, - *m_mouse_tracker.get(), - m_project_explorer, - m_project)); - connect( - m_scene_picking_handler.get(), SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), - SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult))); - connect( - m_scene_picking_handler.get(), SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), - m_camera_controller.get(), SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); - connect( - m_scene_picking_handler.get(), SIGNAL(signal_entity_picked(renderer::ScenePicker::PickingResult)), - m_light_paths_manager.get(), SLOT(slot_entity_picked(renderer::ScenePicker::PickingResult))); - - // Light paths handler. - m_light_paths_manager.reset(new LightPathsViewportManager( - this, - &m_project, - m_application_settings, - *m_mouse_tracker.get())); - - connect( - m_viewport_widget, SIGNAL(signal_base_layer_changed(const ViewportWidget::BaseLayer)), - m_light_paths_manager.get(), SLOT(slot_base_layer_changed(const ViewportWidget::BaseLayer)) - ); - connect( - m_light_paths_manager.get(), SIGNAL(signal_should_display(const bool)), - m_viewport_widget, SLOT(slot_light_paths_should_display(const bool)) - ); - connect( - m_light_paths_toggle_button, SIGNAL(toggled(bool)), - SLOT(slot_toggle_light_paths(bool)) - ); - connect( - this, SIGNAL(signal_clear_frame()), - SLOT(slot_clear_light_paths()) - ); - - // Handler for setting render regions with the mouse. - m_viewport_selection_handler.reset( - new ViewportRegionSelectionHandler( - m_viewport_widget, - *m_mouse_tracker.get())); - connect( - m_viewport_selection_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), - SIGNAL(signal_rectangle_selection(const QRect&))); - connect( - m_viewport_selection_handler.get(), SIGNAL(signal_rectangle_selection(const QRect&)), - m_light_paths_manager.get(), SLOT(slot_rectangle_selection(const QRect&))); - connect( - m_viewport_selection_handler.get(), SIGNAL(signal_render_region(const QRect&)), - SLOT(slot_set_render_region(const QRect&))); - - // Clipboard handler. - m_clipboard_handler.reset(new RenderClipboardHandler(m_viewport_widget, m_viewport_widget)); - - // Material drop handler. - m_material_drop_handler.reset( - new MaterialDropHandler( - m_project, - m_rendering_manager)); - - // Set initial state. - m_pixel_inspector_handler->set_enabled(false); - m_camera_controller->set_enabled(false); - m_scene_picking_handler->set_enabled(true); - - connect( - m_viewport_widget, SIGNAL(signal_material_dropped(const foundation::Vector2d&, const QString&)), - m_material_drop_handler.get(), SLOT(slot_material_dropped(const foundation::Vector2d&, const QString&))); -} - -void ViewportTab::set_light_paths_toggle_enabled(const bool enabled) -{ - if (!enabled) - m_light_paths_toggle_button->setChecked(false); - - m_light_paths_toggle_button->setDisabled(!enabled); -} } // namespace studio } // namespace appleseed diff --git a/src/appleseed.studio/mainwindow/rendering/viewporttab.h b/src/appleseed.studio/mainwindow/rendering/viewporttab.h index e406f5f8f7..291c3a5b77 100644 --- a/src/appleseed.studio/mainwindow/rendering/viewporttab.h +++ b/src/appleseed.studio/mainwindow/rendering/viewporttab.h @@ -31,14 +31,14 @@ // appleseed.studio headers. #include "mainwindow/rendering/cameracontroller.h" -#include "mainwindow/rendering/lightpathsviewportmanager.h" +#include "mainwindow/rendering/lightpathsviewporttoolbar.h" #include "mainwindow/rendering/materialdrophandler.h" #include "mainwindow/rendering/pixelcolortracker.h" #include "mainwindow/rendering/pixelinspectorhandler.h" #include "mainwindow/rendering/renderclipboardhandler.h" #include "mainwindow/rendering/scenepickinghandler.h" +#include "mainwindow/rendering/viewportcanvas.h" #include "mainwindow/rendering/viewportregionselectionhandler.h" -#include "mainwindow/rendering/viewportwidget.h" // appleseed.qtcommon headers. #include "widgets/mousecoordinatestracker.h" @@ -83,26 +83,23 @@ class ViewportTab public: ViewportTab( - const ViewportWidget::BaseLayer base_layer, ProjectExplorer& project_explorer, renderer::Project& project, RenderingManager& rendering_manager, OCIO::ConstConfigRcPtr ocio_config, renderer::ParamArray application_settings); - ViewportWidget* get_viewport_widget() const; - CameraController* get_camera_controller() const; - ScenePickingHandler* get_scene_picking_handler() const; + virtual ViewportCanvas* get_viewport_canvas() const = 0; - void set_clear_frame_button_enabled(const bool enabled); - void set_light_paths_toggle_enabled(const bool enabled); - void set_render_region_buttons_enabled(const bool enabled); + void clear(); - void render_began(); + virtual void render_began(); void reset_zoom(); void update(); - void update_size(); + virtual void update_size(); + + virtual void on_tab_selected(); struct State { @@ -113,73 +110,15 @@ class ViewportTab State save_state() const; void load_state(const State& state); - signals: - void signal_save_frame_and_aovs(); - void signal_quicksave_frame_and_aovs(); - void signal_set_render_region(const QRect& rect); - void signal_clear_render_region(); - void signal_reset_zoom(); - void signal_clear_frame(); - void signal_viewport_widget_context_menu(const QPoint& point); - - void signal_camera_change_begin(); - void signal_camera_changed(); - void signal_camera_change_end(); - - void signal_entity_picked(renderer::ScenePicker::PickingResult); - void signal_rectangle_selection(const QRect& rect); - - private slots: - void slot_camera_changed(); - void slot_base_layer_changed(const ViewportWidget::BaseLayer base_layer); - void slot_set_render_region(const QRect& rect); - void slot_toggle_pixel_inspector(const bool checked); - void slot_toggle_render_region(const bool checked); - void slot_toggle_light_paths(const bool checked); - void slot_viewport_widget_context_menu(const QPoint& point); - void slot_clear_light_paths(); - - private: - ViewportWidget* m_viewport_widget; - - QScrollArea* m_scroll_area; - QToolBar* m_toolbar; - QToolButton* m_set_render_region_button; - QToolButton* m_clear_render_region_button; - QToolButton* m_clear_frame_button; - QToolButton* m_light_paths_toggle_button; - QComboBox* m_picking_mode_combo; - QComboBox* m_display_transform_combo; - QComboBox* m_base_layer_combo; - QLabel* m_info_label; - QLabel* m_r_label; - QLabel* m_g_label; - QLabel* m_b_label; - QLabel* m_a_label; - + protected: + renderer::ParamArray m_application_settings; ProjectExplorer& m_project_explorer; renderer::Project& m_project; RenderingManager& m_rendering_manager; - renderer::ParamArray m_application_settings; + OCIO::ConstConfigRcPtr m_ocio_config; - std::unique_ptr m_light_paths_manager; std::unique_ptr m_zoom_handler; std::unique_ptr m_pan_handler; - std::unique_ptr m_material_drop_handler; - std::unique_ptr m_mouse_tracker; - std::unique_ptr m_pixel_color_tracker; - std::unique_ptr m_pixel_inspector_handler; - std::unique_ptr m_camera_controller; - std::unique_ptr m_scene_picking_handler; - std::unique_ptr m_viewport_selection_handler; - std::unique_ptr m_clipboard_handler; - - OCIO::ConstConfigRcPtr m_ocio_config; - - void create_scrollarea(); - void create_toolbar(); - void create_viewport_widget(); - void recreate_handlers(); }; } // namespace studio diff --git a/src/appleseed.studio/resources/shaders/lightpaths.vert b/src/appleseed.studio/resources/shaders/lightpaths.vert index 99c5a7d050..4cd0460390 100644 --- a/src/appleseed.studio/resources/shaders/lightpaths.vert +++ b/src/appleseed.studio/resources/shaders/lightpaths.vert @@ -33,6 +33,7 @@ layout(location = 0) in vec3 v_previous; layout(location = 1) in vec3 v_position; layout(location = 2) in vec3 v_next; layout(location = 3) in float v_luminance; +// todo: renomer ca v_bitmask ou un truc du genre layout(location = 4) in int v_direction_start_end; // flag defining which part of a light path is currently drawn. layout(location = 5) in vec3 v_color; layout(location = 6) in vec3 v_surface_normal; @@ -53,34 +54,22 @@ flat out float f_thickness; flat out float f_total_thickness; flat out float f_aspect_expansion_len; -const float CLIPPING_PREVENTION_FACTOR = 0.05; +const float CLIPPING_PREVENTION_FACTOR = 0.0001; // // Reference: // - https://mattdesl.svbtle.com/drawing-lines-is-hard#screenspace-projected-lines_2 // -#define DRAW_START_PATH 1 // Drawing the start of the light path -#define DRAW_MIDDLE_PATH 2 // Drawing a point in the middle of the light path -#define DRAW_END_PATH 3 // Drawing the end of the light path - -int get_drawing_mode() +// Compute current line direction +// depending on which part of the path we +// are drawing (start, middle or end). +vec2 get_line_direction(vec2 curr_screen, vec2 prev_screen, vec2 next_screen) { - if ((v_direction_start_end & 2) == 2) - { - //starting point uses (next - current) - return DRAW_START_PATH; - } - else if ((v_direction_start_end & 4) == 4) - { - //ending point uses (current - previous) - return DRAW_END_PATH; - } - else - { - // middle point uses (next - current) - return DRAW_MIDDLE_PATH; - } + // todo: n'utiliser que 2 bits dans le mask + return (v_direction_start_end & 4) == 4 + ? normalize(curr_screen - prev_screen) + : normalize(next_screen - curr_screen); } // Each point on the light path is duplicated to render a real line. @@ -93,8 +82,7 @@ bool is_second_point() void main() { // Aspect ratio correction is applied on // screen points (only on the X axis). - float aspect = u_res.x / u_res.y; - vec2 aspect_correction = vec2(aspect, 1.0); + float aspect_correction = u_res.x / u_res.y; // Project points. // The currently drawn point is offset @@ -111,40 +99,39 @@ void main() { vec2 next_screen = next_proj.xy / next_proj.w; // Apply aspect ratio correction. - curr_screen *= aspect_correction; - prev_screen *= aspect_correction; - next_screen *= aspect_correction; + curr_screen.x *= aspect_correction; + prev_screen.x *= aspect_correction; + next_screen.x *= aspect_correction; - int drawing_mode = get_drawing_mode(); bool is_second_point = is_second_point(); - // Compute current line directionection. - // Depending on which part of the path we - // are drawing (start, middle or end), we - // compute it differently. - vec2 line_direction = - drawing_mode == DRAW_START_PATH ? normalize(next_screen - curr_screen) : - drawing_mode == DRAW_END_PATH ? normalize(curr_screen - prev_screen) : - normalize(next_screen - curr_screen); + vec2 line_direction = get_line_direction(curr_screen, prev_screen, next_screen); // Compute the normal of the line. vec2 line_normal = vec2(-line_direction.y, line_direction.x); vec4 normal_clip = vp * vec4(v_surface_normal, 0.0); - normal_clip.xy *= aspect_correction; + normal_clip.x *= aspect_correction; normal_clip = normalize(normal_clip); vec2 tang_clip = vec2(-normal_clip.y, normal_clip.x); float tdp = dot(tang_clip, line_normal); - vec2 expansion = line_normal; - if (tdp > 0.05) - expansion = tang_clip / tdp; + // it uses tangent to surface unless the tangent to surface is too much aligned with the line direction, + // in which case it uses the line normal as fallback. it does that to reduce the amount of 'pokethrough' of the lines through the geometry. + // if you always expand along line normal then depending on the angle of the line and camera the edges of the rectangle will poke through i the backside of the surface + vec2 expansion = + tdp > 0.05 + ? tang_clip / tdp + : line_normal; vec2 norm_exp = normalize(expansion); vec2 res_exp_line_direction = vec2(norm_exp.x * u_res.x, norm_exp.y * u_res.y); f_aspect_expansion_len = length(res_exp_line_direction); - f_thickness = (max(max(min(v_luminance / u_max_luminance, 1.0), 0.0) * u_max_thickness, u_min_thickness) / 2.0) / f_aspect_expansion_len; + // todo: contant thickness + f_thickness = + (max(max(min(v_luminance / u_max_luminance, 1.0), 0.0) * u_max_thickness, u_min_thickness) / 2.0) + / f_aspect_expansion_len; f_total_thickness = f_thickness + AA_BUFFER_SIZE / f_aspect_expansion_len; @@ -153,7 +140,9 @@ void main() { // Reverse expansion line_directionection for the duplicated point. if (is_second_point) expansion *= -1.0; - gl_Position = vec4((curr_screen + expansion) / aspect_correction, curr_proj.z / curr_proj.w, 1.0); + vec2 screen_pos = curr_screen + expansion; + screen_pos.x /= aspect_correction; + gl_Position = vec4(screen_pos * curr_proj.w, curr_proj.z /* curr_proj.w*/, curr_proj.w); f_aa_norm = is_second_point ? 1.0 : -1.0; bool is_selected = gl_VertexID >= u_first_selected && gl_VertexID < u_last_selected;