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;