Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Allow for multiple Panda3D renderers at the same time or sequentially #1524

Merged
merged 3 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 [email protected]
*
* 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
Loading