Skip to content

Commit

Permalink
EventLoop: Support playing interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
mwestphal committed Dec 12, 2024
1 parent 9f6b417 commit dda37e1
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 44 deletions.
6 changes: 4 additions & 2 deletions application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace fs = std::filesystem;
// This pointer is used to retrieve the interactor in case an OS signal is handled
f3d::interactor* GlobalInteractor = nullptr;

static constexpr int EVENT_LOOP_TIME = 30;

class F3DStarter::F3DInternals
{
public:
Expand Down Expand Up @@ -928,7 +930,7 @@ int F3DStarter::Start(int argc, char** argv)
{
// For better testing, render once before the interaction
window.render();
if (!interactor.playInteraction(interactionTestPlayFile))
if (!interactor.playInteraction(interactionTestPlayFile, EVENT_LOOP_TIME))
{
return EXIT_FAILURE;
}
Expand Down Expand Up @@ -1084,7 +1086,7 @@ int F3DStarter::Start(int argc, char** argv)
std::signal(SIGTERM, F3DInternals::SigCallback);
std::signal(SIGINT, F3DInternals::SigCallback);

interactor.start(30, [this]() { this->EventLoop(); });
interactor.start(EVENT_LOOP_TIME, [this]() { this->EventLoop(); });
}
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion library/private/interactor_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class interactor_impl : public interactor
void enableCameraMovement() override;
void disableCameraMovement() override;

bool playInteraction(const std::string& file) override;
bool playInteraction(const std::string& file, double loopTime, std::function<void()> userCallBack) override;
bool recordInteraction(const std::string& file) override;

void start(double loopTime, std::function<void()> userCallBack) override;
Expand Down
2 changes: 1 addition & 1 deletion library/public/interactor.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class F3D_EXPORT interactor
/**
* Play a VTK interaction file.
*/
virtual bool playInteraction(const std::string& file) = 0;
virtual bool playInteraction(const std::string& file, double loopTime = 5, std::function<void()> userCallBack = nullptr) = 0;

/**
* Start interaction and record it all in a VTK interaction file.
Expand Down
114 changes: 74 additions & 40 deletions library/src/interactor_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,71 @@ class interactor_impl::internals
this->Window.render();
}

//----------------------------------------------------------------------------
void StartEventLoop(double loopTime, std::function<void()> userCallBack)
{
// Copy user callback
this->EventLoopUserCallBack = std::move(userCallBack);

// Configure UI delta time
vtkRenderWindow* renWin = this->Window.GetRenderWindow();
vtkF3DRenderer* ren =
vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer());
ren->SetUIDeltaTime(loopTime);

// Configure animation manager
this->AnimationManager->SetInteractorEventLoopTime(loopTime);

// Create the timer
this->EventLoopTimerId = this->VTKInteractor->CreateRepeatingTimer(loopTime);

// Create the callback and add an observer
auto enventLoopDelta = [this]() { this->EventLoop(); };
vtkNew<vtkCallbackCommand> timerCallBack;
timerCallBack->SetCallback(
[](vtkObject*, unsigned long, void* clientData, void*)
{
std::function<void()>* callBackPtr = static_cast<std::function<void()>*>(clientData);
(*callBackPtr)();
});
this->EventLoopObserverId =
this->VTKInteractor->AddObserver(vtkCommand::TimerEvent, timerCallBack);
timerCallBack->SetClientData(&this->EventLoopCallBack);
}

//----------------------------------------------------------------------------
void StopEventLoop()
{
this->VTKInteractor->RemoveObserver(this->EventLoopObserverId);
this->VTKInteractor->DestroyTimer(this->EventLoopTimerId);
this->EventLoopObserverId = -1;
this->EventLoopTimerId = -1;
}

//----------------------------------------------------------------------------
void EventLoop()
{
if (this->EventLoopUserCallBack)
{
this->EventLoopUserCallBack();
}

if (this->AnimationManager->IsPlaying())
{
this->AnimationManager->Tick();
}

if (this->RenderRequested)
{
this->Window.render();
this->RenderRequested = false;
}
else
{
this->Window.RenderUIOnly();
}
}

//----------------------------------------------------------------------------
options& Options;
window_impl& Window;
Expand Down Expand Up @@ -483,8 +548,10 @@ class interactor_impl::internals
int DragDistanceTol = 3; /* px */
int TransitionDuration = 100; /* ms */

std::function<void()> EventLoopUserCallBack = std::function<void()>();
std::function<void()> EventLoopUserCallBack = nullptr;
unsigned long EventLoopTimerId = -1;
int EventLoopObserverId = -1;
std::function<void()> EventLoopCallBack = [this]() { this->EventLoop(); };
std::atomic<bool> RenderRequested = false;
};

