diff --git a/src/Main/fg_scene_commands.cxx b/src/Main/fg_scene_commands.cxx index a2a8d21a4..c00af6499 100644 --- a/src/Main/fg_scene_commands.cxx +++ b/src/Main/fg_scene_commands.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -215,6 +216,15 @@ do_hires_screen_capture (const SGPropertyNode * arg, SGPropertyNode * root) return true; } +/** + * Reload all Compositor instances in the default CameraGroup. + */ +static bool +do_reload_compositor(const SGPropertyNode*, SGPropertyNode*) +{ + flightgear::reloadCompositors(flightgear::CameraGroup::getDefault()); + return true; +} /** * Reload the tile cache. @@ -544,6 +554,7 @@ static struct { { "print-visible-scene", do_print_visible_scene_info }, { "reload-shaders", do_reload_shaders }, { "reload-materials", do_materials_reload }, + { "reload-compositor", do_reload_compositor }, { "open-launcher", do_open_launcher }, { 0, 0 } // zero-terminated }; diff --git a/src/Viewer/CameraGroup.cxx b/src/Viewer/CameraGroup.cxx index 74aab4dd9..4538a0373 100644 --- a/src/Viewer/CameraGroup.cxx +++ b/src/Viewer/CameraGroup.cxx @@ -689,10 +689,16 @@ void CameraGroup::buildCamera(SGPropertyNode* cameraNode) // If no width or height has been specified, fill the entire window viewportNode->getDoubleValue("width", window->gc->getTraits()->width), viewportNode->getDoubleValue("height",window->gc->getTraits()->height)); - std::string default_compositor = - fgGetString("/sim/rendering/default-compositor", "Compositor/default"); - std::string compositor_path = - cameraNode->getStringValue("compositor", default_compositor.c_str()); + + std::string compositor_path = cameraNode->getStringValue("compositor", ""); + if (compositor_path.empty()) { + compositor_path = fgGetString("/sim/rendering/default-compositor", + "Compositor/default"); + } else { + // Store the custom path in case we need to reload later + info->compositor_path = compositor_path; + } + osg::ref_ptr options = SGReaderWriterOptions::fromPath(globals->get_fg_root()); options->setPropertyNode(globals->get_props()); @@ -705,7 +711,7 @@ void CameraGroup::buildCamera(SGPropertyNode* cameraNode) compositor_path, options); if (compositor) { - info->compositor = compositor; + info->compositor.reset(compositor); } else { throw sg_exception(std::string("Failed to create Compositor in path '") + compositor_path + "'"); @@ -787,7 +793,7 @@ void CameraGroup::buildGUICamera(SGPropertyNode* cameraNode, info->name = "GUI camera"; info->viewOffset = osg::Matrix::identity(); info->projOffset = osg::Matrix::identity(); - info->compositor = compositor; + info->compositor.reset(compositor); _cameras.push_back(info); // Disable statistics for the GUI camera. @@ -944,6 +950,36 @@ void warpGUIPointer(CameraGroup* cgroup, int x, int y) cgroup->getView()->getEventQueue()->mouseWarped(viewerX, viewerY); } +void reloadCompositors(CameraGroup *cgroup) +{ + for (auto &info : cgroup->_cameras) { + // Ignore the GUI camera + if (info->flags & CameraInfo::GUI) + continue; + // Get the viewport and the graphics context from the old Compositor + osg::ref_ptr viewport = info->compositor->getViewport(); + osg::ref_ptr gc = + info->compositor->getGraphicsContext(); + osg::ref_ptr options = + SGReaderWriterOptions::fromPath(globals->get_fg_root()); + options->setPropertyNode(globals->get_props()); + + cgroup->_viewer->getViewerBase()->stopThreading(); + // Force deletion + info->compositor.reset(nullptr); + // Then replace it with a new instance + std::string compositor_path = info->compositor_path.empty() ? + fgGetString("/sim/rendering/default-compositor", "Compositor/default") : + info->compositor_path; + info->compositor.reset(Compositor::create(cgroup->_viewer, + gc, + viewport, + compositor_path, + options)); + cgroup->_viewer->getViewerBase()->startThreading(); + } +} + void CameraGroup::buildDefaultGroup(osgViewer::View* viewer) { // Look for windows, camera groups, and the old syntax of diff --git a/src/Viewer/CameraGroup.hxx b/src/Viewer/CameraGroup.hxx index 781b446f5..0490a0c08 100644 --- a/src/Viewer/CameraGroup.hxx +++ b/src/Viewer/CameraGroup.hxx @@ -114,7 +114,12 @@ struct CameraInfo : public osg::Referenced osg::Matrix viewMatrix, projMatrix; /** The Compositor used to manage the pipeline of this camera. */ - osg::ref_ptr compositor; + std::unique_ptr compositor; + /** Compositor path. Used to recreate the pipeline when reloading. + * If the path is empty, it means that this camera isn't using a custom + * Compositor path and should use the default one. + */ + std::string compositor_path; }; class CameraGroup : public osg::Referenced @@ -190,6 +195,7 @@ protected: const osg::Vec2d& windowPos, osgUtil::LineSegmentIntersector::Intersections& intersections); + friend void reloadCompositors(CameraGroup *cgroup); typedef std::vector> CameraList; CameraList _cameras; @@ -237,6 +243,11 @@ bool computeIntersections(const CameraGroup* cgroup, */ void warpGUIPointer(CameraGroup* cgroup, int x, int y); +/** Force a reload of all Compositor instances in the CameraGroup, + * except the one used by the GUI camera. + */ +void reloadCompositors(CameraGroup *cgroup); + } #endif