Skip to content

Commit

Permalink
Merge pull request lagadic#1524 from SamFlt/fix_panda_multi_renders
Browse files Browse the repository at this point in the history
[FEAT] Allow for multiple Panda3D renderers at the same time or sequentially
  • Loading branch information
fspindle authored Dec 17, 2024
2 parents bbb1d8e + a0ba03b commit b0ac244
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 31 deletions.
12 changes: 12 additions & 0 deletions modules/ar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,15 @@ vp_glob_module_sources()

vp_module_include_directories(${opt_incs} SYSTEM ${opt_system_incs})
vp_create_module(${opt_libs})


set(opt_test_incs "")
set(opt_test_libs "")

if(WITH_CATCH2)
# catch2 is private
list(APPEND opt_test_incs ${CATCH2_INCLUDE_DIRS})
list(APPEND opt_test_libs ${CATCH2_LIBRARIES})
endif()

vp_add_tests(DEPENDS_ON visp_core PRIVATE_INCLUDE_DIRS ${opt_test_incs} PRIVATE_LIBRARIES ${opt_test_libs})
24 changes: 19 additions & 5 deletions modules/ar/include/visp3/ar/vpPanda3DBaseRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,32 @@ class VISP_EXPORT vpPanda3DBaseRenderer
{
public:
vpPanda3DBaseRenderer(const std::string &rendererName)
: m_name(rendererName), m_renderOrder(-100), m_framework(nullptr), m_window(nullptr), m_camera(nullptr)
: m_name(rendererName), m_renderOrder(-100), m_window(nullptr), m_camera(nullptr), m_isWindowOwner(false)
{
setVerticalSyncEnabled(false);
}

virtual ~vpPanda3DBaseRenderer() = default;
virtual ~vpPanda3DBaseRenderer()
{
if (m_window != nullptr) {
for (GraphicsOutput *buffer: m_buffers) {
buffer->get_engine()->remove_window(buffer);
}
}
if (m_isWindowOwner) {
framework.close_window(m_window);
}

m_window = nullptr;
}

/**
* @brief Initialize the whole Panda3D framework. Create a new PandaFramework object and a new window.
*
* Will also perform the renderer setup (scene, camera and render targets)
*/
virtual void initFramework();
virtual void initFromParent(std::shared_ptr<PandaFramework> framework, PointerTo<WindowFramework> window);
virtual void initFromParent(PointerTo<WindowFramework> window);
virtual void initFromParent(const vpPanda3DBaseRenderer &renderer);

virtual void beforeFrameRendered() { }
Expand All @@ -80,7 +92,7 @@ class VISP_EXPORT vpPanda3DBaseRenderer
{
GraphicsOutput *mainBuffer = getMainOutputBuffer();
if (mainBuffer != nullptr) {
m_framework->get_graphics_engine()->extract_texture_data(mainBuffer->get_texture(), mainBuffer->get_gsg());
m_window->get_graphics_output()->get_engine()->extract_texture_data(mainBuffer->get_texture(), mainBuffer->get_gsg());
}
}

Expand Down Expand Up @@ -266,17 +278,19 @@ class VISP_EXPORT vpPanda3DBaseRenderer

const static vpHomogeneousMatrix VISP_T_PANDA; //! Homogeneous transformation matrix to convert from the Panda coordinate system (right-handed Z-up) to the ViSP coordinate system (right-handed Y-Down)
const static vpHomogeneousMatrix PANDA_T_VISP; //! Inverse of VISP_T_PANDA
static PandaFramework framework; //! Panda Rendering framework
static bool frameworkIsOpen;

protected:
std::string m_name; //! name of the renderer
int m_renderOrder; //! Rendering priority for this renderer and its buffers. A lower value will be rendered first. Should be used when calling make_output in setupRenderTarget()
std::shared_ptr<PandaFramework> m_framework; //! Pointer to the active panda framework
PointerTo<WindowFramework> m_window; //! Pointer to owning window, which can create buffers etc. It is not necessarily visible.
vpPanda3DRenderParameters m_renderParameters; //! Rendering parameters
NodePath m_renderRoot; //! Node containing all the objects and the camera for this renderer
PointerTo<Camera> m_camera;
NodePath m_cameraPath; //! NodePath of the camera
std::vector<GraphicsOutput *> m_buffers; //! Set of buffers that this renderer uses. This storage contains weak refs to those buffers and should not deallocate them.
bool m_isWindowOwner; // Whether this panda subrenderer is the "owner" of the window framework and should close all associated windows when getting destroyed
};

