-
Mathias Paulin authoredMathias Paulin authored
MainWindow.cpp 21.76 KiB
#include <Gui/MainWindow.hpp>
#include <RadiumNBR/Gui/RendererPanel.hpp>
#include <tuple>
#include <QColorDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QToolBar>
#include <Gui/SelectionManager/SelectionManager.hpp>
#include <Gui/Timeline/Timeline.hpp>
#include <Gui/Viewer/CameraManipulator.hpp>
#include <Gui/Viewer/Gizmo/GizmoManager.hpp>
#include <Gui/Viewer/Viewer.hpp>
#include <PluginBase/RadiumPluginInterface.hpp>
#include <Engine/Rendering/ForwardRenderer.hpp>
#include <Engine/Rendering/RenderObjectManager.hpp>
#include <Engine/Scene/Camera.hpp>
#include <Engine/Scene/EntityManager.hpp>
#include <Engine/Scene/SignalManager.hpp>
#include <Engine/Scene/SystemDisplay.hpp>
#include <Core/Asset/FileLoaderInterface.hpp>
#include <Core/Utils/StringUtils.hpp>
#include <RadiumPlayer.hpp>
#include <Engine/Scene/SkeletonBasedAnimationSystem.hpp>
#include <Gui/SkeletonBasedAnimation/SkeletonBasedAnimationUI.hpp>
using namespace Ra::Gui;
using namespace Ra::Engine;
using namespace Ra::Engine::Rendering;
using namespace Ra::Engine::Scene;
namespace Mara {
MainWindow::MainWindow( QWidget* parent ) : MainWindowInterface( parent ) {
setupUi( this );
// Initialize the minimum tools for a Radium-Guibased Application
m_viewer = std::make_unique<Viewer>();
m_viewer->setObjectName( QStringLiteral( "m_viewer" ) );
// Initialize the scene interactive representation
m_sceneModel = new ItemModel( Ra::Engine::RadiumEngine::getInstance(), this );
m_selectionManager = new SelectionManager( m_sceneModel, this );
connect( m_selectionManager,
&Ra::Gui::SelectionManager::selectionChanged,
this,
&MainWindow::onSelectionChanged );
// initialize Gui for the application
auto viewerwidget = QWidget::createWindowContainer( m_viewer.get() );
viewerwidget->setAutoFillBackground( false );
setCentralWidget( viewerwidget );
setWindowTitle( QString( "Radium player" ) );
// Application control window
m_controlWindow = new ControlDialogWindow();
#ifdef SHOWTREEVIEW
m_sceneTreeView = new QTreeView();
m_sceneTreeView->setModel( m_sceneModel );
m_sceneTreeView->setSelectionModel( m_selectionManager );
m_controlWindow->addTab( m_sceneTreeView, "Scene" );
addControl( "Scene", tr( "Ctrl+N" ) );
#endif
m_rendererControler = new RendererControl( this );
m_controlWindow->addTab( m_rendererControler, "Renderer" );
addControl( "Renderer", tr( "Ctrl+R" ) );
createConnections();
}
MainWindow::~MainWindow() = default;
// Child QObjects will automatically be deleted
void MainWindow::cleanup() {
// Must ensure the viewer is deleted once.
m_viewer.reset( nullptr );
}
void MainWindow::addTimelineToolBar() {
auto timelineToolbar = new QToolBar( "Timeline", this );
timelineToolbar->setAllowedAreas( Qt::BottomToolBarArea );
timelineToolbar->setVisible( false );
// Add and connect timeline
m_timeline = new Ra::Gui::Timeline( this );
m_timeline->onChangeEnd( Ra::Engine::RadiumEngine::getInstance()->getEndTime() );
// Timeline setup
connect( m_timeline, &Ra::Gui::Timeline::playClicked, this, &MainWindow::timelinePlay );
connect( m_timeline, &Ra::Gui::Timeline::cursorChanged, this, &MainWindow::timelineGoTo );
connect(
m_timeline, &Ra::Gui::Timeline::startChanged, this, &MainWindow::timelineStartChanged );
connect( m_timeline, &Ra::Gui::Timeline::endChanged, this, &MainWindow::timelineEndChanged );
connect( m_timeline, &Ra::Gui::Timeline::setPingPong, this, &MainWindow::timelineSetPingPong );
connect(
m_timeline, &Ra::Gui::Timeline::keyFrameChanged, [=]( Scalar ) { emit frameUpdate(); } );
connect( this, &MainWindow::selectedItem, m_timeline, &Ra::Gui::Timeline::selectionChanged );
timelineToolbar->addWidget( m_timeline );
this->addToolBar( Qt::BottomToolBarArea, timelineToolbar );
auto showTimelineToolbar = new QAction( this );
showTimelineToolbar->setObjectName( QString::fromUtf8( "showTimelineToolbar" ) );
showTimelineToolbar->setCheckable( true );
showTimelineToolbar->setChecked( false );
showTimelineToolbar->setText(
QCoreApplication::translate( "MainWindow", "Timeline toolbar", nullptr ) );
showTimelineToolbar->setToolTip(
QCoreApplication::translate( "MainWindow", "Show/hide the timeline toolbar", nullptr ) );
connect( showTimelineToolbar, &QAction::triggered, timelineToolbar, &QToolBar::setVisible );
connect( timelineToolbar, &QToolBar::visibilityChanged, [showTimelineToolbar]( bool b ) {
showTimelineToolbar->setChecked( b );
} );
menuToolbars->addAction( showTimelineToolbar );
}
void MainWindow::addSelectionToolBar() {
auto selectionToolBar = new QToolBar( "Selection toolbar", this );
auto actionGizmoOff = new QAction( selectionToolBar );
actionGizmoOff->setObjectName( QString::fromUtf8( "actionGizmoOff" ) );
actionGizmoOff->setCheckable( false );
actionGizmoOff->setChecked( false );
QIcon icon3;
icon3.addFile(
QString::fromUtf8( ":/Resources/Icons/select.png" ), QSize(), QIcon::Normal, QIcon::On );
actionGizmoOff->setIcon( icon3 );
actionGizmoOff->setText( QCoreApplication::translate( "MainWindow", "No Gizmos", nullptr ) );
actionGizmoOff->setToolTip(
QCoreApplication::translate( "MainWindow", "Disable transform gizmo.", nullptr ) );
auto actionGizmoTranslate = new QAction( selectionToolBar );
actionGizmoTranslate->setObjectName( QString::fromUtf8( "actionGizmoTranslate" ) );
actionGizmoTranslate->setCheckable( false );
QIcon icon;
icon.addFile(
QString::fromUtf8( ":/Resources/Icons/translate.png" ), QSize(), QIcon::Normal, QIcon::On );
actionGizmoTranslate->setIcon( icon );
actionGizmoTranslate->setText(
QCoreApplication::translate( "MainWindow", "Translate", nullptr ) );
actionGizmoTranslate->setToolTip(
QCoreApplication::translate( "MainWindow", "Translate selected object", nullptr ) );
auto actionGizmoRotate = new QAction( selectionToolBar );
actionGizmoRotate->setObjectName( QString::fromUtf8( "actionGizmoRotate" ) );
actionGizmoRotate->setCheckable( false );
QIcon icon1;
icon1.addFile(
QString::fromUtf8( ":/Resources/Icons/rotate.png" ), QSize(), QIcon::Normal, QIcon::On );
actionGizmoRotate->setIcon( icon1 );
actionGizmoRotate->setText( QCoreApplication::translate( "MainWindow", "Rotate", nullptr ) );
actionGizmoRotate->setToolTip(
QCoreApplication::translate( "MainWindow", "Rotate selected object", nullptr ) );
auto actionToggle_Local_Global = new QAction( selectionToolBar );
actionToggle_Local_Global->setObjectName( QString::fromUtf8( "actionToggle_Local_Global" ) );
actionToggle_Local_Global->setCheckable( true );
QIcon icon2;
icon2.addFile(
QString::fromUtf8( ":/Resources/Icons/gizmo.png" ), QSize(), QIcon::Normal, QIcon::On );
actionToggle_Local_Global->setIcon( icon2 );
actionToggle_Local_Global->setText(
QCoreApplication::translate( "MainWindow", "Toggle Local/Global", nullptr ) );
actionToggle_Local_Global->setToolTip( QCoreApplication::translate(
"MainWindow", "Changes the transform edition mode", nullptr ) );
auto actionGizmoScale = new QAction( selectionToolBar );
actionGizmoScale->setObjectName( QString::fromUtf8( "actionGizmoScale" ) );
actionGizmoScale->setCheckable( false );
QIcon icon5;
icon5.addFile(
QString::fromUtf8( ":/Resources/Icons/scale.png" ), QSize(), QIcon::Normal, QIcon::Off );
actionGizmoScale->setIcon( icon5 );
actionGizmoScale->setText( QCoreApplication::translate( "MainWindow", "Scale", nullptr ) );
actionGizmoScale->setToolTip(
QCoreApplication::translate( "MainWindow", "Scale selected object", nullptr ) );
selectionToolBar->addAction( actionToggle_Local_Global );
selectionToolBar->addAction( actionGizmoTranslate );
selectionToolBar->addAction( actionGizmoRotate );
selectionToolBar->addAction( actionGizmoScale );
selectionToolBar->addAction( actionGizmoOff );
connect(
this, &MainWindow::selectedItem, m_viewer->getGizmoManager(), &GizmoManager::setEditable );
connect( actionGizmoOff, &QAction::triggered, this, &MainWindow::gizmoShowNone );
connect( actionGizmoTranslate, &QAction::triggered, this, &MainWindow::gizmoShowTranslate );
connect( actionGizmoRotate, &QAction::triggered, this, &MainWindow::gizmoShowRotate );
connect( actionGizmoScale, &QAction::triggered, this, &MainWindow::gizmoShowScale );
connect( actionToggle_Local_Global,
&QAction::toggled,
m_viewer->getGizmoManager(),
&GizmoManager::setLocal );
connect( actionToggle_Local_Global, &QAction::toggled, this, &MainWindow::frameUpdate );
this->addToolBar( selectionToolBar );
auto showSelectionToolbar = new QAction( this );
showSelectionToolbar->setObjectName( QString::fromUtf8( "showSelectionToolbar" ) );
showSelectionToolbar->setCheckable( true );
showSelectionToolbar->setChecked( true );
showSelectionToolbar->setText(
QCoreApplication::translate( "MainWindow", "Selection toolbar", nullptr ) );
showSelectionToolbar->setToolTip(
QCoreApplication::translate( "MainWindow", "Show/hide the selection toolbar", nullptr ) );
connect( showSelectionToolbar, &QAction::triggered, selectionToolBar, &QToolBar::setVisible );
connect( selectionToolBar, &QToolBar::visibilityChanged, [showSelectionToolbar]( bool b ) {
showSelectionToolbar->setChecked( b );
} );
menuToolbars->addAction( showSelectionToolbar );
}
void MainWindow::postOpenGLInitializations() {
addSelectionToolBar();
addTimelineToolBar();
addRadiumSystemsUI();
}
void MainWindow::createConnections() {
// Radium engine and Gui initialization process
connect( m_viewer.get(), &Viewer::glInitialized, this, &MainWindow::postOpenGLInitializations );
// Define and connect Engine callbacks
auto add = std::bind( &MainWindow::ItemAdded, this, std::placeholders::_1 );
auto del = std::bind( &MainWindow::ItemRemoved, this, std::placeholders::_1 );
// Connect engine signals to the appropriate callbacks
auto theEngine = Ra::Engine::RadiumEngine::getInstance();
theEngine->getSignalManager()->m_entityCreatedCallbacks.push_back( add );
theEngine->getSignalManager()->m_entityDestroyedCallbacks.push_back( del );
theEngine->getSignalManager()->m_componentAddedCallbacks.push_back( add );
theEngine->getSignalManager()->m_componentRemovedCallbacks.push_back( del );
theEngine->getSignalManager()->m_roAddedCallbacks.push_back( add );
theEngine->getSignalManager()->m_roRemovedCallbacks.push_back( del );
// Qt Gui callbacks
connect( action_Load, &QAction::triggered, this, &MainWindow::loadFile );
connect( actionInfo, &QAction::triggered, this, &MainWindow::displayFileInfo );
connect( action_Reload_shaders, &QAction::triggered, m_viewer.get(), &Viewer::reloadShaders );
connect( m_rendererControler,
&RendererControl::rendererStateChanged,
this,
&MainWindow::frameUpdate );
connect( action_Config, &QAction::triggered, this, &MainWindow::configure );
connect( actionAdd_PluginsDir, &QAction::triggered, this, &MainWindow::addPluginsDir );
connect( actionClear_PluginsDir, &QAction::triggered, this, &MainWindow::clearPluginsDir );
#ifdef SHOWTREEVIEW
connect( actionTree_view, &QAction::triggered, this, &MainWindow::displayTreeView );
#endif
// TODO : connect callbacks roAdded and roRemoved to the renderer and add observable on
// RenderObject to manage more efficiently update for rendering
connect( m_sceneModel, &ItemModel::visibilityROChanged, this, &MainWindow::setROVisible );
connect( m_rendererControler, &RendererControl::fitCamera, this, &MainWindow::fitCamera );
connect( m_rendererControler, &RendererControl::resetCamera, this, &MainWindow::resetCamera );
}
void MainWindow::addRenderer( const std::string& name, std::shared_ptr<Renderer> e ) {
addRenderer( name, e, nullptr );
}
void MainWindow::addRenderer( const std::string& name,
std::shared_ptr<Renderer> e,
RadiumNBR::Gui::RendererPanel* controlPanel ) {
auto id = m_viewer->addRenderer( e );
auto rendererCallback = [this, id]() { return this->m_viewer->changeRenderer( id ); };
m_rendererControler->addRenderer( name, e.get(), rendererCallback, controlPanel );
}
Viewer* MainWindow::getViewer() {
return m_viewer.get();
}
void MainWindow::onFrameComplete() {
// update timeline only if time changed, to allow manipulation of keyframed objects
auto engine = Ra::Engine::RadiumEngine::getInstance();
if ( !Ra::Core::Math::areApproxEqual( m_timeline->getTime(), engine->getTime() ) )
{
m_lockTimeSystem = true;
m_timeline->onChangeCursor( engine->getTime() );
m_lockTimeSystem = false;
}
}
void MainWindow::activateCamera( const std::string& sceneName ) {
// If a camera is in the given scene, use it, else, use default
std::string loadedEntityName = Ra::Core::Utils::getBaseName( sceneName, false );
auto rootEntity =
Ra::Engine::RadiumEngine::getInstance()->getEntityManager()->getEntity( loadedEntityName );
if ( rootEntity != nullptr )
{
auto fc = std::find_if(
rootEntity->getComponents().begin(),
rootEntity->getComponents().end(),
[]( const auto& c ) { return ( c->getName().compare( 0, 7, "CAMERA_" ) == 0 ); } );
if ( fc != rootEntity->getComponents().end() )
{
LOG( Ra::Core::Utils::logINFO ) << "Activating camera " << ( *fc )->getName();
const auto systemEntity = Ra::Engine::Scene::SystemEntity::getInstance();
systemEntity->removeComponent( "CAMERA_DEFAULT" );
auto camera = static_cast<Ra::Engine::Scene::Camera*>( ( *fc ).get() );
m_viewer->getCameraManipulator()->setCamera(
camera->duplicate( systemEntity, "CAMERA_DEFAULT" ) );
}
}
}
void MainWindow::prepareDisplay() {
if ( m_viewer->prepareDisplay() ) { emit frameUpdate(); }
}
void MainWindow::addControl( const QString& tabName, const QKeySequence& shortcut ) {
auto name = tabName.toStdString();
menuControl->addAction(
tabName, [this, name]() { this->m_controlWindow->showTab( name ); }, shortcut );
}
void MainWindow::updateUi( Ra::Plugins::RadiumPluginInterface* plugin ) {
// Add widget
QString tabName;
if ( plugin->doAddWidget( tabName ) )
{
QString shortcut = "Ctrl+" + tabName[0];
addControl( tabName, tr( shortcut.toStdString().c_str() ) );
m_controlWindow->addTab( plugin->getWidget(), tabName.toStdString() );
}
}
void MainWindow::loadFile() {
QString filter;
QString allexts;
for ( const auto& loader : Ra::Engine::RadiumEngine::getInstance()->getFileLoaders() )
{
QString exts;
for ( const auto& e : loader->getFileExtensions() )
{
exts.append( QString::fromStdString( e ) + tr( " " ) );
}
allexts.append( exts + tr( " " ) );
filter.append( QString::fromStdString( loader->name() ) + tr( " (" ) + exts + tr( ");;" ) );
}
// add a filter concetenatting all the supported extensions
filter.prepend( tr( "Supported files (" ) + allexts + tr( ");;" ) );
// remove the last ";;" of the string
filter.remove( filter.size() - 2, 2 );
QSettings settings;
auto path = settings.value( "files/load", QDir::homePath() ).toString();
auto pathList = QFileDialog::getOpenFileNames( this, "Open Files", path, filter );
if ( !pathList.empty() )
{
/* Remove existing scene before loading the new one */
m_viewer->getCameraManipulator()->resetToDefaultCamera();
m_selectionManager->clear();
Ra::Engine::RadiumEngine::getInstance()->getEntityManager()->deleteEntities();
fitCamera();
// load the new scene
settings.setValue( "files/load", pathList.front() );
for ( const auto& file : pathList )
{
emit fileLoading( file );
}
auto romgr = Ra::Engine::RadiumEngine::getInstance()->getRenderObjectManager();
auto polyCount = romgr->getNumFaces();
auto vertexCount = romgr->getNumVertices();
auto objectCount = romgr->getRenderObjectsCount();
auto sceneStats = std::make_tuple( objectCount, polyCount, vertexCount );
m_controlWindow->setFileInfo( pathList.first().toStdString(), sceneStats );
activateCamera( pathList.first().toStdString() );
std::string loadedEntityName =
Ra::Core::Utils::getBaseName( pathList.first().toStdString(), false );
auto rootEntity = Ra::Engine::RadiumEngine::getInstance()->getEntityManager()->getEntity(
loadedEntityName );
if ( rootEntity != nullptr ) { emit entityAdded( rootEntity ); }
}
}
void MainWindow::setROVisible( Ra::Core::Utils::Index roIndex, bool visible ) {
emit roChanged( roIndex, visible );
}
void MainWindow::displayFileInfo() {
m_controlWindow->showTab( "Information" );
}
void MainWindow::fitCamera() {
auto aabb = Ra::Engine::RadiumEngine::getInstance()->computeSceneAabb();
if ( aabb.isEmpty() ) { m_viewer->getCameraManipulator()->resetCamera(); }
else
{ m_viewer->fitCameraToScene( aabb ); }
emit frameUpdate();
}
void MainWindow::resetCamera() {
if ( m_initialCamera )
{
const auto systemEntity = SystemEntity::getInstance();
systemEntity->removeComponent( "CAMERA_DEFAULT" );
auto c = m_initialCamera->duplicate( systemEntity, "CAMERA_DEFAULT" );
c->resize( m_viewer->width(), m_viewer->height() );
m_viewer->getCameraManipulator()->setCamera( c );
emit frameUpdate();
}
else
{ fitCamera(); }
}
Ra::Gui::SelectionManager* MainWindow::getSelectionManager() {
return m_selectionManager;
}
Ra::Gui::Timeline* MainWindow::getTimeline() {
// mus return not null ?
return m_timeline;
}
void MainWindow::ItemAdded( const ItemEntry& ent ) {
m_sceneModel->addItem( ent );
}
void MainWindow::ItemRemoved( const ItemEntry& ent ) {
m_sceneModel->removeItem( ent );
}
void MainWindow::configure() {
QMessageBox::about(
this, "Radium rendering application", "Configuration panel not yet implemented !" );
}
#ifdef SHOWTREEVIEW
void MainWindow::displayTreeView() {
m_controlWindow->showTab( "Scene" );
}
#endif
void MainWindow::on_actionPlay_triggered( bool checked ) {
Ra::Engine::RadiumEngine::getInstance()->play( checked );
emit timeFlow( checked );
}
void MainWindow::on_actionStop_triggered() {
on_actionPlay_triggered( false );
Ra::Engine::RadiumEngine::getInstance()->resetTime();
actionPlay->setChecked( false );
emit frameUpdate();
}
void MainWindow::on_actionStep_triggered() {
Ra::Engine::RadiumEngine::getInstance()->step();
emit frameUpdate();
}
void MainWindow::gizmoShowNone() {
m_viewer->getGizmoManager()->changeGizmoType( GizmoManager::NONE );
emit frameUpdate();
}
void MainWindow::gizmoShowTranslate() {
m_viewer->getGizmoManager()->changeGizmoType( GizmoManager::TRANSLATION );
emit frameUpdate();
}
void MainWindow::gizmoShowRotate() {
m_viewer->getGizmoManager()->changeGizmoType( GizmoManager::ROTATION );
emit frameUpdate();
}
void MainWindow::gizmoShowScale() {
m_viewer->getGizmoManager()->changeGizmoType( GizmoManager::SCALE );
emit frameUpdate();
}
void MainWindow::onSelectionChanged( const QItemSelection& /*selected*/,
const QItemSelection& /*deselected*/ ) {
if ( m_selectionManager->hasSelection() )
{
const ItemEntry& ent = m_selectionManager->currentItem();
emit selectedItem( ent );
/*
* @todo : complete this method to handle how events due to election changes
* cf RadiumSandBox/Mainwindow
*/
}
else
{ emit selectedItem( ItemEntry() ); }
}
void MainWindow::timelinePlay( bool play ) {
actionPlay->setChecked( play );
if ( !m_lockTimeSystem )
{
on_actionPlay_triggered( play );
}
}
void MainWindow::timelineGoTo( double t ) {
if ( !m_lockTimeSystem )
{
Ra::Engine::RadiumEngine::getInstance()->setTime( Scalar( t ) );
emit frameUpdate();
}
}
void MainWindow::timelineStartChanged( double t ) {
if ( !m_lockTimeSystem )
{
Ra::Engine::RadiumEngine::getInstance()->setStartTime( Scalar( t ) );
emit frameUpdate();
}
}
void MainWindow::timelineEndChanged( double t ) {
if ( !m_lockTimeSystem )
{
Ra::Engine::RadiumEngine::getInstance()->setEndTime( Scalar( t ) );
emit frameUpdate();
}
}
void MainWindow::timelineSetPingPong( bool status ) {
if ( !m_lockTimeSystem )
{
Ra::Engine::RadiumEngine::getInstance()->setForwardBackward( status );
emit frameUpdate();
}
}
void MainWindow::addRadiumSystemsUI() {
// Register the Skeleton-based animation UI
auto animSystem = static_cast<Ra::Engine::Scene::SkeletonBasedAnimationSystem*>(
Ra::Engine::RadiumEngine::getInstance()->getSystem( "SkeletonBasedAnimationSystem" ) );
auto skelAnimUI = new Ra::Gui::SkeletonBasedAnimationUI( animSystem, m_timeline );
m_controlWindow->addTab( skelAnimUI, "Skeleton Animation" );
addControl( "Skeleton Animation", tr( "Ctrl+A" ) );
connect( skelAnimUI, &Ra::Gui::SkeletonBasedAnimationUI::askForUpdate, [this]() {
emit frameUpdate();
} );
connect( this,
&MainWindow::entityAdded,
skelAnimUI,
&Ra::Gui::SkeletonBasedAnimationUI::postLoadFile );
connect( this,
&MainWindow::selectedItem,
skelAnimUI,
&Ra::Gui::SkeletonBasedAnimationUI::selectionChanged );
}
} // namespace Mara