Skip to content
Draft
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
2 changes: 2 additions & 0 deletions application/F3DOptionsTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ static inline const std::map<std::string_view, std::string_view> LibOptionsNames
{ "animation-indices", "scene.animation.indices" },
{ "animation-progress", "ui.animation_progress" },
{ "animation-speed-factor", "scene.animation.speed_factor" },
{ "animation-mode", "scene.animation.mode" },
{ "animation-repeat", "scene.animation.repeat" },
{ "anti-aliasing", "render.effect.antialiasing.mode" },
{ "armature", "render.armature.enable" },
{ "axes-grid", "render.axes_grid.enable" },
Expand Down
10 changes: 10 additions & 0 deletions application/testing/tests.interaction.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ if(VTK_VERSION VERSION_GREATER_EQUAL 9.5.20251001)
f3d_test(NAME TestInteractionAnimationProgressBarAxis DATA soldier_animations.mdl ARGS --animation-indices=2 -x --animation-progress=advanced INTERACTION UI) #Hover the last keyframe
endif()

## Animation modes
f3d_test(NAME TestInteractionAnimationModeForward DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-mode=forward --animation-progress=advanced INTERACTION UI)
f3d_test(NAME TestInteractionAnimationModeBackward DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-mode=backward --animation-progress=advanced INTERACTION UI)
f3d_test(NAME TestInteractionAnimationModePingPong DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-mode=pingpong --animation-progress=advanced INTERACTION UI)

# Animation repeats tests
f3d_test(NAME TestInteractionAnimationRepeatOnce DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-repeat=1 --animation-speed-factor=2.0 --animation-progress=advanced INTERACTION UI)
f3d_test(NAME TestInteractionAnimationRepeatTwice DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-repeat=2 --animation-speed-factor=2.0 --animation-progress=advanced INTERACTION UI)
f3d_test(NAME TestInteractionAnimationRepeatInfinity DATA soldier_animations.mdl ARGS --animation-indices=2 --animation-repeat=-1 --animation-speed-factor=2.0 --animation-progress=advanced INTERACTION UI)

## Cheatsheet
f3d_test(NAME TestInteractionCheatsheetWhiteBG DATA cow.vtp ARGS --background-color=1,1,1 INTERACTION UI) #H
f3d_test(NAME TestInteractionCheatsheetBlackBG DATA cow.vtp ARGS --background-color=0,0,0 INTERACTION UI) #H
Expand Down
15 changes: 15 additions & 0 deletions doc/libf3d/03-OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ Set the animation speed factor to slow, speed up or even invert animation.

CLI: `--animation-speed-factor`.

### `scene.animation.mode` (_string_, default: `forward`, enum domain: `forward, backward, pingpong`)

Defines the playback direction and loop behavior:
- `forward`: Plays the animation from start to end (normally).
- `backward`: Plays the animation from end to start (in reverse).
- `pingpong`: Alternating playback direction, moving forward to the end, then backward to the start.

CLI: `--animation-mode`.

### `scene.animation.repeat` (_int_, default: `-1`)

Specifies the number of animation repeat cycles. A value of `-1` means unlimited, while any integer sets a specific number of repeats.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens with 0 btw ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... maybe the animation shouldn't run at all, so we need to add an additional condition in code (we have one tick before stop now)


CLI: `--animation-repeat`.

### `scene.animation.time` (_double_, optional, **on load**)

Set the animation time to load.
Expand Down
11 changes: 11 additions & 0 deletions doc/user/03-OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,17 @@ The default scene always has at most one animation.

Set the animation speed factor to slow, speed up or even invert animation time.

### `--animation-mode=<forward|backward|pingpong>` (_string_, default: `forward`)

Defines the playback direction and loop behavior:
- `forward`: Plays the animation from start to end (normally).
- `backward`: Plays the animation from end to start (in reverse).
- `pingpong`: Alternating playback direction, moving forward to the end, then backward to the start.

### `--animation-repeat=<count>` (_int_, default: `-1`)

Specifies the number of animation repeat cycles. A value of `-1` means unlimited, while any integer sets a specific number of repeats.

### `--animation-time=<time>` (_double_)