END_VISP_NAMESPACE
Expand Down
2 changes: 1 addition & 1 deletion modules/ar/include/visp3/ar/vpPanda3DRendererSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class VISP_EXPORT vpPanda3DRendererSet : public vpPanda3DBaseRenderer, public vp
* Thus, if a renderer B depends on A for its render, and if B.getRenderOrder() > A.getRenderOrder() it can rely on A being initialized when B.initFromParent is called (along with the setupCamera, setupRenderTarget).
*/
void initFramework() VP_OVERRIDE;
void initFromParent(std::shared_ptr<PandaFramework> framework, PointerTo<WindowFramework> window) VP_OVERRIDE;
void initFromParent(PointerTo<WindowFramework> window) VP_OVERRIDE;
void initFromParent(const vpPanda3DBaseRenderer &renderer) VP_OVERRIDE;

/**
Expand Down
43 changes: 31 additions & 12 deletions modules/ar/src/panda3d-simulator/vpPanda3DBaseRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,29 @@ const vpHomogeneousMatrix vpPanda3DBaseRenderer::VISP_T_PANDA({
});
const vpHomogeneousMatrix vpPanda3DBaseRenderer::PANDA_T_VISP(vpPanda3DBaseRenderer::VISP_T_PANDA.inverse());


PandaFramework vpPanda3DBaseRenderer::framework;
bool vpPanda3DBaseRenderer::frameworkIsOpen(false);


void vpPanda3DBaseRenderer::initFramework()
{
if (m_framework.use_count() > 0) {
throw vpException(vpException::notImplementedError,
"Panda3D renderer: Reinitializing is not supported!");

if (!frameworkIsOpen) {
frameworkIsOpen = true;
framework.open_framework();
}
m_framework = std::shared_ptr<PandaFramework>(new PandaFramework());
m_framework->open_framework();

m_isWindowOwner = true;

WindowProperties winProps;
winProps.set_size(LVecBase2i(m_renderParameters.getImageWidth(), m_renderParameters.getImageHeight()));
int flags = GraphicsPipe::BF_refuse_window;
m_window = m_framework->open_window(winProps, flags);
m_window = framework.open_window(winProps, flags);
// try and reopen with visible window
if (m_window == nullptr) {
winProps.set_minimized(true);
m_window = m_framework->open_window(winProps, 0);
m_window = framework.open_window(winProps, 0);
}
if (m_window == nullptr) {
throw vpException(vpException::notInitialized,
Expand All @@ -76,9 +83,9 @@ void vpPanda3DBaseRenderer::initFramework()
//m_window->get_display_region_3d()->set_camera(m_cameraPath);
}

void vpPanda3DBaseRenderer::initFromParent(std::shared_ptr<PandaFramework> framework, PointerTo<WindowFramework> window)
void vpPanda3DBaseRenderer::initFromParent(PointerTo<WindowFramework> window)
{
m_framework = framework;
m_isWindowOwner = false;
m_window = window;
setupScene();
setupCamera();
Expand All @@ -87,7 +94,8 @@ void vpPanda3DBaseRenderer::initFromParent(std::shared_ptr<PandaFramework> frame

void vpPanda3DBaseRenderer::initFromParent(const vpPanda3DBaseRenderer &renderer)
{
initFromParent(renderer.m_framework, renderer.m_window);
m_isWindowOwner = false;
initFromParent(renderer.m_window);
}

void vpPanda3DBaseRenderer::setupScene()
Expand All @@ -109,7 +117,18 @@ void vpPanda3DBaseRenderer::setupCamera()
void vpPanda3DBaseRenderer::renderFrame()
{
beforeFrameRendered();
m_framework->get_graphics_engine()->render_frame();
// Disable rendering for all the other renderers
for (int i = 0; i < framework.get_num_windows(); ++i) {
WindowFramework *fi = framework.get_window(i);
if (fi != m_window) {
fi->get_graphics_output()->get_gsg()->set_active(false);
}
}
m_window->get_graphics_output()->get_engine()->render_frame();
for (int i = 0; i < framework.get_num_windows(); ++i) {
WindowFramework *fi = framework.get_window(i);
fi->get_graphics_output()->get_gsg()->set_active(true);
}
afterFrameRendered();
}

Expand Down Expand Up @@ -273,7 +292,7 @@ void vpPanda3DBaseRenderer::enableSharedDepthBuffer(vpPanda3DBaseRenderer &sourc

NodePath vpPanda3DBaseRenderer::loadObject(const std::string &nodeName, const std::string &modelPath)
{
NodePath model = m_window->load_model(m_framework->get_models(), modelPath);
NodePath model = m_window->load_model(framework.get_models(), modelPath);
for (int i = 0; i < model.get_num_children(); ++i) {
model.get_child(i).clear_transform();
}
Expand Down
27 changes: 14 additions & 13 deletions modules/ar/src/panda3d-simulator/vpPanda3DRendererSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,35 +45,36 @@ vpPanda3DRendererSet::vpPanda3DRendererSet(const vpPanda3DRenderParameters &rend

void vpPanda3DRendererSet::initFramework()
{
if (m_framework.use_count() > 0) {
throw vpException(vpException::notImplementedError, "Panda3D renderer: Reinitializing is not supported!");

if (!frameworkIsOpen) {
frameworkIsOpen = true;
framework.open_framework();
}
m_framework = std::shared_ptr<PandaFramework>(new PandaFramework());
m_isWindowOwner = true;

m_framework->open_framework();
WindowProperties winProps;
winProps.set_size(LVecBase2i(m_renderParameters.getImageWidth(), m_renderParameters.getImageHeight()));
int flags = GraphicsPipe::BF_refuse_window;
m_window = m_framework->open_window(winProps, flags);
m_window = framework.open_window(winProps, flags);
if (m_window == nullptr) {
winProps.set_minimized(true);
m_window = m_framework->open_window(winProps, 0);
m_window = framework.open_window(winProps, 0);
}
if (m_window == nullptr) {
throw vpException(vpException::fatalError, "Could not open Panda3D window (hidden or visible)");
}

m_window->set_background_type(WindowFramework::BackgroundType::BT_black);
for (std::shared_ptr<vpPanda3DBaseRenderer> &renderer: m_subRenderers) {
renderer->initFromParent(m_framework, m_window);
renderer->initFromParent(*this);
}
}

void vpPanda3DRendererSet::initFromParent(std::shared_ptr<PandaFramework> framework, PointerTo<WindowFramework> window)
void vpPanda3DRendererSet::initFromParent(PointerTo<WindowFramework> window)
{
vpPanda3DBaseRenderer::initFromParent(framework, window);
vpPanda3DBaseRenderer::initFromParent(window);
for (std::shared_ptr<vpPanda3DBaseRenderer> &renderer: m_subRenderers) {
renderer->initFromParent(m_framework, m_window);
renderer->initFromParent(m_window);
}
}

Expand Down Expand Up @@ -177,12 +178,12 @@ void vpPanda3DRendererSet::addSubRenderer(std::shared_ptr<vpPanda3DBaseRenderer>
++it;
}
m_subRenderers.insert(it, renderer);

renderer->setRenderParameters(m_renderParameters);
if (m_framework != nullptr) {
renderer->initFromParent(m_framework, m_window);
if (m_window != nullptr) {
renderer->initFromParent(m_window);
renderer->setCameraPose(getCameraPose());
}

}

void vpPanda3DRendererSet::enableSharedDepthBuffer(vpPanda3DBaseRenderer &sourceBuffer)
Expand Down
93 changes: 93 additions & 0 deletions modules/ar/test/catchPanda.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* ViSP, open source Visual Servoing Platform software.
* Copyright (C) 2005 - 2024 by Inria. All rights reserved.
*
* This software is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* See the file LICENSE.txt at the root directory of this source
* distribution for additional information about the GNU GPL.
*
* For using ViSP with software that can not be combined with the GNU
* GPL, please contact Inria about acquiring a ViSP Professional
* Edition License.
*
* See https://visp.inria.fr for more information.
*
* This software was developed at:
* Inria Rennes - Bretagne Atlantique
* Campus Universitaire de Beaulieu
* 35042 Rennes Cedex
* France
*
* If you have questions regarding the use of this file, please contact
* Inria at visp@inria.fr
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Description:
* Test vpCameraParameters JSON parse / save.
*/

