add firmware source code (#4)

* add firmware source code
This commit is contained in:
Forairaaaaa
2026-01-08 09:18:20 +08:00
committed by GitHub
parent 4f1373e449
commit 5001b7081b
164 changed files with 81663 additions and 1 deletions
@@ -0,0 +1,98 @@
/*
* 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();
}
}
@@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
#include <cstdint>
#include <vector>
namespace stackchan::animation {
/**
* @brief
*
*/
struct FeatureKeyframe {
uitk::Vector2i position;
int rotation;
int weight;
FeatureKeyframe(int x = 0, int y = 0, int rotation = 0, int weight = 0)
: position(x, y), rotation(rotation), weight(weight)
{
}
};
/**
* @brief
*
*/
struct ServoKeyframe {
int angle;
int speed;
ServoKeyframe(int angle = 0, int speed = 0) : angle(angle), speed(speed)
{
}
};
/**
* @brief
*
*/
struct Keyframe {
FeatureKeyframe leftEye;
FeatureKeyframe rightEye;
FeatureKeyframe mouth;
ServoKeyframe yawServo;
ServoKeyframe pitchServo;
uint32_t durationMs = 0;
Keyframe()
{
}
Keyframe(const FeatureKeyframe& leftEye, const FeatureKeyframe& rightEye, const FeatureKeyframe& mouth,
const ServoKeyframe& yawServo, const ServoKeyframe& pitchServo, uint32_t durationMs = 0)
: leftEye(leftEye),
rightEye(rightEye),
mouth(mouth),
yawServo(yawServo),
pitchServo(pitchServo),
durationMs(durationMs)
{
}
void apply();
inline uint32_t getDelayMs() const
{
return durationMs;
}
};
using KeyframeSequence = std::vector<Keyframe>;
/**
* @brief
*
*/
class Timeline {
public:
enum class Status {
Idle,
Playing,
Paused,
Finished,
};
Timeline(KeyframeSequence keyframeSequence, bool loop = false)
: _keyframe_sequence(std::move(keyframeSequence)), _loop(loop)
{
}
void start();
void stop();
void pause();
void resume();
void update();
Status getStatus() const
{
return _status;
}
bool isFinished() const
{
return _status == Status::Finished;
}
void setLoop(bool loop)
{
_loop = loop;
}
private:
void _apply_current_keyframe();
KeyframeSequence _keyframe_sequence;
bool _loop;
size_t _current_index = 0;
Status _status = Status::Idle;
uint32_t _start_time = 0;
uint32_t _elapsed_time = 0;
};
} // namespace stackchan::animation
+8
View File
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "skins/default/default.h"
#include "decorators/decorators.h"
@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "elements/key_elements.h"
#include "decorator.h"
#include <memory>
namespace stackchan::avatar {
/**
* @brief Avatar base class
*
*/
class Avatar {
public:
/**
* @brief Update avatar, trigger all elements, decorators and modifiers to update
*
*/
virtual void update()
{
_key_elements.forEach([](Element* element) {
// Update all elements
element->_update();
});
_decorator_pool.forEach([this](Decorator* decorator, int id) {
// Update all decorators
decorator->_update();
});
// Cleanup pools
_decorator_pool.cleanup();
}
const KeyElements_t& getKeyElements()
{
return _key_elements;
}
virtual void setEmotion(const Emotion& emotion)
{
_emotion = emotion;
_key_elements.forEach([&emotion](Element* element) {
// Set for all elements
element->setEmotion(emotion);
});
_decorator_pool.forEach([&emotion](Decorator* decorator, int id) {
// Set for all decorators
decorator->setEmotion(emotion);
});
}
Emotion getEmotion() const
{
return _emotion;
}
Feature& leftEye()
{
return *getKeyElements().leftEye;
}
Feature& rightEye()
{
return *getKeyElements().rightEye;
}
Feature& mouth()
{
return *getKeyElements().mouth;
}
void setSpeech(std::string_view text)
{
if (getKeyElements().speechBubble) {
getKeyElements().speechBubble->setSpeech(text);
}
}
void clearSpeech()
{
if (getKeyElements().speechBubble) {
getKeyElements().speechBubble->clearSpeech();
}
}
void setSpeechTextFont(void* font)
{
if (getKeyElements().speechBubble) {
getKeyElements().speechBubble->setTextFont(font);
}
}
/* ---------------------------- Decorator helpers --------------------------- */
int addDecorator(std::unique_ptr<Decorator> decorator)
{
return _decorator_pool.create(std::move(decorator));
}
bool removeDecorator(int id)
{
return _decorator_pool.destroy(id);
}
void clearDecorators()
{
_decorator_pool.clear();
}
protected:
Avatar() = default;
Emotion _emotion = Emotion::Neutral;
KeyElements_t _key_elements;
ObjectPool<Decorator> _decorator_pool;
};
} // namespace stackchan::avatar
@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "elements/element.h"
#include "../../utils/object_pool.h"
namespace stackchan::avatar {
/**
* @brief Decorator base class
*
*/
class Decorator : public Poolable, public Element {
public:
};
} // namespace stackchan::avatar
@@ -0,0 +1,106 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "emotion.h"
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
namespace stackchan::avatar {
/**
* @brief Renderable element interface
*
*/
class Element {
public:
virtual ~Element() = default;
/**
* @brief (-100~100, -100~100)
*
* @param position
*/
virtual void setPosition(const uitk::Vector2i& position)
{
_position = position;
_position.clamp({-100, -100}, {100, 100});
}
virtual uitk::Vector2i getPosition()
{
return _position;
}
/**
* @brief 0~3600
*
* @param rotation
*/
virtual void setRotation(int rotation)
{
_rotation = uitk::clamp(rotation, 0, 3600);
}
virtual int getRotation()
{
return _rotation;
}
/**
* @brief
*
* @param emotion
*/
virtual void setEmotion(const Emotion& emotion)
{
}
virtual Emotion getEmotion() const
{
return Emotion::Neutral;
}
/**
* @brief Ignore emotion update
*
* @param ignore
*/
virtual void setIgnoreEmotion(bool ignore)
{
_ignore_emotion = ignore;
}
virtual bool getIgnoreEmotion()
{
return _ignore_emotion;
}
/**
* @brief true: visible, false: invisible
*
* @param visible
*/
virtual void setVisible(bool visible)
{
_visible = visible;
}
virtual bool getVisible()
{
return _visible;
}
/**
* @brief Invoked in every update loop
*
*/
virtual void _update()
{
}
protected:
uitk::Vector2i _position;
int _rotation = 0;
bool _visible = true;
bool _ignore_emotion = false;
};
} // namespace stackchan::avatar
@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
namespace stackchan::avatar {
enum class Emotion {
Neutral = 0,
Happy,
Angry,
Sad,
Doubt,
Sleepy,
};
} // namespace stackchan::avatar
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "element.h"
namespace stackchan::avatar {
/**
* @brief Feature base class
*
*/
class Feature : public Element {
public:
/**
* @brief A normalized value representing the intensity of eyes, mouth, or other
*
* @param weight 0~100
*/
virtual void setWeight(int weight)
{
_weight = uitk::clamp(weight, 0, 100);
}
virtual int getWeight()
{
return _weight;
}
/**
* @brief A normalized value representing the size of eyes, 0 for normal size
*
* @param size -100~100
*/
virtual void setSize(int size)
{
_size = uitk::clamp(size, -100, 100);
}
virtual int getSize()
{
return _size;
}
protected:
int _weight = 0;
int _size = 0;
};
} // namespace stackchan::avatar
@@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "element.h"
#include "feature.h"
#include "speech_bubble.h"
#include <functional>
#include <memory>
namespace stackchan::avatar {
/**
* @brief Key elements of avatar
*
*/
struct KeyElements_t {
std::unique_ptr<Feature> leftEye;
std::unique_ptr<Feature> rightEye;
std::unique_ptr<Feature> mouth;
std::unique_ptr<SpeechBubble> speechBubble;
void forEach(std::function<void(Element*)> callback)
{
if (leftEye) {
callback(leftEye.get());
}
if (rightEye) {
callback(rightEye.get());
}
if (mouth) {
callback(mouth.get());
}
if (speechBubble) {
callback(speechBubble.get());
}
}
};
} // namespace stackchan::avatar
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "element.h"
#include <string_view>
#include <string>
namespace stackchan::avatar {
/**
* @brief Speech bubble base class
*
*/
class SpeechBubble : public Element {
public:
virtual ~SpeechBubble() = default;
virtual void setSpeech(std::string_view text)
{
}
virtual void clearSpeech()
{
}
virtual void setTextFont(void* font)
{
}
};
} // namespace stackchan::avatar
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "decorators.h"
#include <vector>
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const Vector2i _angry_default_position = Vector2i(108, -70);
static const lv_color_t _angry_default_color = lv_color_hex(0xFDB034);
static const std::vector<int> _angry_rotation_frames = {150, 200};
LV_IMAGE_DECLARE(decorator_angry);
AngryDecorator::AngryDecorator(lv_obj_t* parent, uint32_t destroyAfterMs, uint32_t animationIntervalMs)
{
_angry = std::make_unique<Image>(parent);
_angry->setSrc(&decorator_angry);
_angry->setAlign(LV_ALIGN_CENTER);
_angry->setPos(_angry_default_position.x, _angry_default_position.y);
_angry->setTransformPivot(_angry->getWidth() / 2, _angry->getHeight() / 2);
_angry->setRotation(_angry_rotation_frames[1]);
_angry->setImageRecolorOpa(LV_OPA_COVER);
_angry->setImageRecolor(_angry_default_color);
if (destroyAfterMs != 0) {
scheduleDestroy(destroyAfterMs);
}
if (animationIntervalMs != 0) {
getTimer().addTask(animationIntervalMs, -1, 0, [this]() {
setRotation(_angry_rotation_frames[_animation_index]);
_animation_index++;
if (_animation_index >= _angry_rotation_frames.size()) {
_animation_index = 0;
}
});
}
}
AngryDecorator::~AngryDecorator()
{
_angry.reset();
}
void AngryDecorator::setPosition(int x, int y)
{
_angry->setPos(x, y);
}
void AngryDecorator::setRotation(int rotation)
{
_angry->setRotation(rotation);
}
void AngryDecorator::setColor(lv_color_t color)
{
_angry->setImageRecolor(color);
}
@@ -0,0 +1,302 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_DECORATOR_ANGRY
#define LV_ATTRIBUTE_IMAGE_DECORATOR_ANGRY
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_DECORATOR_ANGRY uint8_t
decorator_angry_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff,
0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0xff, 0xff, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xdf,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00,
0x70, 0xff, 0xff, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0x8f,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0xff, 0xff, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xaf, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0x50, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xff,
0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0x60, 0x00, 0x00,
0x00, 0x00, 0x60, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0xdf, 0x9f, 0x70, 0x50, 0x50, 0x60, 0xbf, 0xff, 0xff,
0xdf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0xef, 0xff, 0xff, 0xdf, 0x70, 0x40, 0x60, 0x70, 0x8f, 0xdf, 0xff,
0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xaf, 0xef, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xdf,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x70, 0x80, 0x9f, 0xaf, 0x8f, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x60, 0x8f, 0xaf, 0x9f, 0x8f, 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70, 0x8f, 0x9f, 0xaf, 0x8f, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x8f, 0xaf, 0x9f, 0x80, 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xaf, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x70,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef,
0xaf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0xdf,
0x8f, 0x70, 0x60, 0x40, 0x70, 0xdf, 0xff, 0xff, 0xef, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xff, 0xff,
0xbf, 0x60, 0x50, 0x50, 0x70, 0x9f, 0xdf, 0xff, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x70, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00,
0x60, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0x8f,
0x00, 0x00, 0x00, 0x00, 0x8f, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0xff, 0xff, 0xaf, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0xff, 0xff, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xff,
0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xff, 0xff, 0x70, 0x00, 0x00,
0x00, 0x00, 0x70, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0xff,
0xff, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0xff, 0xff, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0xff, 0xff, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t decorator_angry = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 40,
.header.h = 40,
.data_size = 1600 * 3,
.data = decorator_angry_map,
};
@@ -0,0 +1,302 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_DECORATOR_HEART
#define LV_ATTRIBUTE_IMAGE_DECORATOR_HEART
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_DECORATOR_HEART uint8_t
decorator_heart_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x9f, 0xcf, 0xef, 0xff, 0xef, 0xdf, 0x8f, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9f, 0xcf, 0xef, 0xff, 0xef, 0xdf, 0x9f,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x40, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x30, 0x00, 0x00, 0x00, 0x00,
0x30, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x00,
0x00, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf,
0x20, 0x00, 0x00, 0x20, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xdf, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x9f, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xbf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xdf, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xcf, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf,
0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x9f, 0x60, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0xaf, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x50,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x40, 0x00, 0x00, 0x00, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xcf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xcf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xcf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xdf, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x20, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xaf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0xdf, 0xff, 0xff, 0xdf, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xdf, 0xdf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t decorator_heart = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 40,
.header.h = 40,
.data_size = 1600 * 3,
.data = decorator_heart_map,
};
@@ -0,0 +1,302 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_DECORATOR_SWEAT
#define LV_ATTRIBUTE_IMAGE_DECORATOR_SWEAT
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_DECORATOR_SWEAT uint8_t
decorator_sweat_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xe7, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xff,
0xff, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x28, 0xff, 0xff, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x46, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xb3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x39, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x0d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xe6, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1a, 0xeb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xeb, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xd8, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xe0, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x09, 0x60, 0xb4, 0xcf, 0xe3, 0xff, 0xed, 0xb4, 0x60, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t decorator_sweat = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 40,
.header.h = 40,
.data_size = 1600 * 3,
.data = decorator_sweat_map,
};
@@ -0,0 +1,123 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "../../utils/timer.h"
#include "../avatar/decorator.h"
#include <lvgl.h>
#include <smooth_lvgl.hpp>
#include <cstdint>
#include <memory>
namespace stackchan::avatar {
/**
* @brief Decorator with a timer
*
*/
class TimerDecorator : public Decorator {
public:
void scheduleDestroy(uint32_t ms)
{
_timer.addTask(ms, 1, 0, [this]() { requestDestroy(); });
}
Timer& getTimer()
{
return _timer;
}
virtual void _update() override
{
_timer.update();
}
private:
Timer _timer;
};
/**
* @brief
*
*/
class HeartDecorator : public TimerDecorator {
public:
/**
* @brief
*
* @param parent
* @param destroyAfterMs Destroy after milliseconds, 0 for infinite
* @param animationIntervalMs Animation update interval in milliseconds, 0 for none
*/
HeartDecorator(lv_obj_t* parent, uint32_t destroyAfterMs = 0, uint32_t animationIntervalMs = 500);
~HeartDecorator();
using Element::setPosition;
void setPosition(int x, int y);
void setRotation(int rotation);
void setColor(lv_color_t color);
private:
std::unique_ptr<uitk::lvgl_cpp::Image> _heart;
int _animation_index = 0;
};
/**
* @brief
*
*/
class AngryDecorator : public TimerDecorator {
public:
/**
* @brief
*
* @param parent
* @param destroyAfterMs Destroy after milliseconds, 0 for infinite
* @param animationIntervalMs Animation update interval in milliseconds, 0 for none
*/
AngryDecorator(lv_obj_t* parent, uint32_t destroyAfterMs = 0, uint32_t animationIntervalMs = 500);
~AngryDecorator();
using Element::setPosition;
void setPosition(int x, int y);
void setRotation(int rotation);
void setColor(lv_color_t color);
private:
std::unique_ptr<uitk::lvgl_cpp::Image> _angry;
int _animation_index = 0;
};
/**
* @brief
*
*/
class SweatDecorator : public TimerDecorator {
public:
/**
* @brief
*
* @param parent
* @param destroyAfterMs Destroy after milliseconds, 0 for infinite
* @param animationIntervalMs Animation update interval in milliseconds, 0 for none
*/
SweatDecorator(lv_obj_t* parent, uint32_t destroyAfterMs = 0, uint32_t animationIntervalMs = 700);
~SweatDecorator();
using Element::setPosition;
void setPosition(int x, int y);
void setRotation(int rotation) override;
void setColor(lv_color_t color);
void setVisible(bool visible) override;
private:
std::unique_ptr<uitk::lvgl_cpp::Image> _sweat;
int _animation_index = 0;
};
} // namespace stackchan::avatar
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "decorators.h"
#include <vector>
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const Vector2i _heart_default_position = Vector2i(108, -70);
static const lv_color_t _heart_default_color = lv_color_hex(0xE13232);
static const std::vector<int> _heart_rotation_frames = {150, 200};
LV_IMAGE_DECLARE(decorator_heart);
HeartDecorator::HeartDecorator(lv_obj_t* parent, uint32_t destroyAfterMs, uint32_t animationIntervalMs)
{
_heart = std::make_unique<Image>(parent);
_heart->setSrc(&decorator_heart);
_heart->setAlign(LV_ALIGN_CENTER);
_heart->setPos(_heart_default_position.x, _heart_default_position.y);
_heart->setTransformPivot(_heart->getWidth() / 2, _heart->getHeight() / 2);
_heart->setRotation(_heart_rotation_frames[1]);
_heart->setImageRecolorOpa(LV_OPA_COVER);
_heart->setImageRecolor(_heart_default_color);
if (destroyAfterMs != 0) {
scheduleDestroy(destroyAfterMs);
}
if (animationIntervalMs != 0) {
getTimer().addTask(animationIntervalMs, -1, 0, [this]() {
setRotation(_heart_rotation_frames[_animation_index]);
_animation_index++;
if (_animation_index >= _heart_rotation_frames.size()) {
_animation_index = 0;
}
});
}
}
HeartDecorator::~HeartDecorator()
{
_heart.reset();
}
void HeartDecorator::setPosition(int x, int y)
{
_heart->setPos(x, y);
}
void HeartDecorator::setRotation(int rotation)
{
_heart->setRotation(rotation);
}
void HeartDecorator::setColor(lv_color_t color)
{
_heart->setImageRecolor(color);
}
@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "decorators.h"
#include <vector>
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const Vector2i _sweat_default_position = Vector2i(-116, -72);
static const lv_color_t _sweat_default_color = lv_color_hex(0x75E1FF);
static const std::vector<int> _sweat_pos_y_frames = {-72, -68, -62, -58, 0};
LV_IMAGE_DECLARE(decorator_sweat);
SweatDecorator::SweatDecorator(lv_obj_t* parent, uint32_t destroyAfterMs, uint32_t animationIntervalMs)
{
_sweat = std::make_unique<Image>(parent);
_sweat->setSrc(&decorator_sweat);
_sweat->setAlign(LV_ALIGN_CENTER);
_sweat->setPos(_sweat_default_position.x, _sweat_default_position.y);
_sweat->setTransformPivot(_sweat->getWidth() / 2, _sweat->getHeight() / 2);
_sweat->setImageRecolorOpa(LV_OPA_COVER);
_sweat->setImageRecolor(_sweat_default_color);
if (destroyAfterMs != 0) {
scheduleDestroy(destroyAfterMs);
}
if (animationIntervalMs != 0) {
getTimer().addTask(animationIntervalMs, -1, 0, [this]() {
if (_sweat_pos_y_frames[_animation_index] == 0) {
setVisible(false);
} else {
setVisible(true);
setPosition(_sweat_default_position.x, _sweat_pos_y_frames[_animation_index]);
}
_animation_index++;
if (_animation_index >= _sweat_pos_y_frames.size()) {
_animation_index = 0;
}
});
}
}
SweatDecorator::~SweatDecorator()
{
_sweat.reset();
}
void SweatDecorator::setPosition(int x, int y)
{
Element::setPosition({x, y});
_sweat->setPos(x, y);
}
void SweatDecorator::setRotation(int rotation)
{
Element::setRotation(rotation);
_sweat->setRotation(rotation);
}
void SweatDecorator::setColor(lv_color_t color)
{
_sweat->setImageRecolor(color);
}
void SweatDecorator::setVisible(bool visible)
{
Element::setVisible(visible);
_sweat->setHidden(!visible);
}
@@ -0,0 +1,185 @@
#ifdef __has_include
#if __has_include("lvgl.h")
#ifndef LV_LVGL_H_INCLUDE_SIMPLE
#define LV_LVGL_H_INCLUDE_SIMPLE
#endif
#endif
#endif
#if defined(LV_LVGL_H_INCLUDE_SIMPLE)
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMAGE_DEFAULT_BUBBLE_ARROW
#define LV_ATTRIBUTE_IMAGE_DEFAULT_BUBBLE_ARROW
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMAGE_DEFAULT_BUBBLE_ARROW uint8_t
default_bubble_arrow_map[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x92, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xbf, 0xff, 0xc0, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xff, 0xff, 0xdd, 0x26, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x97, 0xff, 0xff, 0xff, 0xed, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0xff, 0xff, 0xff, 0xff,
0xfe, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x95, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xde, 0x28,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xe0, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd6, 0x2a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x5f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x6b, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe8, 0x73, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x56, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0x7b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf1, 0x83, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2e, 0xff, 0xff, 0xff, 0xff, 0xf5, 0x8b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xf9,
0x93, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfd, 0x9f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const lv_image_dsc_t default_bubble_arrow = {
.header.cf = LV_COLOR_FORMAT_RGB565A8,
.header.magic = LV_IMAGE_HEADER_MAGIC,
.header.w = 28,
.header.h = 32,
.data_size = 896 * 3,
.data = default_bubble_arrow_map,
};
@@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "default.h"
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
void DefaultAvatar::init(lv_obj_t* parent, const lv_font_t* font)
{
_pannel = std::make_unique<Container>(parent);
_pannel->align(LV_ALIGN_CENTER, 0, 0);
_pannel->setSize(320, 240);
_pannel->setRadius(0);
_pannel->setBorderWidth(0);
_pannel->setBgColor(secondaryColor);
_pannel->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_key_elements.leftEye = std::make_unique<DefaultEyes>(_pannel->get(), primaryColor, secondaryColor, true);
_key_elements.rightEye = std::make_unique<DefaultEyes>(_pannel->get(), primaryColor, secondaryColor, false);
_key_elements.mouth = std::make_unique<DefaultMouth>(_pannel->get(), primaryColor, secondaryColor);
_key_elements.speechBubble =
std::make_unique<DefaultSpeechBubble>(_pannel->get(), primaryColor, secondaryColor, font);
}
Container* DefaultAvatar::getPanel() const
{
if (_pannel) {
return _pannel.get();
}
return NULL;
}
@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "../../avatar/avatar.h"
#include "../../avatar/elements/feature.h"
#include <lvgl.h>
#include <smooth_lvgl.hpp>
#include <memory>
namespace stackchan::avatar {
/**
* @brief
*
*/
class DefaultAvatar : public Avatar {
public:
lv_color_t primaryColor = lv_color_white();
lv_color_t secondaryColor = lv_color_black();
void init(lv_obj_t* parent, const lv_font_t* font = &lv_font_montserrat_16);
uitk::lvgl_cpp::Container* getPanel() const;
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _pannel;
};
/**
* @brief
*
*/
class DefaultEyes : public Feature {
public:
DefaultEyes(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor, bool isLeftEye);
~DefaultEyes();
void setPosition(const uitk::Vector2i& position) override;
void setWeight(int weight) override;
void setRotation(int rotation) override;
void setEmotion(const Emotion& emotion) override;
void setVisible(bool visible) override;
void setSize(int size) override;
private:
bool _is_left_eye = false;
int _eyelid_offset_y = 0;
std::unique_ptr<uitk::lvgl_cpp::Container> _container;
std::unique_ptr<uitk::lvgl_cpp::Container> _eye;
std::unique_ptr<uitk::lvgl_cpp::Container> _eyelid;
};
/**
* @brief
*
*/
class DefaultMouth : public Feature {
public:
DefaultMouth(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor);
~DefaultMouth();
void setPosition(const uitk::Vector2i& position) override;
void setWeight(int weight) override;
void setRotation(int rotation) override;
void setVisible(bool visible) override;
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _mouth;
};
/**
* @brief
*
*/
class DefaultSpeechBubble : public SpeechBubble {
public:
DefaultSpeechBubble(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor, const lv_font_t* font);
~DefaultSpeechBubble();
void setSpeech(std::string_view text) override;
void clearSpeech() override;
void setVisible(bool visible) override;
void setTextFont(void* font) override;
private:
std::unique_ptr<uitk::lvgl_cpp::Container> _container;
std::unique_ptr<uitk::lvgl_cpp::Image> _arrow;
std::unique_ptr<uitk::lvgl_cpp::Container> _bubble;
std::unique_ptr<uitk::lvgl_cpp::Label> _text;
};
} // namespace stackchan::avatar
@@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "default.h"
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const int _eye_size = 16;
static const Vector2i _eye_pos = Vector2i(-70, -16);
static const Vector2i _eye_min_offset = Vector2i(-16, -16);
static const Vector2i _eye_max_offset = Vector2i(16, 16);
static const Vector2i _eye_size_limit = Vector2i(8, 32);
DefaultEyes::DefaultEyes(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor, bool isLeftEye)
{
_is_left_eye = isLeftEye;
_container = std::make_unique<Container>(parent);
_container->setRadius(0);
_container->setAlign(LV_ALIGN_CENTER);
_container->setBorderWidth(0);
_container->setBgOpa(0);
_container->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_container->setPadding(0, 0, 0, 0);
_container->setTransformPivot(_eye_size_limit.y / 2, _eye_size_limit.y / 2);
_container->setSize(_eye_size_limit.y, _eye_size_limit.y);
_eye = std::make_unique<Container>(_container->get());
_eye->setRadius(LV_RADIUS_CIRCLE);
_eye->align(LV_ALIGN_CENTER, 0, 0);
_eye->setBorderWidth(0);
_eye->setBgColor(primaryColor);
_eye->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_eyelid = std::make_unique<Container>(_container->get());
_eyelid->setRadius(0);
_eyelid->align(LV_ALIGN_CENTER, 0, 0);
_eyelid->setBorderWidth(0);
_eyelid->setBgColor(secondaryColor);
_eyelid->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
setSize(0);
setWeight(100);
setPosition(_position);
setRotation(0);
}
DefaultEyes::~DefaultEyes()
{
_eyelid.reset();
_eye.reset();
_container.reset();
}
void DefaultEyes::setPosition(const Vector2i& position)
{
Element::setPosition(position);
auto pos_x = _is_left_eye ? _eye_pos.x : -_eye_pos.x;
pos_x += map_range(_position.x, -100, 100, _eye_min_offset.x, _eye_max_offset.x);
auto pos_y = _eye_pos.y + map_range(_position.y, -100, 100, _eye_min_offset.y, _eye_max_offset.y);
_container->setPos(pos_x, pos_y);
_eyelid->setY(_eyelid_offset_y);
}
void DefaultEyes::setWeight(int weight)
{
Feature::setWeight(weight);
_eyelid_offset_y = -map_range(_weight, 0, 100, 0, (int)_eyelid->getHeight());
_eyelid->setY(_eyelid_offset_y);
}
void DefaultEyes::setRotation(int rotation)
{
Element::setRotation(rotation);
_container->setRotation(rotation);
}
void DefaultEyes::setEmotion(const Emotion& emotion)
{
if (getIgnoreEmotion()) {
return;
}
auto apply_style = [this](int weight, int rotation) {
setWeight(weight);
if (_is_left_eye) {
setRotation(rotation);
} else {
setRotation(-rotation);
}
};
switch (emotion) {
case Emotion::Neutral:
apply_style(100, 0);
break;
case Emotion::Happy:
apply_style(72, 1550);
break;
case Emotion::Angry:
apply_style(70, 450);
break;
case Emotion::Sad:
apply_style(70, -400);
break;
case Emotion::Doubt:
apply_style(75, 0);
break;
case Emotion::Sleepy:
apply_style(35, -50);
break;
default:
break;
}
}
void DefaultEyes::setVisible(bool visible)
{
Element::setVisible(visible);
_container->setHidden(!visible);
}
void DefaultEyes::setSize(int size)
{
Feature::setSize(size);
int eye_size = map_range(_size, -100, 100, _eye_size_limit.x, _eye_size_limit.y);
_eye->setSize(eye_size, eye_size);
_eyelid->setSize(eye_size, eye_size);
// Force eyelid update
setWeight(getWeight());
}
@@ -0,0 +1,73 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "default.h"
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const Vector2i _mouth_pos = Vector2i(0, 26);
static const Vector2i _mouth_min_offset = Vector2i(-16, -16);
static const Vector2i _mouth_max_offset = Vector2i(16, 16);
static const Vector2i _mouth_min_size = Vector2i(90, 6);
static const Vector2i _mouth_max_size = Vector2i(60, 50);
static const int _mouth_min_radius = 0;
static const int _mouth_max_radius = 16;
DefaultMouth::DefaultMouth(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor)
{
_mouth = std::make_unique<Container>(parent);
_mouth->setAlign(LV_ALIGN_CENTER);
_mouth->setBorderWidth(0);
_mouth->setBgColor(primaryColor);
_mouth->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
setPosition(_position);
setWeight(0);
setRotation(0);
}
DefaultMouth::~DefaultMouth()
{
_mouth.reset();
}
void DefaultMouth::setPosition(const Vector2i& position)
{
Element::setPosition(position);
auto pos_x = _mouth_pos.x + map_range(_position.x, -100, 100, _mouth_min_offset.x, _mouth_max_offset.x);
auto pos_y = _mouth_pos.y + map_range(_position.y, -100, 100, _mouth_min_offset.y, _mouth_max_offset.y);
_mouth->setPos(pos_x, pos_y);
}
void DefaultMouth::setWeight(int weight)
{
Feature::setWeight(weight);
auto size_x = map_range(_weight, 0, 100, _mouth_min_size.x, _mouth_max_size.x);
auto size_y = map_range(_weight, 0, 100, _mouth_min_size.y, _mouth_max_size.y);
auto radius = map_range(_weight, 0, 100, _mouth_min_radius, _mouth_max_radius);
_mouth->setSize(size_x, size_y);
_mouth->setRadius(radius);
}
void DefaultMouth::setRotation(int rotation)
{
Element::setRotation(rotation);
_mouth->setTransformPivot(_mouth->getWidth() / 2, _mouth->getHeight() / 2);
_mouth->setRotation(rotation);
}
void DefaultMouth::setVisible(bool visible)
{
Element::setVisible(visible);
_mouth->setHidden(!visible);
}
@@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "default.h"
using namespace uitk;
using namespace uitk::lvgl_cpp;
using namespace stackchan::avatar;
static const Vector2i _container_pos = Vector2i(0, 89);
static const Vector2i _container_size = Vector2i(320, 74);
static const Vector2i _arrow_offset = Vector2i(40, -15);
static const int _text_mx = 20;
static const int _bubble_min_width = 90;
static const int _bubble_max_width = 340;
static const int _bubble_height = 52;
static const int _bubble_min_offset_x = 66;
static const int _bubble_max_offset_x = 0;
LV_IMAGE_DECLARE(default_bubble_arrow);
DefaultSpeechBubble::DefaultSpeechBubble(lv_obj_t* parent, lv_color_t primaryColor, lv_color_t secondaryColor,
const lv_font_t* font)
{
_container = std::make_unique<Container>(parent);
_container->setRadius(0);
_container->setAlign(LV_ALIGN_CENTER);
_container->setBorderWidth(0);
_container->setBgOpa(0);
_container->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_container->setSize(_container_size.x, _container_size.y);
_container->setPos(_container_pos.x, _container_pos.y);
_container->setPadding(0, 0, 0, 0);
_arrow = std::make_unique<Image>(_container->get());
_arrow->setSrc(&default_bubble_arrow);
_arrow->setAlign(LV_ALIGN_CENTER);
_arrow->setPos(_arrow_offset.x, _arrow_offset.y);
_arrow->setImageRecolorOpa(LV_OPA_COVER);
_arrow->setImageRecolor(primaryColor);
_bubble = std::make_unique<Container>(_container->get());
_bubble->setRadius(LV_RADIUS_CIRCLE);
_bubble->setAlign(LV_ALIGN_CENTER);
_bubble->setBorderWidth(0);
_bubble->setBgColor(primaryColor);
_bubble->removeFlag(LV_OBJ_FLAG_SCROLLABLE);
_bubble->setSize(_bubble_max_width, _bubble_height);
_bubble->setPos(0, 11);
_text = std::make_unique<Label>(_bubble->get());
_text->setTextColor(secondaryColor);
_text->setTextFont(font);
_text->setTextAlign(LV_TEXT_ALIGN_CENTER);
_text->setAlign(LV_ALIGN_CENTER);
_text->setPos(0, 0);
_text->setWidth(320 - _text_mx * 2);
_text->setLongMode(LV_LABEL_LONG_MODE_SCROLL_CIRCULAR);
clearSpeech();
}
DefaultSpeechBubble::~DefaultSpeechBubble()
{
_text.reset();
_bubble.reset();
_arrow.reset();
_container.reset();
}
void DefaultSpeechBubble::setSpeech(std::string_view text)
{
if (text.empty()) {
clearSpeech();
return;
}
_text->setText(text);
lv_point_t text_size;
lv_text_get_size(&text_size, text.data(), _text->getTextFont(), 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
int bubble_width = min(text_size.x + _text_mx * 2, _bubble_max_width);
bubble_width = max(bubble_width, _bubble_min_width);
auto bubble_offset_x =
map_range(bubble_width, _bubble_min_width, _bubble_max_width, _bubble_min_offset_x, _bubble_max_offset_x);
_bubble->setWidth(bubble_width);
_bubble->setX(bubble_offset_x);
setVisible(true);
}
void DefaultSpeechBubble::clearSpeech()
{
_text->setText("");
setVisible(false);
}
void DefaultSpeechBubble::setVisible(bool visible)
{
SpeechBubble::setVisible(visible);
_container->setHidden(!visible);
}
void DefaultSpeechBubble::setTextFont(void* font)
{
if (_text && font) {
_text->setTextFont((lv_font_t*)font);
}
}
@@ -0,0 +1,223 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "json_helper.h"
#include <ArduinoJson.hpp>
#include <mooncake_log.h>
static const char* _tag = "stackchan-json";
using namespace uitk;
namespace stackchan::avatar {
static void update_feature(Feature& feature, ArduinoJson::JsonObject& jsonObject)
{
if (jsonObject["x"].is<int>() && jsonObject["y"].is<int>()) {
Vector2i position;
position.x = jsonObject["x"];
position.y = jsonObject["y"];
feature.setPosition(position);
}
if (jsonObject["rotation"].is<int>()) {
int rotation = jsonObject["rotation"];
feature.setRotation(rotation);
}
if (jsonObject["weight"].is<int>()) {
int weight = jsonObject["weight"];
feature.setWeight(weight);
}
if (jsonObject["size"].is<int>()) {
int size = jsonObject["size"];
feature.setSize(size);
}
}
void update_from_json(Avatar* avatar, const char* jsonContent)
{
if (!avatar || !jsonContent) {
return;
}
ArduinoJson::JsonDocument doc;
auto error = ArduinoJson::deserializeJson(doc, jsonContent);
if (error) {
mclog::tagError(_tag, "deserializeJson failed: {}", error.c_str());
return;
}
if (doc["leftEye"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject leftEyeObj = doc["leftEye"];
update_feature(avatar->leftEye(), leftEyeObj);
}
if (doc["rightEye"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject rightEyeObj = doc["rightEye"];
update_feature(avatar->rightEye(), rightEyeObj);
}
if (doc["mouth"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject mouthObj = doc["mouth"];
update_feature(avatar->mouth(), mouthObj);
}
}
} // namespace stackchan::avatar
namespace stackchan::motion {
static void update_servo(Servo& servo, ArduinoJson::JsonObject& jsonObject)
{
// If is rotate mode
if (jsonObject["rotate"].is<int>()) {
int rotate = jsonObject["rotate"];
servo.rotate(rotate);
return;
}
if (!jsonObject["angle"].is<int>()) {
return;
}
int angle = jsonObject["angle"];
// If has speed, move directly
if (jsonObject["speed"].is<int>()) {
int speed = jsonObject["speed"];
servo.moveWithSpeed(angle, speed);
return;
}
// If has spring params, move with spring params
if (jsonObject["spring"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject spring = jsonObject["spring"];
float stiffness = 170.0f;
if (spring["stiffness"].is<float>()) {
stiffness = spring["stiffness"];
}
float damping = 26.0f;
if (spring["damping"].is<float>()) {
damping = spring["damping"];
}
servo.moveWithSpringParams(angle, stiffness, damping);
return;
}
// Move in deafult spring
servo.move(angle);
}
void update_from_json(Motion* motion, const char* jsonContent)
{
if (!motion || !jsonContent) {
return;
}
ArduinoJson::JsonDocument doc;
auto error = ArduinoJson::deserializeJson(doc, jsonContent);
if (error) {
mclog::tagError(_tag, "deserializeJson failed: {}", error.c_str());
return;
}
if (doc["yawServo"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject yawServoObj = doc["yawServo"];
update_servo(motion->yawServo(), yawServoObj);
}
if (doc["pitchServo"].is<ArduinoJson::JsonObject>()) {
ArduinoJson::JsonObject pitchServoObj = doc["pitchServo"];
update_servo(motion->pitchServo(), pitchServoObj);
}
}
} // namespace stackchan::motion
namespace stackchan::animation {
static FeatureKeyframe parse_feature(ArduinoJson::JsonObject jsonObject)
{
FeatureKeyframe kf;
if (jsonObject["x"].is<int>()) {
kf.position.x = jsonObject["x"];
}
if (jsonObject["y"].is<int>()) {
kf.position.y = jsonObject["y"];
}
if (jsonObject["rotation"].is<int>()) {
kf.rotation = jsonObject["rotation"];
}
if (jsonObject["weight"].is<int>()) {
kf.weight = jsonObject["weight"];
}
return kf;
}
static ServoKeyframe parse_servo(ArduinoJson::JsonObject jsonObject)
{
ServoKeyframe kf;
if (jsonObject["angle"].is<int>()) {
kf.angle = jsonObject["angle"];
}
if (jsonObject["speed"].is<int>()) {
kf.speed = jsonObject["speed"];
}
return kf;
}
KeyframeSequence parse_sequence_from_json(const char* jsonContent)
{
KeyframeSequence sequence;
if (!jsonContent) {
return sequence;
}
ArduinoJson::JsonDocument doc;
auto error = ArduinoJson::deserializeJson(doc, jsonContent);
if (error) {
mclog::tagError(_tag, "deserializeJson failed: {}", error.c_str());
return sequence;
}
if (!doc.is<ArduinoJson::JsonArray>()) {
mclog::tagError(_tag, "json is not an array");
return sequence;
}
ArduinoJson::JsonArray array = doc.as<ArduinoJson::JsonArray>();
for (ArduinoJson::JsonObject kfObj : array) {
Keyframe kf;
if (kfObj["leftEye"].is<ArduinoJson::JsonObject>()) {
kf.leftEye = parse_feature(kfObj["leftEye"]);
}
if (kfObj["rightEye"].is<ArduinoJson::JsonObject>()) {
kf.rightEye = parse_feature(kfObj["rightEye"]);
}
if (kfObj["mouth"].is<ArduinoJson::JsonObject>()) {
kf.mouth = parse_feature(kfObj["mouth"]);
}
if (kfObj["yawServo"].is<ArduinoJson::JsonObject>()) {
kf.yawServo = parse_servo(kfObj["yawServo"]);
}
if (kfObj["pitchServo"].is<ArduinoJson::JsonObject>()) {
kf.pitchServo = parse_servo(kfObj["pitchServo"]);
}
if (kfObj["durationMs"].is<int>()) {
kf.durationMs = kfObj["durationMs"];
}
sequence.push_back(kf);
}
return sequence;
}
} // namespace stackchan::animation
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "../avatar/avatar.h"
#include "../motion/motion.h"
#include "../animation/animation.h"
namespace stackchan {
namespace avatar {
void update_from_json(Avatar* avatar, const char* jsonContent);
}
namespace motion {
void update_from_json(Motion* motion, const char* jsonContent);
}
namespace animation {
KeyframeSequence parse_sequence_from_json(const char* jsonContent);
}
} // namespace stackchan
+39
View File
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "avatar/avatar.h"
#include "motion/motion.h"
#include "utils/object_pool.h"
namespace stackchan {
/**
* @brief Modifiable base class, expose modifiable APIs to the modifiers
*
*/
class Modifiable {
public:
virtual ~Modifiable() = default;
virtual motion::Motion& motion() = 0;
virtual avatar::Avatar& avatar() = 0;
virtual bool hasAvatar() = 0;
};
/**
* @brief Modifier base class
*
*/
class Modifier : public Poolable {
public:
virtual void _update(Modifiable& stackchan)
{
}
};
} // namespace stackchan
+80
View File
@@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include <cstdint>
namespace stackchan {
/**
* @brief
*
*/
class BlinkModifier : public TimerModifier {
public:
BlinkModifier(uint32_t destroyAfterMs = 0, uint32_t openIntervalMs = 5200, uint32_t closeIntervalMs = 200)
: _open_interval_ms(openIntervalMs), _close_interval_ms(closeIntervalMs)
{
if (destroyAfterMs != 0) {
scheduleDestroy(destroyAfterMs);
}
_should_close = true;
}
void resyncEyeWeights()
{
_needs_resync = true;
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (!stackchan.hasAvatar()) {
return;
}
if (_needs_resync) {
_needs_resync = false;
_left_eye_weight = stackchan.avatar().leftEye().getWeight();
_right_eye_weight = stackchan.avatar().rightEye().getWeight();
}
if (_should_close) {
_should_close = false;
_left_eye_weight = stackchan.avatar().leftEye().getWeight();
_right_eye_weight = stackchan.avatar().rightEye().getWeight();
stackchan.avatar().leftEye().setWeight(25);
stackchan.avatar().rightEye().setWeight(25);
getTimer().addTask(_close_interval_ms, 1, 0, [this]() { _should_open = true; });
}
if (_should_open) {
_should_open = false;
stackchan.avatar().leftEye().setWeight(_left_eye_weight);
stackchan.avatar().rightEye().setWeight(_right_eye_weight);
getTimer().addTask(_open_interval_ms, 1, 0, [this]() { _should_close = true; });
}
}
private:
uint32_t _open_interval_ms;
uint32_t _close_interval_ms;
bool _should_close = false;
bool _should_open = false;
bool _needs_resync = false;
int _left_eye_weight = 0;
int _right_eye_weight = 0;
};
} // namespace stackchan
@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include <cstdint>
namespace stackchan {
/**
* @brief
*
*/
class BreathModifier : public TimerModifier {
public:
BreathModifier(uint32_t destroyAfterMs = 0, uint32_t updateIntervalMs = 600)
{
if (destroyAfterMs != 0) {
scheduleDestroy(destroyAfterMs);
}
if (updateIntervalMs == 0) {
requestDestroy();
}
getTimer().addTask(updateIntervalMs, -1, 0, [this]() { _update_flag = true; });
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (!stackchan.hasAvatar()) {
return;
}
if (!_update_flag) {
return;
}
_update_flag = false;
// Check state switch
_breathe_count++;
if (_is_breathing_in) {
if (_breathe_count >= _breathe_in_count) {
_is_breathing_in = false;
_breathe_count = 0;
}
} else {
if (_breathe_count >= _breathe_out_count) {
_is_breathing_in = true;
_breathe_count = 0;
}
}
// Update breath
auto& avatar = stackchan.avatar();
_left_eye_position = avatar.leftEye().getPosition();
_right_eye_position = avatar.rightEye().getPosition();
_mouth_position = avatar.mouth().getPosition();
if (_is_breathing_in) {
_left_eye_position.y += _breathe_in_offset;
_right_eye_position.y += _breathe_in_offset;
_mouth_position.y += _breathe_in_offset;
} else {
_left_eye_position.y += _breathe_out_offset;
_right_eye_position.y += _breathe_out_offset;
_mouth_position.y += _breathe_out_offset;
}
avatar.leftEye().setPosition(_left_eye_position);
avatar.rightEye().setPosition(_right_eye_position);
avatar.mouth().setPosition(_mouth_position);
}
private:
// Keep in and out total offset added up to 0
const int _breathe_in_count = 7;
const int _breathe_in_offset = -4;
const int _breathe_out_count = 7;
const int _breathe_out_offset = 4;
bool _update_flag = false;
bool _is_breathing_in = true;
int _breathe_count = 0;
uitk::Vector2i _left_eye_position;
uitk::Vector2i _right_eye_position;
uitk::Vector2i _mouth_position;
};
} // namespace stackchan
+113
View File
@@ -0,0 +1,113 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "../modifiable.h"
#include "../animation/animation.h"
namespace stackchan {
class DanceModifier : public Modifier {
public:
/**
* @brief Happy dance
* - Swaying left and right
* - Eyes squinting (Happy expression)
* - Mouth open
*/
inline static const animation::KeyframeSequence Happy = {
// Center, prepare
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 200}, {0, 200}, 500},
// Sway Left, Eyes Happy (Weight 50), Mouth Open (Weight 50)
{{-10, 0, 0, 50}, {-10, 0, 0, 50}, {0, 0, 0, 50}, {300, 200}, {-100, 200}, 800},
// Sway Right
{{10, 0, 0, 50}, {10, 0, 0, 50}, {0, 0, 0, 50}, {-300, 200}, {-100, 200}, 800},
// Sway Left
{{-10, 0, 0, 50}, {-10, 0, 0, 50}, {0, 0, 0, 50}, {300, 200}, {-100, 200}, 800},
// Sway Right
{{10, 0, 0, 50}, {10, 0, 0, 50}, {0, 0, 0, 50}, {-300, 200}, {-100, 200}, 800},
// Center, Back to normal
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 200}, {0, 200}, 500},
};
/**
* @brief Robot dance
* - Stiff, jerky movements
* - Sharp angles
* - Eyes fixed open
*/
inline static const animation::KeyframeSequence Robot = {
// Center
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 500}, {0, 500}, 500},
// Turn Left Sharp
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {450, 800}, {0, 800}, 400},
// Pitch Down Sharp
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {450, 800}, {200, 800}, 400},
// Turn Right Sharp (keeping pitch)
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {-450, 800}, {200, 800}, 600},
// Pitch Up
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {-450, 800}, {0, 800}, 400},
// Center
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 800}, {0, 800}, 400},
};
/**
* @brief Panic dance
* - Fast shaking
* - Eyes wide open (surprised)
* - Mouth wide open
*/
inline static const animation::KeyframeSequence Panic = {
// Start Panic
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {0, 1000}, {0, 1000}, 100},
// Shake 1
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {200, 1000}, {100, 1000}, 100},
// Shake 2
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {-200, 1000}, {-100, 1000}, 100},
// Shake 3
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {200, 1000}, {100, 1000}, 100},
// Shake 4
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {-200, 1000}, {-100, 1000}, 100},
// Shake 5
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 100}, {200, 1000}, {100, 1000}, 100},
// Calm down
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 200}, {0, 200}, 500},
};
/**
* @brief Look Around
* - Slow scanning of the environment
*/
inline static const animation::KeyframeSequence LookAround = {
// Center
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 200}, {0, 200}, 1000},
// Look Left
{{-20, 0, 0, 100}, {-20, 0, 0, 100}, {0, 0, 0, 20}, {600, 150}, {0, 150}, 2000},
// Look Right
{{20, 0, 0, 100}, {20, 0, 0, 100}, {0, 0, 0, 20}, {-600, 150}, {0, 150}, 2000},
// Look Up
{{0, -20, 0, 100}, {0, -20, 0, 100}, {0, 0, 0, 40}, {0, 150}, {-300, 150}, 1500},
// Center
{{0, 0, 0, 100}, {0, 0, 0, 100}, {0, 0, 0, 0}, {0, 200}, {0, 200}, 1000},
};
DanceModifier(const animation::KeyframeSequence& sequence) : _timeline(sequence, false)
{
_timeline.start();
}
void _update(Modifiable& stackchan) override
{
_timeline.update();
if (_timeline.isFinished()) {
requestDestroy();
}
}
private:
animation::Timeline _timeline;
};
} // namespace stackchan
@@ -0,0 +1,145 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include "../avatar/decorators/decorators.h"
#include "../utils/random.h"
#include <smooth_ui_toolkit.hpp>
#include <hal/hal.h>
#include <cstdint>
#include <memory>
namespace stackchan {
class HeadPetModifier : public TimerModifier {
public:
HeadPetModifier(uint32_t restoreDelayMs = 3000) : _restore_delay_ms(restoreDelayMs)
{
_signal_connection = GetHAL().onHeadPetGesture.connect([this](HeadPetGesture gesture) {
LvglLockGuard lock;
if (gesture == HeadPetGesture::SwipeForward || gesture == HeadPetGesture::SwipeBackward) {
_trigger_happy = true;
_trigger_release = false;
// 每次抚摸都打断恢复倒计时
_should_restore = false;
_restore_timer_active = false;
} else if (gesture == HeadPetGesture::Release) {
_trigger_release = true;
}
});
}
~HeadPetModifier()
{
GetHAL().onHeadPetGesture.disconnect(_signal_connection);
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (_trigger_happy) {
_trigger_happy = false;
// 1. 首次进入记录当前位置
if (!_in_happy_state) {
_prev_emotion = stackchan.avatar().getEmotion();
_prev_pitch = stackchan.motion().getCurrentPitchAngle();
_prev_yaw = stackchan.motion().getCurrentYawAngle();
_in_happy_state = true;
}
// 2. 表情反馈
stackchan.avatar().setEmotion(avatar::Emotion::Happy);
int duration = Random::getInstance().getInt(1500, 2500);
stackchan.avatar().addDecorator(
std::make_unique<avatar::HeartDecorator>(lv_screen_active(), duration, 500));
// 3. 执行随机动作
perform_random_motion(stackchan);
}
if (_trigger_release) {
_trigger_release = false;
if (_in_happy_state) {
// 启动恢复计时
_restore_timer_active = true;
getTimer().addTask(_restore_delay_ms, 1, 0, [this]() { _should_restore = true; });
}
}
if (_should_restore) {
_should_restore = false;
if (_restore_timer_active && _in_happy_state) {
// 恢复原状
stackchan.avatar().setEmotion(_prev_emotion);
auto& motion = stackchan.motion();
motion.moveWithSpeed(_prev_yaw, _prev_pitch, 200);
_in_happy_state = false;
_restore_timer_active = false;
}
}
}
private:
void perform_random_motion(Modifiable& stackchan)
{
int action = Random::getInstance().getInt(0, 2);
auto& motion = stackchan.motion();
int speed = Random::getInstance().getInt(400, 800);
int32_t target_pitch = _prev_pitch;
int32_t target_yaw = _prev_yaw;
// 角度限制: 10 units = 1度
switch (action) {
case 0: // 舒服地蹭手/抬头
target_pitch += Random::getInstance().getInt(150, 250);
target_yaw += Random::getInstance().getInt(-50, 50); // 微调 Yaw
break;
case 1: // 开心歪头/摇晃
target_pitch -= Random::getInstance().getInt(0, 50); // 略微低头
if (Random::getInstance().getInt(0, 1) == 0) {
target_yaw += Random::getInstance().getInt(100, 200);
} else {
target_yaw -= Random::getInstance().getInt(100, 200);
}
break;
case 2: // 兴奋大幅度抬头
target_pitch += Random::getInstance().getInt(250, 400);
break;
}
target_pitch = uitk::clamp(target_pitch, 0, 900);
target_yaw = uitk::clamp(target_yaw, -1280, 1280);
motion.moveWithSpeed(target_yaw, target_pitch, speed);
}
int _signal_connection;
uint32_t _restore_delay_ms;
bool _trigger_happy = false;
bool _trigger_release = false;
bool _in_happy_state = false;
bool _restore_timer_active = false;
bool _should_restore = false;
avatar::Emotion _prev_emotion = avatar::Emotion::Neutral;
int32_t _prev_pitch = 0;
int32_t _prev_yaw = 0;
};
} // namespace stackchan
@@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include "../utils/random.h"
#include <smooth_ui_toolkit.hpp>
#include <cstdint>
namespace stackchan {
class IdleMotionModifier : public TimerModifier {
public:
IdleMotionModifier(uint32_t interval_min = 2000, uint32_t interval_max = 8000)
: _interval_min(interval_min), _interval_max(interval_max)
{
schedule_next_move();
}
void pause()
{
_paused = true;
}
void resume()
{
if (_paused) {
_paused = false;
if (!_timer_active) {
schedule_next_move();
}
}
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (_trigger_move) {
_trigger_move = false;
_timer_active = false;
if (!_paused) {
perform_idle_motion(stackchan);
schedule_next_move();
}
}
}
private:
void schedule_next_move()
{
if (_paused) {
_timer_active = false;
return;
}
_timer_active = true;
uint32_t delay = Random::getInstance().getInt(_interval_min, _interval_max);
getTimer().addTask(delay, 1, 0, [this]() { _trigger_move = true; });
}
void perform_idle_motion(Modifiable& stackchan)
{
auto& motion = stackchan.motion();
int action = Random::getInstance().getInt(0, 10); // Probabilistic choice
int32_t current_yaw = motion.getCurrentYawAngle();
int32_t current_pitch = motion.getCurrentPitchAngle();
int32_t target_yaw = current_yaw;
int32_t target_pitch = current_pitch;
int speed = 400;
if (action < 5) {
// 50% chance: Casual look around (Look at a random point in front)
target_yaw = Random::getInstance().getInt(-300, 300);
target_pitch = Random::getInstance().getInt(100, 250);
speed = Random::getInstance().getInt(200, 500); // Slow to medium speed
} else if (action < 7) {
// 20% chance: Small adjustment / "Breathing" (Very small movement from current)
target_yaw += Random::getInstance().getInt(-100, 100);
target_pitch += Random::getInstance().getInt(-50, 50);
speed = Random::getInstance().getInt(100, 300); // Very slow
} else if (action < 9) {
// 20% chance: Quick glance (Faster, smaller range)
target_yaw += Random::getInstance().getInt(-100, 100);
target_pitch += Random::getInstance().getInt(-30, 30);
speed = Random::getInstance().getInt(300, 600); // Fast
} else {
// 10% chance: Return to center / Neutral
target_yaw = 0;
target_pitch = 200; // Slightly looking up/forward
speed = 100;
}
target_yaw = uitk::clamp(target_yaw, -1280, 1280);
target_pitch = uitk::clamp(target_pitch, 0, 900);
speed = uitk::clamp(speed, 0, 1000);
motion.moveWithSpeed(target_yaw, target_pitch, speed);
}
uint32_t _interval_min;
uint32_t _interval_max;
bool _trigger_move = false;
bool _paused = false;
bool _timer_active = false;
};
} // namespace stackchan
+74
View File
@@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#
#include <cstdint>
namespace stackchan {
/**
* @brief
*
*/
class IMUMotionModifier : public TimerModifier {
public:
IMUMotionModifier()
{
GetHAL().onImuMotionEvent.connect([&](ImuMotionEvent event) {
if (_is_applied) {
return;
}
_new_event = event;
});
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (_new_event != ImuMotionEvent::None) {
_new_event = ImuMotionEvent::None;
apply(stackchan, false);
_is_applied = true;
_restore_flag = false;
getTimer().addTask(2000, 0, 0, [&]() { _restore_flag = true; });
}
if (_restore_flag) {
apply(stackchan, true);
_restore_flag = false;
_is_applied = false;
}
}
void apply(Modifiable& stackchan, bool isRestore)
{
auto& avatar = stackchan.avatar();
if (isRestore) {
avatar.leftEye().setPosition({0, 0});
avatar.rightEye().setPosition({0, 0});
avatar.leftEye().setSize(0);
avatar.rightEye().setSize(0);
avatar.mouth().setPosition({0, 0});
avatar.mouth().setWeight(0);
} else {
avatar.leftEye().setPosition({-20, 0});
avatar.rightEye().setPosition({20, 0});
avatar.leftEye().setSize(60);
avatar.rightEye().setSize(60);
avatar.mouth().setPosition({0, -40});
avatar.mouth().setWeight(58);
}
}
private:
ImuMotionEvent _new_event = ImuMotionEvent::None;
bool _is_applied = false;
bool _restore_flag = false;
};
} // namespace stackchan
@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include "blink.h"
#include "breath.h"
#include "speaking.h"
#include "head_pet.h"
#include "idle_motion.h"
#include "dance.h"
#include "imu.h"
@@ -0,0 +1,126 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "timed.h"
#include "../utils/random.h"
#include <smooth_ui_toolkit.hpp>
#include <cstdint>
namespace stackchan {
/**
* @brief
*
*/
class SpeakingModifier : public TimerModifier {
public:
SpeakingModifier(uint32_t destroyAfterMs = 0, uint32_t updateIntervalMs = 180, bool enableMotion = true)
: _enable_motion(enableMotion)
{
if (destroyAfterMs != 0) {
getTimer().addTask(destroyAfterMs, -1, 0, [this]() { _destroy_flag = true; });
}
if (updateIntervalMs == 0) {
requestDestroy();
}
getTimer().addTask(updateIntervalMs, -1, 0, [this]() { _update_flag = true; });
if (_enable_motion) {
schedule_next_motion();
}
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (!stackchan.hasAvatar()) {
return;
}
if (_motion_flag) {
_motion_flag = false;
perform_speaking_motion(stackchan);
schedule_next_motion();
}
if (!_update_flag) {
return;
}
_update_flag = false;
if (_destroy_flag) {
stackchan.avatar().mouth().setWeight(0);
requestDestroy();
return;
}
auto& random = Random::getInstance();
_is_opened = !_is_opened;
if (_is_opened) {
stackchan.avatar().mouth().setWeight(random.getInt(_open_min_weight, _open_max_weight));
} else {
stackchan.avatar().mouth().setWeight(random.getInt(_close_min_weight, _close_max_weight));
}
}
private:
void schedule_next_motion()
{
uint32_t delay = Random::getInstance().getInt(1600, 2200);
getTimer().addTask(delay, 1, 0, [this]() { _motion_flag = true; });
}
void perform_speaking_motion(Modifiable& stackchan)
{
auto& motion = stackchan.motion();
int action = Random::getInstance().getInt(0, 10);
int32_t current_yaw = motion.getCurrentYawAngle();
int32_t current_pitch = motion.getCurrentPitchAngle();
int32_t target_yaw = current_yaw;
int32_t target_pitch = current_pitch;
int speed = 120;
if (action < 4) {
// Emphasize: Nod / Head bob
target_pitch += Random::getInstance().getInt(-30, 60);
speed = Random::getInstance().getInt(100, 160);
} else if (action < 7) {
// Look at audience: Small yaw changes
target_yaw += Random::getInstance().getInt(-60, 60);
target_pitch += Random::getInstance().getInt(-30, 30);
speed = Random::getInstance().getInt(160, 200);
} else if (action < 9) {
// Reset / Center attention
target_yaw = Random::getInstance().getInt(-60, 60);
target_pitch = 200 + Random::getInstance().getInt(-50, 50);
speed = 120;
}
target_yaw = uitk::clamp(target_yaw, -1280, 1280);
target_pitch = uitk::clamp(target_pitch, 0, 900);
motion.moveWithSpeed(target_yaw, target_pitch, speed);
}
const int _open_min_weight = 40;
const int _open_max_weight = 70;
const int _close_min_weight = 0;
const int _close_max_weight = 30;
bool _enable_motion = false;
bool _motion_flag = false;
bool _update_flag = false;
bool _destroy_flag = false;
bool _is_opened = false;
};
} // namespace stackchan
+160
View File
@@ -0,0 +1,160 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "../utils/timer.h"
#include "../modifiable.h"
#include <string_view>
#include <functional>
#include <cstdint>
#include <memory>
namespace stackchan {
/**
* @brief
*
*/
class TimerModifier : public Modifier {
public:
void scheduleDestroy(uint32_t ms)
{
getTimer().addTask(ms, 1, 0, [this]() { requestDestroy(); });
}
Timer& getTimer()
{
if (!_timer) {
_timer = std::make_unique<Timer>();
}
return *_timer;
}
virtual void _update(Modifiable& stackchan) override
{
if (_timer) {
_timer->update();
}
}
private:
std::unique_ptr<Timer> _timer;
};
/**
* @brief A timed event modifier base, which will be destroyed after the given duration
*
*/
class TimedEventModifier : public TimerModifier {
public:
TimedEventModifier(uint32_t durationMs)
{
if (durationMs == 0) {
requestDestroy();
}
getTimer().addTask(durationMs, -1, 0, [this]() { _destroy_flag = true; });
_is_first_in = true;
}
void _update(Modifiable& stackchan) override
{
TimerModifier::_update(stackchan);
if (_is_first_in) {
_is_first_in = false;
_on_start(stackchan);
return;
}
if (_destroy_flag) {
_on_end(stackchan);
requestDestroy();
}
}
virtual void _on_start(Modifiable& stackchan)
{
}
virtual void _on_end(Modifiable& stackchan)
{
}
private:
bool _is_first_in = true;
bool _destroy_flag = false;
};
/**
* @brief Set emotion for the given duration
*
*/
class TimedEmotionModifier : public TimedEventModifier {
public:
TimedEmotionModifier(avatar::Emotion emotion, uint32_t durationMs) : TimedEventModifier(durationMs)
{
_target_emotion = emotion;
}
void _on_start(Modifiable& stackchan) override
{
if (!stackchan.hasAvatar()) {
return;
}
_prev_emotion = stackchan.avatar().getEmotion();
stackchan.avatar().setEmotion(_target_emotion);
}
void _on_end(Modifiable& stackchan) override
{
if (!stackchan.hasAvatar()) {
return;
}
stackchan.avatar().setEmotion(_prev_emotion);
}
private:
avatar::Emotion _prev_emotion = avatar::Emotion::Neutral;
avatar::Emotion _target_emotion = avatar::Emotion::Neutral;
};
/**
* @brief Set speech for the given duration
*
*/
class TimedSpeechModifier : public TimedEventModifier {
public:
TimedSpeechModifier(std::string_view speech, uint32_t durationMs) : TimedEventModifier(durationMs)
{
_target_speech = speech;
}
void _on_start(Modifiable& stackchan) override
{
if (!stackchan.hasAvatar()) {
return;
}
stackchan.avatar().setSpeech(_target_speech);
}
void _on_end(Modifiable& stackchan) override
{
if (!stackchan.hasAvatar()) {
return;
}
stackchan.avatar().clearSpeech();
}
private:
std::string _target_speech;
};
} // namespace stackchan
+139
View File
@@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "motion.h"
#include <cmath>
using namespace uitk;
using namespace stackchan::motion;
void Motion::init()
{
_yaw_servo->init();
_pitch_servo->init();
}
void Motion::update()
{
_yaw_servo->update();
_pitch_servo->update();
}
Servo& Motion::yawServo()
{
return *_yaw_servo;
}
Servo& Motion::pitchServo()
{
return *_pitch_servo;
}
void Motion::moveYaw(int angle)
{
_yaw_servo->move(angle);
}
void Motion::moveYawWithSpeed(int angle, int speed)
{
_yaw_servo->moveWithSpeed(angle, speed);
}
void Motion::movePitch(int angle)
{
_pitch_servo->move(angle);
}
void Motion::movePitchWithSpeed(int angle, int speed)
{
_pitch_servo->moveWithSpeed(angle, speed);
}
void Motion::move(int yawAngle, int pitchAngle)
{
_yaw_servo->move(yawAngle);
_pitch_servo->move(pitchAngle);
}
void Motion::moveWithSpeed(int yawAngle, int pitchAngle, int speed)
{
_yaw_servo->moveWithSpeed(yawAngle, speed);
_pitch_servo->moveWithSpeed(pitchAngle, speed);
}
void Motion::goHome(int speed)
{
_yaw_servo->moveWithSpeed(0, speed);
_pitch_servo->moveWithSpeed(0, speed);
}
void Motion::stop()
{
_yaw_servo->move(_yaw_servo->getCurrentAngle());
_pitch_servo->move(_pitch_servo->getCurrentAngle());
}
void Motion::lookAtNormalized(float x, float y, int speed)
{
int yaw_angle =
uitk::map_range(x, -1.0f, 1.0f, (float)_yaw_servo->getAngleLimit().x, (float)_yaw_servo->getAngleLimit().y);
int pitch_angle =
uitk::map_range(y, -1.0f, 1.0f, (float)_pitch_servo->getAngleLimit().x, (float)_pitch_servo->getAngleLimit().y);
moveWithSpeed(yaw_angle, pitch_angle, speed);
}
void Motion::lookAtPoint(float x, float y, float z, int speed)
{
// Yaw: 绕 Z 轴旋转。使用 atan2(y, x)
float yaw_rad = std::atan2(y, x);
// Pitch: 俯仰。使用 atan2(z, sqrt(x*x + y*y))
float ground_dist = std::sqrt(x * x + y * y);
float pitch_rad = std::atan2(z, ground_dist);
// 将弧度转换为你的舵机单位 (-1280~1280 等)
int yaw_angle = static_cast<int>(to_degrees(yaw_rad) * 10);
int pitch_angle = static_cast<int>(to_degrees(pitch_rad) * 10);
moveWithSpeed(yaw_angle, pitch_angle, speed);
}
bool Motion::isMoving()
{
return _yaw_servo->isMoving() || _pitch_servo->isMoving();
}
int Motion::getCurrentYawAngle()
{
return _yaw_servo->getCurrentAngle();
}
int Motion::getCurrentPitchAngle()
{
return _pitch_servo->getCurrentAngle();
}
uitk::Vector2i Motion::getCurrentAngles()
{
return uitk::Vector2i(_yaw_servo->getCurrentAngle(), _pitch_servo->getCurrentAngle());
}
void Motion::setTorqueEnabled(bool enabled)
{
_yaw_servo->setTorqueEnabled(enabled);
_pitch_servo->setTorqueEnabled(enabled);
}
void Motion::setAutoTorqueReleaseEnabled(bool enabled)
{
_yaw_servo->setAutoTorqueReleaseEnabled(enabled);
_pitch_servo->setAutoTorqueReleaseEnabled(enabled);
}
void Motion::setAutoAngleSyncEnabled(bool enabled)
{
_yaw_servo->setAutoAngleSyncEnabled(enabled);
_pitch_servo->setAutoAngleSyncEnabled(enabled);
}
+171
View File
@@ -0,0 +1,171 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "servo.h"
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
#include <memory>
namespace stackchan::motion {
/**
* @brief
*
*/
class Motion {
public:
Motion(std::unique_ptr<Servo> yawServo, std::unique_ptr<Servo> pitchServo)
: _yaw_servo(std::move(yawServo)), _pitch_servo(std::move(pitchServo))
{
}
/**
* @brief
*
*/
void init();
/**
* @brief
*
*/
void update();
/**
* @brief Get yaw servo instance
*
* @return Servo&
*/
Servo& yawServo();
/**
* @brief Get pitch servo instance
*
* @return Servo&
*/
Servo& pitchServo();
/**
* @brief
*
* @param angle
*/
void moveYaw(int angle);
/**
* @brief
*
* @param angle
* @param speed (0-1000)
*/
void moveYawWithSpeed(int angle, int speed);
/**
* @brief
*
* @param angle
*/
void movePitch(int angle);
/**
* @brief
*
* @param angle
* @param speed (0-1000)
*/
void movePitchWithSpeed(int angle, int speed);
/**
* @brief
*
* @param yawAngle
* @param pitchAngle
*/
void move(int yawAngle, int pitchAngle);
/**
* @brief
*
* @param yawAngle
* @param pitchAngle
* @param speed (0-1000)
*/
void moveWithSpeed(int yawAngle, int pitchAngle, int speed);
/**
* @brief Move head to home position (0,0)
*
* @param speed (0-1000)
*/
void goHome(int speed = 500);
/**
* @brief Stop head movement
*
*/
void stop();
/**
* @brief Moves the head using normalized coordinates ranging from -1.0 to 1.0.
*
* This method maps a proportional input to the full physical range of the servos.
* It is ideal for visual tracking (e.g., centering a face in a camera frame)
* or joystick-based control.
*
* Mapping Logic:
* - X-axis (Yaw): -1.0 (Max Left) <---> 1.0 (Max Right). 0.0 is center.
* - Y-axis (Pitch): -1.0 (Max Down) <---> 1.0 (Max Up). 0.0 is the midpoint of the pitch range.
*
* @param x Normalized horizontal value [-1.0, 1.0].
* @param y Normalized vertical value [-1.0, 1.0].
* @param speed Movement speed from 0 to 1000.
*
* @note The actual angles are calculated based on the servo's `getAngleLimit()`.
* For example, if Pitch range is 0 to 900, y = -1.0 maps to 0 and y = 1.0 maps to 900.
*/
void lookAtNormalized(float x, float y, int speed = 500);
/**
* @brief Directs the head to look at a target point in 3D Cartesian space.
*
* This method performs Inverse Kinematics (IK) to convert 3D coordinates
* into Yaw and Pitch angles. It assumes the head rotation center is at (0,0,0).
*
* Coordinate System (Right-Handed):
* - X-axis: Forward (positive is in front of the robot).
* - Y-axis: Lateral (positive is to the left, negative is to the right).
* - Z-axis: Vertical (positive is up, negative is down).
*
* @param x The forward distance from the rotation center (usually in mm).
* @param y The lateral distance; positive values move the head left (usually in mm).
* @param z The vertical distance; positive values move the head up (usually in mm).
* @param speed The movement speed, ranging from 0 (slowest) to 1000 (fastest).
*
* @note If the target point is at (0,0,0), the behavior is undefined (mathematical singularity).
*/
void lookAtPoint(float x, float y, float z, int speed = 500);
bool isMoving();
uitk::Vector2i getCurrentAngles();
int getCurrentYawAngle();
int getCurrentPitchAngle();
void setTorqueEnabled(bool enabled);
void setAutoTorqueReleaseEnabled(bool enabled);
void setAutoAngleSyncEnabled(bool enabled);
private:
std::unique_ptr<Servo> _yaw_servo;
std::unique_ptr<Servo> _pitch_servo;
static constexpr float RAD_TO_DEG = 180.0f / M_PI;
inline float to_degrees(float radians)
{
return radians * RAD_TO_DEG;
}
};
} // namespace stackchan::motion
+149
View File
@@ -0,0 +1,149 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "servo.h"
#include <hal/hal.h>
using namespace uitk;
namespace stackchan::motion {
static SpringOptions_t _default_spring_options = {
.stiffness = 170.0,
.damping = 26.0,
.mass = 1.0,
.velocity = 0.0,
.restSpeed = 0.1,
.restDelta = 0.1,
.duration = 0.0,
.bounce = 0.0,
.visualDuration = 0.0,
};
void Servo::init()
{
apply_default_spring_options();
_angle_anim.teleport(getCurrentAngle());
update();
setTorqueEnabled(false);
}
void Servo::update()
{
// Update at 50Hz
if (GetHAL().millis() - _last_tick < 20) {
return;
}
_last_tick = GetHAL().millis();
// Apply animation
if (!_angle_anim.done()) {
_angle_anim.update();
set_angle_impl(static_cast<int>(_angle_anim.directValue()));
}
// Snap to target angle when animation ends
else if (_snap_to_target_on_rest) {
_snap_to_target_on_rest = false;
set_angle_impl(_angle_anim.end);
}
// Auto release torque on rest
else if (_auto_torque_release_enabled && !isMoving()) {
if (GetHAL().millis() - _last_torque_check_tick > 200) {
if (getTorqueEnabled()) {
setTorqueEnabled(false);
}
_last_torque_check_tick = GetHAL().millis();
}
}
}
void Servo::move(int angle)
{
apply_default_spring_options();
update_angle_anim_target(angle);
}
void Servo::moveWithSpringParams(int angle, float stiffness, float damping)
{
_angle_anim.springOptions().visualDuration = 0.0f; // Disable timing override
_angle_anim.springOptions().stiffness = stiffness;
_angle_anim.springOptions().damping = damping;
update_angle_anim_target(angle);
}
void Servo::moveWithSpeed(int angle, int speed)
{
auto spring_options = map_speed_to_spring_options(speed);
moveWithSpringParams(angle, spring_options.stiffness, spring_options.damping);
}
int Servo::getCurrentAngle()
{
return _angle_anim.directValue();
}
void Servo::apply_default_spring_options()
{
auto& options = _angle_anim.springOptions();
options.visualDuration = 0.0f; // Disable timing override
options.stiffness = _default_spring_options.stiffness;
options.damping = _default_spring_options.damping;
}
void Servo::update_angle_anim_target(int angle)
{
if (_auto_angle_sync_enabled) {
_angle_anim.teleport(getCurrentAngle()); // Use current angle as start
}
_angle_anim = angle; // Apply new target
_snap_to_target_on_rest = true;
}
uitk::SpringOptions_t Servo::map_speed_to_spring_options(int speed)
{
speed = uitk::clamp(speed, 0, 1000);
// 1. 计算 Stiffness (刚度)
// 使用二次方映射: k = k_min + (speed/1000)^2 * k_range
// 当 speed=500 时,k 约为 10 + 0.25 * 640 = 170
float k_min = 10.0f;
float k_max = 650.0f;
float normalizedSpeed = speed / 1000.0f;
float stiffness = k_min + (normalizedSpeed * normalizedSpeed) * (k_max - k_min);
// 2. 计算 Damping (阻尼)
// 为了保持临界阻尼(无过冲,最快稳定),公式为 d = 2 * sqrt(m * k)
// 如果想要带一点点弹性感(bounce),可以将系数从 2.0 降到 1.5~1.8
float mass = 1.0f;
float damping = 2.0f * sqrtf(mass * stiffness);
// 3. 构造选项
uitk::SpringOptions_t options = _default_spring_options;
options.stiffness = stiffness;
options.damping = damping;
options.mass = mass;
// 4. 动态调整静止阈值
// 高速时阈值大一点可以防止由于离散计算导致的微小抖动
if (speed > 800) {
options.restDelta = 0.5f;
options.restSpeed = 0.5f;
} else {
options.restDelta = 0.1f;
options.restSpeed = 0.1f;
}
return options;
}
} // namespace stackchan::motion
+174
View File
@@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <smooth_ui_toolkit.hpp>
#include <uitk/short_namespace.hpp>
#include <cstdint>
namespace stackchan::motion {
/**
* @brief
*
*/
class Servo {
public:
virtual ~Servo() = default;
/**
* @brief
*
*/
virtual void init();
/**
* @brief
*
*/
virtual void update();
/**
* @brief Move to angle
*
* @param angle
*/
void move(int angle);
/**
* @brief Move to angle with custom spring params
*
* @param angle
* @param stiffness
* @param damping
*/
void moveWithSpringParams(int angle, float stiffness = 170.0f, float damping = 26.0f);
/**
* @brief Move to angle with speed mapping
*
* @param angle
* @param speed (0-1000)
*/
void moveWithSpeed(int angle, int speed);
/**
* @brief Rotate servo with given velocity
*
* @param velocity (-1000, 1000)
*/
virtual void rotate(int velocity)
{
}
/**
* @brief Get servo current angle
*
* @return int
*/
virtual int getCurrentAngle();
/**
* @brief
*
* @return uitk::Vector2i
*/
virtual uitk::Vector2i getAngleLimit() const
{
return _angle_limit;
}
/**
* @brief
*
* @return true
* @return false
*/
virtual bool isMoving()
{
return false;
}
/**
* @brief
*
* @param enabled
*/
virtual void setTorqueEnabled(bool enabled)
{
}
virtual bool getTorqueEnabled()
{
return false;
}
/**
* @brief Auto release torque on rest
*
* @param enabled
*/
void setAutoTorqueReleaseEnabled(bool enabled)
{
_auto_torque_release_enabled = enabled;
}
/**
* @brief Enables or disables automatic synchronization of the animation start point
* with the current physical angle.
*
* @param enabled
* - If true: Prevents sudden "jumps" when the servo is moved manually by
* external forces, but may cause stuttering during high-frequency updates
* as it resets the animation's velocity.
* - If false: Maintains animation momentum and velocity for smooth,
* continuous motion, but may cause a "snap" if the actual angle differs
* significantly from the internal state.
*/
void setAutoAngleSyncEnabled(bool enabled)
{
_auto_angle_sync_enabled = enabled;
}
/**
* @brief
*
*/
virtual void setCurrentAngleAsZero()
{
}
protected:
Servo()
{
}
void set_angle_limit(uitk::Vector2i angleLimit)
{
_angle_limit = angleLimit;
}
/**
* @brief Servo set angle implementation
*
* @param angle
*/
virtual void set_angle_impl(int angle) = 0;
private:
uitk::Vector2i _angle_limit;
uitk::AnimateValue _angle_anim;
uint32_t _last_tick = 0;
uint32_t _last_torque_check_tick = 0;
bool _snap_to_target_on_rest = false;
bool _auto_torque_release_enabled = true;
bool _auto_angle_sync_enabled = true;
void apply_default_spring_options();
void update_angle_anim_target(int angle);
uitk::SpringOptions_t map_speed_to_spring_options(int speed);
};
} // namespace stackchan::motion
+12
View File
@@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#include "stackchan.h"
stackchan::StackChan& GetStackChan()
{
static stackchan::StackChan stackchan;
return stackchan;
}
+180
View File
@@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "modifiable.h"
#include "modifiers/modifiers.h"
#include "json/json_helper.h"
#include <memory>
namespace stackchan {
/**
* @brief
*
*/
class StackChan : public Modifiable {
public:
/**
* @brief Attach motion instance
*
* @param yawServo
* @param pitchServo
*/
void attachMotion(std::unique_ptr<motion::Motion> motion)
{
_motion = std::move(motion);
}
/**
* @brief Reset and destroy attached motion instance
*
*/
void resetMotion()
{
_motion.reset();
}
/**
* @brief Attach avatar instance
*
* @param avatar
*/
void attachAvatar(std::unique_ptr<avatar::Avatar> avatar)
{
_avatar = std::move(avatar);
}
/**
* @brief Reset and destroy attached avatar instance
*
*/
void resetAvatar()
{
_avatar.reset();
}
/**
* @brief Get motion instance
*
* @return motion::Motion&
*/
motion::Motion& motion() override
{
return *_motion;
}
/**
* @brief Get avatar instance
*
* @return avatar::Avatar&
*/
avatar::Avatar& avatar() override
{
return *_avatar;
}
/**
* @brief Check if avatar is attached
*
* @return true
* @return false
*/
bool hasAvatar() override
{
if (_avatar) {
return true;
}
return false;
}
/**
* @brief Check if motion is attached
*
* @return true
* @return false
*/
bool hasMotion()
{
if (_motion) {
return true;
}
return false;
}
/**
* @brief Add modifier
*
* @param modifier
* @return int
*/
int addModifier(std::unique_ptr<Modifier> modifier)
{
return _modifier_pool.create(std::move(modifier));
}
Modifier* getModifier(int id)
{
return _modifier_pool.get(id);
}
bool removeModifier(int id)
{
return _modifier_pool.destroy(id);
}
void clearModifiers()
{
_modifier_pool.clear();
}
/**
* @brief Update
*
*/
void update()
{
_modifier_pool.forEach([this](Modifier* modifier, int id) { modifier->_update(*this); });
_modifier_pool.cleanup();
if (_avatar) {
_avatar->update();
}
if (_motion) {
_motion->update();
}
}
/**
* @brief
*
* @param jsonContent
*/
void updateAvatarFromJson(const char* jsonContent)
{
if (_avatar) {
avatar::update_from_json(_avatar.get(), jsonContent);
}
}
/**
* @brief
*
* @param jsonContent
*/
void updateMotionFromJson(const char* jsonContent)
{
if (_motion) {
motion::update_from_json(_motion.get(), jsonContent);
}
}
private:
std::unique_ptr<avatar::Avatar> _avatar;
std::unique_ptr<motion::Motion> _motion;
ObjectPool<Modifier> _modifier_pool;
};
} // namespace stackchan
stackchan::StackChan& GetStackChan();
+289
View File
@@ -0,0 +1,289 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <vector>
#include <memory>
#include <functional>
namespace stackchan {
class Poolable {
public:
virtual ~Poolable() = default;
// 标记对象需要销毁。
// 通常由对象自身调用(例如,在其 Update 方法内部)。
void requestDestroy()
{
_destroy_requested = true;
}
bool isDestroyRequested() const
{
return _destroy_requested;
}
private:
bool _destroy_requested = false;
};
/**
* @brief 通用对象池
* 适用于不在乎最大容量,更关注对象自身生命周期管理的场景。
*
* @tparam T
*/
template <typename T>
class ObjectPool {
public:
/**
* @brief 创建一个新对象并返回其 ID。
* 使用空闲列表策略实现 O(1) 插入。
*
* @param obj 对象实例的唯一指针
* @return int 分配的对象 ID (索引)
*/
int create(std::unique_ptr<T> obj)
{
// 1. 如果有空闲槽位,重用它
if (!_free_indices.empty()) {
int id = _free_indices.back();
_free_indices.pop_back();
_objs[id] = std::move(obj);
return id;
}
// 2. 没有空闲槽位,追加到末尾
_objs.push_back(std::move(obj));
return (int)_objs.size() - 1;
}
/**
* @brief 通过 ID 获取对象实例。
*
* @param id 对象 ID
* @return T* 对象指针,如果无效或为空则返回 nullptr
*/
T* get(int id)
{
if (id < 0 || id >= (int)_objs.size()) {
return nullptr;
}
return static_cast<T*>(_objs[id].get());
}
/**
* @brief 遍历所有活跃对象。
*
* @param func 接收 (Object*, ID) 的回调函数
*/
void forEach(const std::function<void(T*, int)>& func)
{
for (int i = 0; i < (int)_objs.size(); ++i) {
if (_objs[i]) {
func(static_cast<T*>(_objs[i].get()), i);
}
}
}
/**
* @brief Poolable 的主要适配方法:
* 检查所有对象,看它们是否请求了销毁。
* 应该每帧调用一次(例如,在游戏循环结束时)。
*/
void cleanup()
{
for (int i = 0; i < (int)_objs.size(); ++i) {
// 如果对象存在且请求了销毁
if (_objs[i] && _objs[i]->isDestroyRequested()) {
destroy(i);
}
}
}
/**
* @brief 通过 ID 销毁对象并释放槽位。
*
* @param id 对象 ID
* @return true 如果成功销毁,false 如果无效或已经为空
*/
bool destroy(int id)
{
if (id < 0 || id >= (int)_objs.size()) {
return false;
}
// 防止重复释放
if (!_objs[id]) {
return false;
}
// 释放内存
_objs[id].reset();
// 将此 ID 添加到空闲列表以便立即重用
_free_indices.push_back(id);
return true;
}
/**
* @brief 清除所有对象并重置池。
*/
void clear()
{
_objs.clear();
_free_indices.clear();
}
/**
* @brief 获取总容量(最大索引 + 1)。
* 注意:这包括空槽位(空洞)。
*
* @return size_t
*/
size_t size()
{
return _objs.size();
}
/**
* @brief 获取实际活跃对象的数量。
*
* @return size_t
*/
size_t activeCount()
{
return _objs.size() - _free_indices.size();
}
private:
std::vector<std::unique_ptr<Poolable>> _objs;
std::vector<int> _free_indices;
};
/**
* @brief 环形对象池
* 适用于大量对象并限定数量的场景(定长)。
* 当池满时,新对象会自动覆盖最旧的对象。
*
* @tparam T
*/
template <typename T>
class RingObjectPool {
public:
/**
* @brief
* @param capacity 池子的最大容量
*/
explicit RingObjectPool(size_t capacity) : _capacity(capacity), _cursor(0)
{
// 预先分配好所有槽位,全是 nullptr
_objs.resize(capacity);
}
/**
* @brief 创建/生成一个新对象。
* 如果当前槽位已有对象,该旧对象会被立即析构(覆盖)。
*
* @param obj 新对象的唯一指针
* @return int 分配的 ID (索引)
*/
int create(std::unique_ptr<T> obj)
{
int id = _cursor;
// 如果该位置已有对象,unique_ptr 的赋值操作会自动析构旧对象
// 这一步实现了 "自动顶替最旧数据"
_objs[id] = std::move(obj);
// 移动游标,如果超过容量则回到 0
_cursor = (_cursor + 1) % _capacity;
return id;
}
/**
* @brief 通过 ID 获取对象
* 注意:在环形池中,如果你持有 ID 太久,该 ID 对应的内容可能已经被新对象覆盖。
*
* @param id 对象索引
* @return T* 对象指针,如果是空槽位则返回 nullptr
*/
T* get(int id)
{
if (id < 0 || id >= (int)_objs.size()) {
return nullptr;
}
return _objs[id].get();
}
/**
* @brief 遍历所有活跃的对象
* 会自动跳过空槽位 (nullptr)
*/
void forEach(const std::function<void(T*, int)>& func)
{
for (int i = 0; i < (int)_objs.size(); ++i) {
if (_objs[i]) {
func(_objs[i].get(), i);
}
}
}
/**
* @brief 清理主动请求销毁的对象。
* 针对那些还没轮到被覆盖,但逻辑上已经结束的对象(比如血量归零的敌人)。
*/
void cleanup()
{
for (auto& ptr : _objs) {
// 如果对象存在,且请求了销毁
if (ptr && ptr->isDestroyRequested()) {
ptr.reset(); // 释放内存,变为空槽位 (nullptr)
}
}
}
/**
* @brief 获取总容量
*/
size_t capacity() const
{
return _capacity;
}
/**
* @brief 获取当前实际存活的对象数量
*/
size_t activeCount() const
{
size_t count = 0;
for (const auto& ptr : _objs) {
if (ptr) count++;
}
return count;
}
/**
* @brief 强制清空整个池子
*/
void clear()
{
for (auto& ptr : _objs) {
ptr.reset();
}
_cursor = 0; // 重置游标
}
private:
std::vector<std::unique_ptr<T>> _objs;
size_t _capacity;
int _cursor; // 当前写入位置的指针
};
} // namespace stackchan
+77
View File
@@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <mutex>
#include <random>
#include <vector>
#include <cassert>
#ifdef ESP_PLATFORM
#include <esp_random.h>
#endif
namespace stackchan {
class Random {
public:
static Random& getInstance()
{
static Random instance;
return instance;
}
int getInt(int a, int b)
{
std::lock_guard<std::mutex> lock(_mutex);
if (a > b) {
std::swap(a, b);
}
return std::uniform_int_distribution<int>{a, b}(_rng);
}
float getFloat(float a, float b)
{
std::lock_guard<std::mutex> lock(_mutex);
if (a > b) {
std::swap(a, b);
}
return std::uniform_real_distribution<float>{a, b}(_rng);
}
double getDouble(double a, double b)
{
std::lock_guard<std::mutex> lock(_mutex);
if (a > b) {
std::swap(a, b);
}
return std::uniform_real_distribution<double>{a, b}(_rng);
}
template <typename T>
const T& choice(const std::vector<T>& vec)
{
assert(!vec.empty());
std::lock_guard<std::mutex> lock(_mutex);
std::uniform_int_distribution<size_t> dist(0, vec.size() - 1);
return vec[dist(_rng)];
}
private:
std::mt19937 _rng;
std::mutex _mutex;
Random()
{
#ifdef ESP_PLATFORM
_rng.seed(esp_random());
#else
std::random_device rd;
_rng.seed(rd());
#endif
}
};
} // namespace stackchan
+165
View File
@@ -0,0 +1,165 @@
/*
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <hal/hal.h>
#include <functional>
#include <vector>
namespace stackchan {
class Timer {
public:
using Callback = std::function<void(void)>;
struct Task {
uint32_t intervalMs; // Time interval between executions (ms)
uint32_t lastTick; // Last tick recorded
uint32_t delayMs; // Delay before first execution (ms)
int repeatCount; // Remaining repeat count (-1 = infinite)
Callback callback; // Task callback function
bool enabled; // Enabled or disabled
bool started; // Has delay finished and started interval execution?
};
/**
* @brief Register a new task
* @param intervalMs Execution interval in milliseconds
* @param repeatCount Times to execute (-1 = infinite loop)
* @param delayMs Delay before the first execution (ms)
* @param cb Callback function
* @param start Whether to start immediately
* @return Task ID
*/
int addTask(uint32_t intervalMs, int repeatCount, uint32_t delayMs, Callback cb, bool start = true)
{
int id = -1;
if (!_free_indices.empty()) {
id = _free_indices.back();
_free_indices.pop_back();
} else {
id = (int)_tasks.size();
_tasks.push_back(Task());
}
Task& t = _tasks[id];
t.intervalMs = intervalMs;
t.repeatCount = repeatCount;
t.delayMs = delayMs;
t.callback = cb;
t.enabled = start;
t.started = false;
t.lastTick = GetHAL().millis();
return id;
}
void setInterval(int id, uint32_t intervalMs)
{
if (is_valid(id)) {
_tasks[id].intervalMs = intervalMs;
}
}
void setRepeat(int id, int repeatCount)
{
if (is_valid(id)) {
_tasks[id].repeatCount = repeatCount;
}
}
void setDelay(int id, uint32_t delayMs)
{
if (is_valid(id)) {
_tasks[id].delayMs = delayMs;
}
}
void enable(int id)
{
if (is_valid(id)) {
_tasks[id].enabled = true;
}
}
void disable(int id)
{
if (is_valid(id)) {
_tasks[id].enabled = false;
}
}
/**
* @brief Remove task and recycle its ID
*/
void remove(int id)
{
if (is_valid(id)) {
_tasks[id] = Task(); // Reset content
_tasks[id].enabled = false;
_tasks[id].callback = nullptr;
_free_indices.push_back(id); // Recycle index
}
}
/**
* @brief MUST be called periodically in your main loop
*/
void update()
{
uint32_t now = GetHAL().millis();
for (int i = 0; i < (int)_tasks.size(); i++) {
Task& t = _tasks[i];
if (!t.enabled) {
continue;
}
if (!t.callback) {
continue;
}
// Handle delay start
if (!t.started) {
if ((now - t.lastTick) >= t.delayMs) {
t.started = true;
t.lastTick = now;
} else {
continue;
}
}
// Handle interval execution
if ((now - t.lastTick) >= t.intervalMs) {
t.lastTick = now;
t.callback();
if (t.repeatCount > 0) {
t.repeatCount--;
if (t.repeatCount == 0) {
t.enabled = false;
}
}
}
}
}
private:
bool is_valid(int id)
{
if (id < 0) {
return false;
}
if (id >= (int)_tasks.size()) {
return false;
}
return true;
}
std::vector<Task> _tasks;
std::vector<int> _free_indices;
};
} // namespace stackchan