Set the animation time to load.
Expand Down
2 changes: 2 additions & 0 deletions doc/user/05-ANIMATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ F3D animation behavior can be fully controlled from the command line using the f
| \-\-animation\-indices | | Select the animations to play. |
| \-\-animation\-indices=-1 | | Play all animations at once (only if supported) |
| \-\-animation\-speed\-factor | Time Unit = Seconds | Adjust time unit. |
| \-\-animation\-mode | forward | Set playback behavior. |
| \-\-animation\-repeat | -1 | Set repeat cycles. |
| \-\-frame\-rate | 60 FPS | Adjust animation (and others components) frame rate. |
| \-\-animation\-time | | Load a specific time value on start. |

Expand Down
12 changes: 12 additions & 0 deletions library/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
"max": "2.0",
"increment": "0.1"
}
},
"repeat": {
"type": "int",
"default_value": "-1"
},
"mode": {
"type": "string",
"default_value": "forward",
"domain": {
"style": "enum",
"enum": ["forward", "backward", "pingpong"]
}
}
},
"camera": {
Expand Down
24 changes: 24 additions & 0 deletions library/private/animationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ class animationManager
*/
void SetCheatSheetConfigured(bool configured);

/**
* Internal setter for Mode.
*/
void SetAnimationMode(const std::string& mode);

/**
* Internal setter for repeats.
*/
void SetAnimationRepeat(int repeat);

options& Options;
window_impl& Window;
vtkF3DMetaImporter* Importer = nullptr;
Expand All @@ -231,6 +241,20 @@ class animationManager
// Dynamic options
bool Autoplay = false;
double SpeedFactor = 1.0;

/**
* Enum listing possible blending modes.
*/
enum class AnimationModeType : unsigned char
{
FORWARD,
BACKWARD,
PINGPONG
};
AnimationModeType AnimationMode = AnimationModeType::FORWARD;
int AnimationMaxRepeat = -1;
int AnimationModeDirection = 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the point of this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, you're right. That's a typo in the comment; it should be replaced with "Enum listing possible animation modes." The purpose of this code is to manage animation modes, repeat counts, and animation direction (depending on the mode).

int AnimationCurrentRepeat = 0;
};
}
}
Expand Down
85 changes: 81 additions & 4 deletions library/src/animationManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,14 @@ void animationManager::ToggleAnimation()
// Initialize time if not already
if (!this->CurrentTimeSet)
{
this->CurrentTime = this->TimeRange[0];
if (this->AnimationMode == AnimationModeType::BACKWARD)
{
this->CurrentTime = TimeRange[1];
}
else
{
this->CurrentTime = TimeRange[0];
}
this->CurrentTimeSet = true;
}
}
Expand All @@ -155,7 +162,8 @@ void animationManager::Tick()
assert(this->DeltaTime > 0);
if (this->Playing)
{
this->CurrentTime += (this->DeltaTime * this->SpeedFactor) * this->AnimationDirection;
this->CurrentTime += (this->DeltaTime * this->SpeedFactor) * this->AnimationDirection *
this->AnimationModeDirection;

// Modulo computation, compute CurrentTime in the time range.
if (this->CurrentTime < this->TimeRange[0] || this->CurrentTime > this->TimeRange[1])
Expand All @@ -165,15 +173,56 @@ void animationManager::Tick()
const double remainder = fmod(val, mod);
return remainder < 0 ? remainder + mod : remainder;
};
this->CurrentTime = this->TimeRange[0] +
modulo(this->CurrentTime - this->TimeRange[0], this->TimeRange[1] - this->TimeRange[0]);

