mirror of
https://github.com/m5stack/StackChan.git
synced 2026-04-27 19:12:40 +00:00
5001b7081b
* add firmware source code
99 lines
2.3 KiB
C++
99 lines
2.3 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
#include "animation.h"
|
|
#include "../stackchan.h"
|
|
#include <hal/hal.h>
|
|
|
|
using namespace stackchan::animation;
|
|
|
|
void Keyframe::apply()
|
|
{
|
|
auto& stackchan = GetStackChan();
|
|
auto& avatar = stackchan.avatar();
|
|
auto& motion = stackchan.motion();
|
|
|
|
auto apply_feature = [&](const FeatureKeyframe& kf, avatar::Feature& feat) {
|
|
feat.setPosition(kf.position);
|
|
feat.setRotation(kf.rotation);
|
|
feat.setWeight(kf.weight);
|
|
};
|
|
apply_feature(leftEye, avatar.leftEye());
|
|
apply_feature(rightEye, avatar.rightEye());
|
|
apply_feature(mouth, avatar.mouth());
|
|
|
|
auto apply_servo = [&](const ServoKeyframe& kf, motion::Servo& servo) { servo.moveWithSpeed(kf.angle, kf.speed); };
|
|
apply_servo(yawServo, motion.yawServo());
|
|
apply_servo(pitchServo, motion.pitchServo());
|
|
}
|
|
|
|
void Timeline::start()
|
|
{
|
|
if (_keyframe_sequence.empty()) {
|
|
_status = Status::Finished;
|
|
return;
|
|
}
|
|
_current_index = 0;
|
|
_status = Status::Playing;
|
|
_start_time = GetHAL().millis();
|
|
_apply_current_keyframe();
|
|
}
|
|
|
|
void Timeline::stop()
|
|
{
|
|
_status = Status::Idle;
|
|
_current_index = 0;
|
|
}
|
|
|
|
void Timeline::pause()
|
|
{
|
|
if (_status == Status::Playing) {
|
|
_status = Status::Paused;
|
|
_elapsed_time = GetHAL().millis() - _start_time;
|
|
}
|
|
}
|
|
|
|
void Timeline::resume()
|
|
{
|
|
if (_status == Status::Paused) {
|
|
_status = Status::Playing;
|
|
_start_time = GetHAL().millis() - _elapsed_time;
|
|
}
|
|
}
|
|
|
|
void Timeline::update()
|
|
{
|
|
if (_status != Status::Playing) {
|
|
return;
|
|
}
|
|
|
|
if (_keyframe_sequence.empty()) {
|
|
_status = Status::Finished;
|
|
return;
|
|
}
|
|
|
|
uint32_t now = GetHAL().millis();
|
|
if (now - _start_time >= _keyframe_sequence[_current_index].durationMs) {
|
|
_current_index++;
|
|
if (_current_index >= _keyframe_sequence.size()) {
|
|
if (_loop) {
|
|
_current_index = 0;
|
|
} else {
|
|
_status = Status::Finished;
|
|
return;
|
|
}
|
|
}
|
|
_start_time = now;
|
|
_apply_current_keyframe();
|
|
}
|
|
}
|
|
|
|
void Timeline::_apply_current_keyframe()
|
|
{
|
|
if (_current_index < _keyframe_sequence.size()) {
|
|
_keyframe_sequence[_current_index].apply();
|
|
}
|
|
}
|