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

Implement proper event loop in libf3d #1770

Merged
merged 31 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
aea757b
Add a simple event loop
mwestphal Dec 11, 2024
e412623
Add animation to eventLoop
mwestphal Dec 8, 2024
b89455d
ui event loop
mwestphal Dec 11, 2024
9f6b417
UI: Add proper delta time configuration
mwestphal Dec 12, 2024
bb26d12
EventLoop: Support playing interactions
mwestphal Dec 12, 2024
0bbe6bd
Add a test for anim frame rate
mwestphal Dec 12, 2024
3e2e049
interactor: Remove timer API
mwestphal Dec 12, 2024
180ab22
codespell
mwestphal Dec 12, 2024
1bf2748
clg
mwestphal Dec 12, 2024
2bb7952
fix framerate test
mwestphal Dec 12, 2024
f9d541a
fixup windows
mwestphal Dec 12, 2024
eabf2df
update examples
mwestphal Dec 12, 2024
3a3cd43
fixup winsdows
mwestphal Dec 12, 2024
c7177fd
fizup old vtk
mwestphal Dec 12, 2024
63cdefa
doc
mwestphal Dec 12, 2024
b187bdc
Rework animation logic and updates tests
mwestphal Dec 13, 2024
187b35f
remove framerate option
mwestphal Dec 13, 2024
3439ab1
fixup
mwestphal Dec 14, 2024
2acf77e
clfi
mwestphal Dec 14, 2024
468dd09
test again 9.2.5
mwestphal Dec 14, 2024
eb1d287
finishing up
mwestphal Dec 15, 2024
9096c5e
clfi
mwestphal Dec 15, 2024
d085c33
cleanups doc
mwestphal Dec 15, 2024
12e8cd0
Updating python bindings and testing
mwestphal Dec 15, 2024
5787fbd
fixup loop
mwestphal Dec 15, 2024
fbcdbbe
added bindings clf
mwestphal Dec 15, 2024
24f84cc
Add better testing
mwestphal Dec 15, 2024
fe38947
Update library/src/animationManager.cxx
mwestphal Dec 16, 2024
cd4c52e
fmod
mwestphal Dec 16, 2024
e9dfa97
frame rate in double
mwestphal Dec 16, 2024
dbc556c
Update doc/libf3d/CLASSES.md
mwestphal Dec 16, 2024
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
4 changes: 2 additions & 2 deletions application/F3DOptionsTools.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{ "rendering-backend", "", "Backend to use when rendering (auto|glx|wgl|egl|osmesa)", "<string>", "" },
{ "max-size", "", "Maximum size in Mib of a file to load, negative value means unlimited", "<size in Mib>", "" },
{ "watch", "", "Watch current file and automatically reload it whenever it is modified on disk", "<bool>", "1" },
{ "frame-rate", "", "Frame rate used to refresh animation and other repeated tasks (watch, UI). Does not impact rendering frame rate.", "<fps>", "" },
{ "load-plugins", "", "List of plugins to load separated with a comma", "<paths or names>", "" },
{ "scan-plugins", "", "Scan standard directories for plugins and display available plugins (result can be incomplete)", "", "" },
{ "screenshot-filename", "", "Screenshot filename", "<filename>", "" } } },
Expand All @@ -94,7 +95,6 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{ "animation-index", "", "Select animation to show", "<index>", "" },
{ "animation-speed-factor", "", "Set animation speed factor", "<factor>", "" },
{ "animation-time", "", "Set animation time to load", "<time>", "" },
{"animation-frame-rate", "", "Set animation frame rate when playing animation interactively", "<frame rate>", ""},
{"font-file", "", "Path to a FreeType compatible font file", "<file_path>", ""},
{"command-script", "", "Path to a script file containing commands to execute", "<file_path>", "" } } },
{ "Material",
Expand Down Expand Up @@ -122,7 +122,7 @@ static inline const std::array<CLIGroup, 8> CLIOptions = {{
{ {"bg-color", "", "Background color", "<R,G,B>", ""},
{"resolution", "", "Window resolution", "<width,height>", ""},
{"position", "", "Window position", "<x,y>", ""},
{"fps", "z", "Display frame per second", "<bool>", "1"},
{"fps", "z", "Display rendering frame per second", "<bool>", "1"},
Meakk marked this conversation as resolved.
Show resolved Hide resolved
{"filename", "n", "Display filename", "<bool>", "1"},
{"metadata", "m", "Display file metadata", "<bool>", "1"},
{"blur-background", "u", "Blur background", "<bool>", "1" },
Expand Down
2 changes: 1 addition & 1 deletion application/F3DOptionsTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ static inline const OptionsDict DefaultAppOptions = {
{ "interaction-test-record", "" },
{ "interaction-test-play", "" },
{ "command-script", "" },
{ "frame-rate", "30" },
};

/**
Expand All @@ -78,7 +79,6 @@ static inline const std::map<std::string_view, std::string_view> LibOptionsNames
{ "animation-autoplay", "scene.animation.autoplay" },
{ "animation-index", "scene.animation.index" },
{ "animation-speed-factor", "scene.animation.speed_factor" },
{ "animation-frame-rate", "scene.animation.frame_rate" },
{ "font-file", "ui.font_file" },
{ "point-sprites", "model.point_sprites.enable" },
{ "point-sprites-type", "model.point_sprites.type" },
Expand Down
24 changes: 6 additions & 18 deletions application/F3DStarter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class F3DStarter::F3DInternals
double MaxSize;
std::optional<double> AnimationTime;
bool Watch;
int FrameRate;
mwestphal marked this conversation as resolved.
Show resolved Hide resolved
std::vector<std::string> Plugins;
std::string ScreenshotFilename;
std::string VerboseLevel;
Expand Down Expand Up @@ -546,6 +547,7 @@ class F3DStarter::F3DInternals
{
this->AppOptions.AnimationTime = f3d::options::parse<double>(appOptions.at("animation-time"));
}
this->AppOptions.FrameRate = f3d::options::parse<int>(appOptions.at("frame-rate"));
this->AppOptions.Watch = f3d::options::parse<bool>(appOptions.at("watch"));
this->AppOptions.Plugins = { f3d::options::parse<std::vector<std::string>>(
appOptions.at("load-plugins")) };
Expand Down Expand Up @@ -673,7 +675,6 @@ class F3DStarter::F3DInternals
interactor.addBinding({ mod_t::CTRL, "O" }, "open_file_dialog", "Others", std::bind(docString, "Open File Dialog"));
interactor.addBinding({ mod_t::CTRL, "F12" }, "take_minimal_screenshot", "Others", std::bind(docString, "Take a minimal screenshot"));


// This replace an existing default binding command in the libf3d
interactor.removeBinding({ mod_t::NONE, "Drop" });
interactor.addBinding({ mod_t::NONE, "Drop" }, "add_files_or_set_hdri", "Others", std::bind(docString, "Load dropped files, folder or HDRI"));
Expand Down Expand Up @@ -762,7 +763,6 @@ class F3DStarter::F3DInternals
std::mutex LoadedFilesMutex;

// Event loop atomics
std::atomic<bool> RenderRequested = false;
std::atomic<bool> ReloadFileRequested = false;
};

Expand Down Expand Up @@ -842,6 +842,7 @@ int F3DStarter::Start(int argc, char** argv)

f3d::log::debug("========== Configuring engine ==========");

double deltaTime = 1.0 / this->Internals->AppOptions.FrameRate;
const std::string& reference = this->Internals->AppOptions.Reference;
const std::string& output = this->Internals->AppOptions.Output;

Expand Down Expand Up @@ -929,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, deltaTime))
{
return EXIT_FAILURE;
}
Expand Down Expand Up @@ -1079,14 +1080,13 @@ int F3DStarter::Start(int argc, char** argv)
{
// Create the event loop repeating timer
window.render();
interactor.createTimerCallBack(30, [this]() { this->EventLoop(); });

// gracefully exits if SIGTERM or SIGINT is send to F3D
GlobalInteractor = &interactor;
std::signal(SIGTERM, F3DInternals::SigCallback);
std::signal(SIGINT, F3DInternals::SigCallback);

interactor.start();
interactor.start(deltaTime, [this]() { this->EventLoop(); });
}
#endif
}
Expand Down Expand Up @@ -1342,13 +1342,6 @@ void F3DStarter::LoadFileGroup(
options.ui.filename_info = filenameInfo;
}

//----------------------------------------------------------------------------
void F3DStarter::RequestRender()
{
// Render will be called by the next event loop
this->Internals->RenderRequested = true;
}

//----------------------------------------------------------------------------
void F3DStarter::Render()
{
Expand Down Expand Up @@ -1511,7 +1504,7 @@ bool F3DStarter::LoadRelativeFileGroup(int index, bool restoreCamera, bool force
this->LoadFileGroup(index, true, forceClear);
}

this->RequestRender();
this->Internals->Engine->getInteractor().requestRender();

return true;
}
Expand All @@ -1524,11 +1517,6 @@ void F3DStarter::EventLoop()
this->LoadRelativeFileGroup(0, true, true);
this->Internals->ReloadFileRequested = false;
}
if (this->Internals->RenderRequested)
{
this->Render();
this->Internals->RenderRequested = false;
}
}

//----------------------------------------------------------------------------
Expand Down
11 changes: 5 additions & 6 deletions application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,11 @@ f3d_test(NAME TestVerboseAnimation DATA InterpolationTest.glb ARGS --verbose NO_
f3d_test(NAME TestVerboseAnimationIndexError DATA InterpolationTest.glb ARGS --animation-index=48 NO_BASELINE REGEXP "Specified animation index is greater than the highest possible animation index, enabling the first animation.")

# Test interactive animation and speed factor
f3d_test(NAME TestInteractionAnimationFast DATA InterpolationTest.glb ARGS --animation-speed-factor=1000 --animation-index=-1 INTERACTION NO_BASELINE)#Space;Space;
f3d_test(NAME TestInteractionAnimationSlow DATA InterpolationTest.glb ARGS --animation-speed-factor=0.01 --animation-index=-1 INTERACTION)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimationCameraMovement DATA CameraAnimated.glb ARGS --camera-index=0 --animation-speed-factor=1000 --animation-progress INTERACTION)#Space;MouseMovement;Space;

# Framerate test is a smoke test as event playing seems to break VTK timers
f3d_test(NAME TestInteractionAnimationFrameRate DATA InterpolationTest.glb ARGS --animation-frame-rate=2 --animation-index=-1 INTERACTION NO_BASELINE)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimation DATA f3d.glb ARGS --animation-progress INTERACTION)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimationFast DATA f3d.glb ARGS --animation-progress --animation-speed-factor=1.5 INTERACTION)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimationSlow DATA f3d.glb ARGS --animation-progress --animation-speed-factor=0.5 INTERACTION)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimationFrameRate DATA f3d.glb ARGS --animation-progress --frame-rate=1 INTERACTION)#Space;Wait;Space;
f3d_test(NAME TestInteractionAnimationCameraMovement DATA CameraAnimated.glb ARGS --camera-index=0 --animation-progress INTERACTION)#Space;MouseMovement;Space;

# A verbose test that needs animation index support
f3d_test(NAME TestVerboseAnimationWrongAnimationTimeHigh DATA BoxAnimated.gltf ARGS --animation-time=10 --verbose REGEXP "Animation time 10 is outside of range \\[0, 3\\.70833\\], using 3\\.70833" NO_BASELINE)
Expand Down
1 change: 1 addition & 0 deletions doc/libf3d/CLASSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ This API also lets you control the content of the cheatsheet.
Use `log::setVerboseLevel(log::VerboseLevel::DEBUG)` to print debug information on interaction and command use.

Of course, you can use `start` and `stop` to control the interactor behavior.
`start` let you specify time for the event loop and a std::function to execute at each loop.
mwestphal marked this conversation as resolved.
Show resolved Hide resolved

## Camera class

Expand Down
1 change: 0 additions & 1 deletion doc/libf3d/OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ scene.animation.autoplay|bool<br>false<br>load|Automatically start animation.|\-
scene.animation.index|int<br>0<br>load|Select the animation to load.<br>Any negative value means all animations (glTF only).<br>The default scene always has at most one animation.|\-\-animation-index
scene.animation.speed_factor|double<br>1<br>render|Set the animation speed factor to slow, speed up or even invert animation.|\-\-animation-speed-factor
scene.animation.time|double<br>optional<br>load|Set the animation time to load.|\-\-animation-time
scene.animation.frame_rate|double<br>60<br>render|Set the animation frame rate used to play the animation interactively.|\-\-animation-frame-rate
scene.camera.index|int<br>optional<br>load|Select the scene camera to use when available in the file.<br>The default scene always uses automatic camera.|\-\-camera-index
scene.up_direction|string<br>+Y<br>load|Define the Up direction. It impacts the grid, the axis, the HDRI and the camera.|\-\-up
scene.camera.orthographic|bool<br>optional<br>load|Set to true to force orthographic projection. Model specified by default, which is false if not specified.|\-\-camera\-orthographic
Expand Down
2 changes: 1 addition & 1 deletion doc/user/CONFIGURATION_FILE.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ The following options <b> cannot </b> be set via config file:
`help`, `version`, `readers-list`, `config`, `dry-run` and `input`.

The following options <b>are only taken on the first load</b>:
`no-render`, `output`, `position`, `resolution` and all testing options.
`no-render`, `output`, `position`, `resolution`, `frame-rate` and all testing options.

Boolean options that have been turned on in the configuration file can be turned
off on the command line if needed, eg: `--point-sprites=false`.
Expand Down
4 changes: 2 additions & 2 deletions doc/user/OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Options|Default|Description
\-\-no-render||Do not render anything and quit just after loading the first file, use with \-\-verbose to recover information about a file.
\-\-max-size=\<size in MiB\>|-1|Prevent F3D to load a file bigger than the provided size in Mib, negative value means unlimited, useful for thumbnails.
\-\-watch||Watch current file and automatically reload it whenever it is modified on disk.
\-\-frame-rate=\<fps\>|30|Frame rate used to refresh animation and other repeated tasks (watch, UI). Does not impact rendering frame rate.
\-\-load-plugins=\<paths or names\>||List of plugins to load separated with a comma. Official plugins are `alembic`, `assimp`, `draco`, `exodus`, `occt`, `usd`, `vdb`. See [plugins](PLUGINS.md) for more info.
\-\-scan-plugins||Scan standard directories for plugins and display their names, results may be incomplete. See [plugins](PLUGINS.md) for more info.
\-\-screenshot-filename=\<png file\>|`{app}/{model}_{n}.png`|Filename to save [screenshots](INTERACTIONS.md#taking-screenshots) to. Can use [template variables](#filename-templating).
Expand All @@ -45,7 +46,6 @@ Options|Default|Description
\-\-animation-index=\<idx\>|0|Select the animation to show.<br>Any negative value means all animations (glTF only).<br>The default scene always has at most one animation.
\-\-animation-speed-factor=\<factor\>|1|Set the animation speed factor to slow, speed up or even invert animation time.
\-\-animation-time=\<factor\>||Set the animation time to load.
\-\-animation-frame-rate=\<factor\>|60|Set the animation frame rate used when playing animation interactively.
\-\-font-file=\<font file\>||Use the provided FreeType compatible font file to display text.<br>Can be useful to display non-ASCII filenames.
\-\-command-script=\<command script\>||Provide a script file containing a list of commands to be executed sequentially.<br>Allows automation of multiple commands or pre-defined tasks.

Expand Down Expand Up @@ -78,7 +78,7 @@ Options|Default|Description
\-\-bg-color=\<R,G,B\>|0.2, 0.2, 0.2|Set the window *background color*.<br>Ignored if *hdri* is set.
\-\-resolution=\<width,height\>|1000, 600|Set the *window resolution*.
\-\-position=\<x,y\>||Set the *window position* (top left corner) , in pixels, starting from the top left of your screens.
-z, \-\-fps||Display a *frame per second counter*.
-z, \-\-fps||Display a rendering *frame per second counter*.
-n, \-\-filename||Display the *name of the file* on top of the window.
-m, \-\-metadata||Display the *metadata*.
\-\-hdri-skybox||Show the HDRI as a skybox. Overrides \-\-bg-color and \-\-no-background.
Expand Down
8 changes: 4 additions & 4 deletions examples/libf3d/cpp/multi-files/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ int main(int argc, char** argv)
f3d::window& win = eng.getWindow();
win.render();

// Create a timer to stop interaction after one second
// Start interaction and stop it after one second
f3d::interactor& inter = eng.getInteractor();
inter.createTimerCallBack(1000, [&inter]() { inter.stop(); });
inter.start(1, [&inter]() { inter.stop(); });
Meakk marked this conversation as resolved.
Show resolved Hide resolved

// Start interaction
inter.start();
// Actual call would look like this
// inter.start();

return EXIT_SUCCESS;
}
8 changes: 4 additions & 4 deletions examples/libf3d/cpp/render-interact/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ int main(int argc, char** argv)
f3d::window& win = eng.getWindow();
win.render();

// Create a timer to stop interaction after one second
// Start interaction and stop it after one second
f3d::interactor& inter = eng.getInteractor();
inter.createTimerCallBack(1000, [&inter]() { inter.stop(); });
inter.start(1, [&inter]() { inter.stop(); });

// Start interaction
inter.start();
// Actual call would look like this
// inter.start();

return EXIT_SUCCESS;
}
8 changes: 4 additions & 4 deletions examples/libf3d/cpp/use-options-string/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ int main(int argc, char** argv)
f3d::window& win = eng.getWindow();
win.render();

// Create a timer to stop interaction after one second
// Start interaction and stop it after one second
f3d::interactor& inter = eng.getInteractor();
inter.createTimerCallBack(1000, [&inter]() { inter.stop(); });
inter.start(1, [&inter]() { inter.stop(); });

// Start interaction
inter.start();
// Actual call would look like this
// inter.start();

return EXIT_SUCCESS;
}
8 changes: 4 additions & 4 deletions examples/libf3d/cpp/use-options-struct/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ int main(int argc, char** argv)
f3d::window& win = eng.getWindow();
win.render();

// Create a timer to stop interaction after one second
// Start interaction and stop it after one second
f3d::interactor& inter = eng.getInteractor();
inter.createTimerCallBack(1000, [&inter]() { inter.stop(); });
inter.start(1, [&inter]() { inter.stop(); });

// Start interaction
inter.start();
// Actual call would look like this
// inter.start();

return EXIT_SUCCESS;
}
8 changes: 4 additions & 4 deletions examples/libf3d/cpp/use-options-variant/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ int main(int argc, char** argv)
f3d::window& win = eng.getWindow();
win.render();

// Create a timer to stop interaction after one second
// Start interaction and stop it after one second
f3d::interactor& inter = eng.getInteractor();
inter.createTimerCallBack(1000, [&inter]() { inter.stop(); });
inter.start(1, [&inter]() { inter.stop(); });

// Start interaction
inter.start();
// Actual call would look like this
// inter.start();

return EXIT_SUCCESS;
}
4 changes: 0 additions & 4 deletions library/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
"speed_factor": {
"type": "ratio",
"default_value": "1.0"
},
"frame_rate": {
"type": "double",
"default_value": "60.0"
}
},
"camera": {
Expand Down
18 changes: 12 additions & 6 deletions library/private/animationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ class animationManager
return Playing;
}

/**
* Set the animation in delta time in seconds
*/
void SetDeltaTime(double deltaTime);

/**
* Advance animationTime of DeltaTime and call loadAtTime accordingly
* Do nothing if IsPlaying is false
*/
void Tick();

/**
* Load animation at provided time value
*/
Expand All @@ -101,11 +112,6 @@ class animationManager
std::pair<double, double> GetTimeRange();

private:
/**
* Called by an internal timer to advance one animation tick
*/
void Tick();

const options& Options;
window_impl& Window;
vtkImporter* Importer = nullptr;
Expand All @@ -114,8 +120,8 @@ class animationManager
double TimeRange[2] = { 0.0, 0.0 };
bool Playing = false;
bool HasAnimation = false;
unsigned long CallBackId = 0;
double CurrentTime = 0;
double DeltaTime = 0;
bool CurrentTimeSet = false;
int AnimationIndex = 0;
int AvailAnimations = -1;
Expand Down
15 changes: 10 additions & 5 deletions library/private/interactor_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ class interactor_impl : public interactor
std::pair<std::string, std::string> getBindingDocumentation(
const interaction_bind_t& bind) const override;

unsigned long createTimerCallBack(double time, std::function<void()> callBack) override;
void removeTimerCallBack(unsigned long id) override;

void toggleAnimation() override;
void startAnimation() override;
void stopAnimation() override;
Expand All @@ -67,11 +64,13 @@ 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 deltaTime, std::function<void()> userCallBack) override;
bool recordInteraction(const std::string& file) override;

void start() override;
void start(double deltaTime, std::function<void()> userCallBack) override;
void stop() override;
void requestRender() override;
///@}

/**
Expand Down Expand Up @@ -101,6 +100,12 @@ class interactor_impl : public interactor
*/
void UpdateRendererAfterInteraction();

/**
* Event loop being called automatically once the interactor is started
* First call the EventLoopUserCallBack, then call render if requested.
*/
void EventLoop();

/**
* An exception that can be thrown by certain command callbacks
* when the arguments of the callback are incorrect and expected
Expand Down
6 changes: 6 additions & 0 deletions library/private/window_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ class window_impl : public window
*/
void SetInteractor(interactor_impl* interactor);

/**
* Trigger a render only of the UI
* Does nothing if F3D_MODULE_UI is OFF
*/
void RenderUIOnly();

private:
class internals;
std::unique_ptr<internals> Internals;
Expand Down
Loading
Loading