Expand Down Expand Up @@ -1060,7 +1127,7 @@ void interactor_impl::disableCameraMovement()
}

//----------------------------------------------------------------------------
bool interactor_impl::playInteraction(const std::string& file)
bool interactor_impl::playInteraction(const std::string& file, double loopTime, std::function<void()> userCallBack)
{
if (!vtksys::SystemTools::FileExists(file))
{
Expand All @@ -1073,12 +1140,13 @@ bool interactor_impl::playInteraction(const std::string& file)
this->Internals->Recorder->Off();
this->Internals->Recorder->Clear();

// this->Internals->StartEventLoop(); Why was it needed ? TODO

this->Internals->StartEventLoop(loopTime, std::move(userCallBack));

std::string cleanFile = vtksys::SystemTools::CollapseFullPath(file);
this->Internals->Recorder->SetFileName(cleanFile.c_str());
this->Internals->Recorder->Play();

this->Internals->StopEventLoop();
}

// Recorder can stop the interactor, make sure it is still running
Expand Down Expand Up @@ -1132,26 +1200,14 @@ bool interactor_impl::recordInteraction(const std::string& file)
//----------------------------------------------------------------------------
void interactor_impl::start(double loopTime, std::function<void()> userCallBack)
{
if (userCallBack)
{
this->Internals->EventLoopUserCallBack = std::move(userCallBack);
}

vtkRenderWindow* renWin = this->Internals->Window.GetRenderWindow();
vtkF3DRenderer* ren =
vtkF3DRenderer::SafeDownCast(renWin->GetRenderers()->GetFirstRenderer());
ren->SetUIDeltaTime(loopTime);

this->Internals->AnimationManager->SetInteractorEventLoopTime(loopTime);
this->Internals->EventLoopTimerId = this->createTimerCallBack(loopTime, [this]() { this->EventLoop(); });
this->Internals->StartEventLoop(loopTime, std::move(userCallBack));
this->Internals->VTKInteractor->Start();
}

//----------------------------------------------------------------------------
void interactor_impl::stop()
{
this->removeTimerCallBack(this->Internals->EventLoopTimerId);
this->Internals->VTKInteractor->RemoveObservers(vtkCommand::TimerEvent);
this->Internals->StopEventLoop();
this->Internals->VTKInteractor->ExitCallback();
}

Expand Down Expand Up @@ -1179,28 +1235,6 @@ void interactor_impl::UpdateRendererAfterInteraction()
this->Internals->Style->UpdateRendererAfterInteraction();
}

//----------------------------------------------------------------------------
void interactor_impl::EventLoop()
{
this->Internals->EventLoopUserCallBack();

if (this->Internals->AnimationManager->IsPlaying())
{
this->Internals->AnimationManager->Tick();
}

if (this->Internals->RenderRequested)
{
this->Internals->Window.render();
this->Internals->RenderRequested = false;
}
else
{
// TODO speed blinking ?
this->Internals->Window.RenderUIOnly();
}
}

//----------------------------------------------------------------------------
interactor_impl::invalid_args_exception::invalid_args_exception(const std::string& what)
: exception(what)
Expand Down

0 comments on commit dda37e1

Please sign in to comment.