// Switching between animation modes, forward is default
switch (this->AnimationMode)
{
case AnimationModeType::PINGPONG:
this->AnimationModeDirection *= -1;
if (this->CurrentTime < this->TimeRange[0])
{
this->CurrentTime = this->TimeRange[0] + (this->TimeRange[0] - this->CurrentTime);
}
else if (this->CurrentTime > this->TimeRange[1])
{
this->CurrentTime = this->TimeRange[1] - (this->CurrentTime - this->TimeRange[1]);
}
if (this->AnimationMaxRepeat != -1 && AnimationModeDirection == 1)
{
this->AnimationCurrentRepeat++;
}
break;
case AnimationModeType::BACKWARD:
this->AnimationModeDirection = -1;
this->CurrentTime = this->TimeRange[1] -
modulo(this->TimeRange[1] - this->CurrentTime, this->TimeRange[1] - this->TimeRange[0]);
if (this->AnimationMaxRepeat != -1)
{
this->AnimationCurrentRepeat++;
}
break;
default:
this->AnimationModeDirection = 1;
this->CurrentTime = this->TimeRange[0] +
modulo(this->CurrentTime - this->TimeRange[0], this->TimeRange[1] - this->TimeRange[0]);
if (this->AnimationMaxRepeat != -1)
{
this->AnimationCurrentRepeat++;
}
break;
}
}

if (this->LoadAtTime(this->CurrentTime))
{
this->Window.render();
}
}
if (this->AnimationMaxRepeat != -1 && this->AnimationCurrentRepeat == this->AnimationMaxRepeat)
{
this->Playing = false;
this->AnimationCurrentRepeat = 0;
}
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -692,10 +741,38 @@ void animationManager::SetAnimationDirection(int direction)
this->AnimationDirection = direction;
}

//----------------------------------------------------------------------------
void animationManager::SetAnimationMode(const std::string& mode)
{
if (mode == "backward")
{
this->AnimationMode = AnimationModeType::BACKWARD;
this->AnimationModeDirection = -1;
}
else if (mode == "pingpong")
{
this->AnimationMode = AnimationModeType::PINGPONG;
}
else
{
this->AnimationMode = AnimationModeType::FORWARD;
this->AnimationModeDirection = 1;
}
}

//----------------------------------------------------------------------------
void animationManager::SetAnimationRepeat(int repeat)
{
assert(repeat >= -1);
this->AnimationMaxRepeat = repeat;
}

//----------------------------------------------------------------------------
void animationManager::UpdateDynamicOptions()
{
this->SetAutoplay(this->Options.scene.animation.autoplay);
this->SetSpeedFactor(this->Options.scene.animation.speed_factor);
this->SetAnimationMode(this->Options.scene.animation.mode);
this->SetAnimationRepeat(this->Options.scene.animation.repeat);
}
}
10 changes: 10 additions & 0 deletions resources/cli-options.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,16 @@
"helpText": "Set animation time to load",
"valueHelper": "<time>"
},
{
"longName": "animation-mode",
"helpText": "Set the animation mode (forward, backward, pingpong...)",
"valueHelper": "<string>"
},
{
"longName": "animation-repeat",
"helpText": "Set the animation repeat count",
"valueHelper": "<int>"
},
{
"longName": "font-file",
"helpText": "Path to a FreeType compatible font file",
Expand Down
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionAnimationModeBackward.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionAnimationModeForward.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionAnimationModePingPong.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionAnimationRepeatOnce.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionAnimationRepeatTwice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions testing/recordings/TestInteractionAnimationModeBackward.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# StreamVersion 1.2
# Start animation mode backward
KeyPressEvent 989 6 0 32 1 space 0
CharEvent 989 6 0 32 1 space 0
KeyReleaseEvent 989 6 0 32 1 space 0

# Time for moving
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0
TimerEvent 989 6 0 32 1 space 0

# Stop animation mode backward
KeyPressEvent 989 6 0 32 1 space 0
CharEvent 989 6 0 32 1 space 0
KeyReleaseEvent 989 6 0 32 1 space 0
31 changes: 31 additions & 0 deletions testing/recordings/TestInteractionAnimationModeForward.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# StreamVersion 1.2
# Start animation mode forward
KeyPressEvent 8 16 0 32 1 space 0
CharEvent 8 16 0 32 1 space 0
KeyReleaseEvent 8 16 0 32 1 space 0

# Time for moving
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0
TimerEvent 8 16 0 32 1 space 0

# Stop animation mode forward
KeyPressEvent 8 16 0 32 1 space 0
CharEvent 8 16 0 32 1 space 0
KeyReleaseEvent 8 16 0 32 1 space 0
Loading
Loading