/*!
\example catchJsonCamera.cpp
Test saving and parsing JSON configuration for vpCameraParameters.
*/

#include <visp3/core/vpCameraParameters.h>
#include <visp3/core/vpIoTools.h>

#if defined(VISP_HAVE_PANDA3D) && defined(VISP_HAVE_CATCH2)
#include <visp3/ar/vpPanda3DBaseRenderer.h>
#include <visp3/ar/vpPanda3DRGBRenderer.h>
#include <visp3/ar/vpPanda3DGeometryRenderer.h>
#include <visp3/core/vpCameraParameters.h>
#include <catch_amalgamated.hpp>

#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

#include <random>


vpPanda3DRenderParameters defaultRenderParams()
{
vpCameraParameters cam(600, 600, 160, 120);
return vpPanda3DRenderParameters(cam, 240, 320, 0.001, 1.0);
}

SCENARIO("Instanciating multiple Panda3D renderers", "[Panda3D]")
{
GIVEN("A single renderer")
{
vpPanda3DGeometryRenderer r1(vpPanda3DGeometryRenderer::CAMERA_NORMALS);
r1.setRenderParameters(defaultRenderParams());
r1.initFramework();

THEN("Creating another, uncoupled renderer is ok and its destruction does not raise an error")
{
vpPanda3DGeometryRenderer r2(vpPanda3DGeometryRenderer::CAMERA_NORMALS);
r2.setRenderParameters(defaultRenderParams());
r2.initFramework();
}
}
}

int main(int argc, char *argv[])
{
Catch::Session session; // There must be exactly one instance
session.applyCommandLine(argc, argv);

int numFailed = session.run();
return numFailed;
}

#else

int main() { return EXIT_SUCCESS; }

#endif

0 comments on commit b0ac244

Please sign in to comment.