From b08e5bba8c32cddc24e41092777a09bdcdcf1458 Mon Sep 17 00:00:00 2001 From: botamochi6277 Date: Sun, 14 Apr 2024 23:50:57 +0900 Subject: [PATCH 1/4] Add LR eye open ratio --- src/Avatar.cpp | 149 +++++++++++++++++++++++++++---------------------- src/Avatar.h | 32 +++++++---- 2 files changed, 104 insertions(+), 77 deletions(-) diff --git a/src/Avatar.cpp b/src/Avatar.cpp index 4e98a45..3cbc334 100644 --- a/src/Avatar.cpp +++ b/src/Avatar.cpp @@ -23,12 +23,10 @@ unsigned int seed = 0; #ifdef SDL_h_ #define TaskResult() return 0 #define TaskDelay(ms) lgfx::delay(ms) -long random(long howbig) { - return std::rand() % howbig; -} +long random(long howbig) { return std::rand() % howbig; } #else #define TaskResult() vTaskDelete(NULL) -#define TaskDelay(ms) vTaskDelay(ms/portTICK_PERIOD_MS) +#define TaskDelay(ms) vTaskDelay(ms / portTICK_PERIOD_MS) #endif // TODO(meganetaaan): make read-only @@ -51,7 +49,7 @@ TaskResult_t drawLoop(void *args) { } TaskResult_t facialLoop(void *args) { - int c = 0; + int count = 0; DriveContext *ctx = reinterpret_cast(args); Avatar *avatar = ctx->getAvatar(); uint32_t saccade_interval = 1000; @@ -64,7 +62,6 @@ TaskResult_t facialLoop(void *args) { float breath = 0.0f; init_rand(); while (avatar->isDrawing()) { - if ((lgfx::millis() - last_saccade_millis) > saccade_interval) { vertical = _rand() / (RAND_MAX / 2.0) - 1; horizontal = _rand() / (RAND_MAX / 2.0) - 1; @@ -73,21 +70,24 @@ TaskResult_t facialLoop(void *args) { last_saccade_millis = lgfx::millis(); } - if ((lgfx::millis()- last_blink_millis) > blink_interval) { - if (eye_open) { - avatar->setEyeOpenRatio(1); - blink_interval = 2500 + 100 * random(20); - } else { - avatar->setEyeOpenRatio(0); - blink_interval = 300 + 10 * random(20); + if (avatar->getIsAutoBlink()) { + /* code */ if ((lgfx::millis() - last_blink_millis) > blink_interval) { + if (eye_open) { + avatar->setEyeOpenRatio(1.0f); + blink_interval = 2500 + 100 * random(20); + } else { + avatar->setEyeOpenRatio(0.0f); + blink_interval = 300 + 10 * random(20); + } + eye_open = !eye_open; + last_blink_millis = lgfx::millis(); } - eye_open = !eye_open; - last_blink_millis = lgfx::millis(); } - c = (c + 1) % 100; - breath = sin(c * 2 * PI / 100.0); + + count = (count + 1) % 100; + breath = sin(count * 2 * PI / 100.0); avatar->setBreath(breath); - TaskDelay(33); + TaskDelay(33); // approx. 30fps } TaskResult(); } @@ -99,7 +99,9 @@ Avatar::Avatar(Face *face) _isDrawing{false}, expression{Expression::Neutral}, breath{0}, - eyeOpenRatio{1}, + leftEyeOpenRatio_{1}, + rightEyeOpenRatio_{1}, + isAutoBlink_{true}, mouthOpenRatio{0}, gazeV{0}, gazeH{0}, @@ -108,22 +110,18 @@ Avatar::Avatar(Face *face) palette{ColorPalette()}, speechText{""}, colorDepth{1}, - batteryIconStatus{BatteryIconStatus::invisible}{} + batteryIconStatus{BatteryIconStatus::invisible} {} -Avatar::~Avatar() { - delete face; -} +Avatar::~Avatar() { delete face; } void Avatar::setFace(Face *face) { this->face = face; } Face *Avatar::getFace() const { return face; } -void Avatar::addTask(TaskFunction_t f - , const char* name - , const uint32_t stack_size - , UBaseType_t priority - , TaskHandle_t* const task_handle - , const BaseType_t core_id) { +void Avatar::addTask(TaskFunction_t f, const char *name, + const uint32_t stack_size, UBaseType_t priority, + TaskHandle_t *const task_handle, + const BaseType_t core_id) { DriveContext *ctx = new DriveContext(this); #ifdef SDL_h_ if (task_handle == NULL) { @@ -133,13 +131,13 @@ void Avatar::addTask(TaskFunction_t f } #else // TODO(meganetaaan): set a task handler - xTaskCreateUniversal(f, /* Function to implement the task */ - name, /* Name of the task */ - stack_size, /* Stack size in words */ - ctx, /* Task input parameter */ - priority, /* Priority of the task */ - task_handle, /* Task handle. */ - core_id); /* Core No*/ + xTaskCreateUniversal(f, /* Function to implement the task */ + name, /* Name of the task */ + stack_size, /* Stack size in words */ + ctx, /* Task input parameter */ + priority, /* Priority of the task */ + task_handle, /* Task handle. */ + core_id); /* Core No*/ #endif } @@ -162,7 +160,7 @@ void Avatar::resume() { #endif } -void Avatar::start(int colorDepth) { +void Avatar::start(int colorDepth) { // if the task already started, don't create another task; if (_isDrawing) return; _isDrawing = true; @@ -170,34 +168,37 @@ void Avatar::start(int colorDepth) { this->colorDepth = colorDepth; DriveContext *ctx = new DriveContext(this); #ifdef SDL_h_ - drawTaskHandle = SDL_CreateThreadWithStackSize(drawLoop, "drawLoop", 2048, ctx); + drawTaskHandle = + SDL_CreateThreadWithStackSize(drawLoop, "drawLoop", 2048, ctx); SDL_CreateThreadWithStackSize(facialLoop, "facialLoop", 1024, ctx); #else // TODO(meganetaaan): keep handle of these tasks - xTaskCreateUniversal(drawLoop, /* Function to implement the task */ - "drawLoop", /* Name of the task */ - 2048, /* Stack size in words */ - ctx, /* Task input parameter */ - 1, /* Priority of the task */ - &drawTaskHandle, /* Task handle. */ - APP_CPU_NUM); - - xTaskCreateUniversal(facialLoop, /* Function to implement the task */ - "facialLoop", /* Name of the task */ - 1024, /* Stack size in words */ - ctx, /* Task input parameter */ - 2, /* Priority of the task */ - NULL, /* Task handle. */ - APP_CPU_NUM); + xTaskCreateUniversal(drawLoop, /* Function to implement the task */ + "drawLoop", /* Name of the task */ + 2048, /* Stack size in words */ + ctx, /* Task input parameter */ + 1, /* Priority of the task */ + &drawTaskHandle, /* Task handle. */ + APP_CPU_NUM); + + xTaskCreateUniversal(facialLoop, /* Function to implement the task */ + "facialLoop", /* Name of the task */ + 1024, /* Stack size in words */ + ctx, /* Task input parameter */ + 2, /* Priority of the task */ + NULL, /* Task handle. */ + APP_CPU_NUM); #endif } void Avatar::draw() { Gaze g = Gaze(this->gazeV, this->gazeH); - DrawContext *ctx = new DrawContext(this->expression, this->breath, - &this->palette, g, this->eyeOpenRatio, - this->mouthOpenRatio, this->speechText, - this->rotation, this->scale, this->colorDepth, this->batteryIconStatus, this->batteryLevel, this->speechFont); + DrawContext *ctx = new DrawContext( + this->expression, this->breath, &this->palette, g, + 0.5f * this->leftEyeOpenRatio_ + 0.5f * this->rightEyeOpenRatio_, + this->mouthOpenRatio, this->speechText, this->rotation, this->scale, + this->colorDepth, this->batteryIconStatus, this->batteryLevel, + this->speechFont); face->draw(ctx); delete ctx; } @@ -210,15 +211,11 @@ void Avatar::setExpression(Expression expression) { resume(); } -Expression Avatar::getExpression() { - return this->expression; -} +Expression Avatar::getExpression() { return this->expression; } void Avatar::setBreath(float breath) { this->breath = breath; } -float Avatar::getBreath() { - return this->breath; -} +float Avatar::getBreath() { return this->breath; } void Avatar::setRotation(float radian) { this->rotation = radian; } @@ -234,7 +231,26 @@ ColorPalette Avatar::getColorPalette(void) const { return this->palette; } void Avatar::setMouthOpenRatio(float ratio) { this->mouthOpenRatio = ratio; } -void Avatar::setEyeOpenRatio(float ratio) { this->eyeOpenRatio = ratio; } +void Avatar::setEyeOpenRatio(float ratio) { + setLeftEyeOpenRatio(ratio); + setRightEyeOpenRatio(ratio); +} + +void Avatar::setLeftEyeOpenRatio(float ratio) { + this->leftEyeOpenRatio_ = ratio; +} + +float Avatar::getLeftEyeOpenRatio() { return this->leftEyeOpenRatio_; } + +void Avatar::setRightEyeOpenRatio(float ratio) { + this->rightEyeOpenRatio_ = ratio; +} + +float Avatar::getRightEyeOpenRatio() { return this->rightEyeOpenRatio_; } + +void Avatar::setIsAutoBlink(bool b) { this->isAutoBlink_ = b; } + +bool Avatar::getIsAutoBlink() { return this->isAutoBlink_; } void Avatar::setGaze(float vertical, float horizontal) { this->gazeV = vertical; @@ -243,7 +259,7 @@ void Avatar::setGaze(float vertical, float horizontal) { void Avatar::getGaze(float *vertical, float *horizontal) { *vertical = this->gazeV; - *horizontal = this->gazeH; + *horizontal = this->gazeH; } void Avatar::setSpeechText(const char *speechText) { @@ -267,11 +283,10 @@ void Avatar::setBatteryStatus(bool isCharging, int32_t batteryLevel) { if (isCharging) { this->batteryIconStatus = BatteryIconStatus::charging; } else { - this->batteryIconStatus = BatteryIconStatus::discharging; + this->batteryIconStatus = BatteryIconStatus::discharging; } this->batteryLevel = batteryLevel; } - } } // namespace m5avatar diff --git a/src/Avatar.h b/src/Avatar.h index 2453f8d..5a908ce 100644 --- a/src/Avatar.h +++ b/src/Avatar.h @@ -4,15 +4,16 @@ #ifndef AVATAR_H_ #define AVATAR_H_ +#include + #include "ColorPalette.h" #include "Face.h" -#include #ifdef SDL_h_ typedef SDL_ThreadFunction TaskFunction_t; typedef int BaseType_t; typedef unsigned int UBaseType_t; -typedef SDL_Thread* TaskHandle_t; +typedef SDL_Thread *TaskHandle_t; typedef int TaskResult_t; #define APP_CPU_NUM (1) #else @@ -35,7 +36,13 @@ class Avatar { bool _isDrawing; Expression expression; float breath; - float eyeOpenRatio; + + // eyes variables + // float eyeOpenRatio; + float leftEyeOpenRatio_; + float rightEyeOpenRatio_; + bool isAutoBlink_; + float mouthOpenRatio; float gazeV; float gazeH; @@ -65,7 +72,15 @@ class Avatar { void setGaze(float vertical, float horizontal); void getGaze(float *vertical, float *horizontal); void setExpression(Expression exp); + // eyes functions void setEyeOpenRatio(float ratio); + void setLeftEyeOpenRatio(float ratio); + float getLeftEyeOpenRatio(); + void setRightEyeOpenRatio(float ratio); + float getRightEyeOpenRatio(); + void setIsAutoBlink(bool b); + bool getIsAutoBlink(); + void setMouthOpenRatio(float ratio); void setSpeechText(const char *speechText); void setSpeechFont(const lgfx::IFont *speechFont); @@ -76,19 +91,16 @@ class Avatar { bool isDrawing(); void start(int colorDepth = 1); void stop(); - void addTask(TaskFunction_t f - , const char* name - , const uint32_t stack_size=2048 - , UBaseType_t priority=4 - , TaskHandle_t* const task_handle=NULL - , const BaseType_t core_id=APP_CPU_NUM); + void addTask(TaskFunction_t f, const char *name, + const uint32_t stack_size = 2048, UBaseType_t priority = 4, + TaskHandle_t *const task_handle = NULL, + const BaseType_t core_id = APP_CPU_NUM); void suspend(); void resume(); void setBatteryIcon(bool iconStatus); void setBatteryStatus(bool isCharging, int32_t batteryLevel); }; - class DriveContext { private: // TODO(meganetaaan): cyclic reference From 29c580ae47e04ed48914226a80064b8f712807bb Mon Sep 17 00:00:00 2001 From: botamochi6277 Date: Sun, 14 Apr 2024 23:51:03 +0900 Subject: [PATCH 2/4] Add wink demo --- examples/wink-demo/wink-demo.ino | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 examples/wink-demo/wink-demo.ino diff --git a/examples/wink-demo/wink-demo.ino b/examples/wink-demo/wink-demo.ino new file mode 100644 index 0000000..64dec77 --- /dev/null +++ b/examples/wink-demo/wink-demo.ino @@ -0,0 +1,27 @@ +#include +#include + +m5avatar::Avatar avatar; + +void setup() { + M5.begin(); + avatar.init(); // start drawing +} + +void loop() { + M5.update(); + if (M5.BtnA.wasPressed()) { + // switch right eye + avatar.setRightEyeOpenRatio(avatar.getRightEyeOpenRatio() > 0.5f ? 0.0f + : 1.0f); + } + if (M5.BtnB.wasPressed()) { + avatar.setIsAutoBlink(!avatar.getIsAutoBlink()); + } + if (M5.BtnC.wasPressed()) { + // switch left eye + avatar.setLeftEyeOpenRatio(avatar.getLeftEyeOpenRatio() > 0.5f ? 0.0f + : 1.0f); + } + delay(10); +} From 4df0f0673a8925a0bbf9914b42058fbcb45418fc Mon Sep 17 00:00:00 2001 From: botamochi6277 Date: Wed, 17 Apr 2024 01:01:10 +0900 Subject: [PATCH 3/4] Add LR Gaze --- src/Avatar.cpp | 48 ++++++++++++++++++++++++++++++--------------- src/Avatar.h | 22 +++++++++++++-------- src/DrawContext.cpp | 45 ++++++++++++++++++++++++++++-------------- src/DrawContext.h | 39 ++++++++++++++++++++++++------------ src/Eye.cpp | 13 ++++++++---- 5 files changed, 112 insertions(+), 55 deletions(-) diff --git a/src/Avatar.cpp b/src/Avatar.cpp index 3cbc334..8e79bb9 100644 --- a/src/Avatar.cpp +++ b/src/Avatar.cpp @@ -39,6 +39,7 @@ TaskHandle_t drawTaskHandle; TaskResult_t drawLoop(void *args) { DriveContext *ctx = reinterpret_cast(args); Avatar *avatar = ctx->getAvatar(); + // update drawings in the display while (avatar->isDrawing()) { if (avatar->isDrawing()) { avatar->draw(); @@ -61,17 +62,19 @@ TaskResult_t facialLoop(void *args) { float horizontal = 0.0f; float breath = 0.0f; init_rand(); + // update facial internal state while (avatar->isDrawing()) { if ((lgfx::millis() - last_saccade_millis) > saccade_interval) { vertical = _rand() / (RAND_MAX / 2.0) - 1; horizontal = _rand() / (RAND_MAX / 2.0) - 1; - avatar->setGaze(vertical, horizontal); + avatar->setRightGaze(vertical, horizontal); + avatar->setLeftGaze(vertical, horizontal); saccade_interval = 500 + 100 * random(20); last_saccade_millis = lgfx::millis(); } if (avatar->getIsAutoBlink()) { - /* code */ if ((lgfx::millis() - last_blink_millis) > blink_interval) { + if ((lgfx::millis() - last_blink_millis) > blink_interval) { if (eye_open) { avatar->setEyeOpenRatio(1.0f); blink_interval = 2500 + 100 * random(20); @@ -99,12 +102,14 @@ Avatar::Avatar(Face *face) _isDrawing{false}, expression{Expression::Neutral}, breath{0}, - leftEyeOpenRatio_{1}, - rightEyeOpenRatio_{1}, + leftEyeOpenRatio_{1.0f}, + leftGazeH_{1.0f}, + leftGazeV_{1.0f}, + rightEyeOpenRatio_{1.0f}, + rightGazeH_{1.0f}, + rightGazeV_{1.0f}, isAutoBlink_{true}, mouthOpenRatio{0}, - gazeV{0}, - gazeH{0}, rotation{0}, scale{1}, palette{ColorPalette()}, @@ -192,10 +197,11 @@ void Avatar::start(int colorDepth) { } void Avatar::draw() { - Gaze g = Gaze(this->gazeV, this->gazeH); + Gaze rightGaze = Gaze(this->rightGazeV_, this->rightGazeV_); + Gaze leftGaze = Gaze(this->leftGazeV_, this->leftGazeH_); DrawContext *ctx = new DrawContext( - this->expression, this->breath, &this->palette, g, - 0.5f * this->leftEyeOpenRatio_ + 0.5f * this->rightEyeOpenRatio_, + this->expression, this->breath, &this->palette, rightGaze, + this->rightEyeOpenRatio_, leftGaze, this->leftEyeOpenRatio_, this->mouthOpenRatio, this->speechText, this->rotation, this->scale, this->colorDepth, this->batteryIconStatus, this->batteryLevel, this->speechFont); @@ -232,8 +238,8 @@ ColorPalette Avatar::getColorPalette(void) const { return this->palette; } void Avatar::setMouthOpenRatio(float ratio) { this->mouthOpenRatio = ratio; } void Avatar::setEyeOpenRatio(float ratio) { - setLeftEyeOpenRatio(ratio); setRightEyeOpenRatio(ratio); + setLeftEyeOpenRatio(ratio); } void Avatar::setLeftEyeOpenRatio(float ratio) { @@ -252,14 +258,24 @@ void Avatar::setIsAutoBlink(bool b) { this->isAutoBlink_ = b; } bool Avatar::getIsAutoBlink() { return this->isAutoBlink_; } -void Avatar::setGaze(float vertical, float horizontal) { - this->gazeV = vertical; - this->gazeH = horizontal; +void Avatar::setRightGaze(float vertical, float horizontal) { + this->rightGazeV_ = vertical; + this->rightGazeH_ = horizontal; +} + +void Avatar::getRightGaze(float *vertical, float *horizontal) { + *vertical = this->rightGazeV_; + *horizontal = this->rightGazeH_; +} + +void Avatar::setLeftGaze(float vertical, float horizontal) { + this->leftGazeV_ = vertical; + this->leftGazeH_ = horizontal; } -void Avatar::getGaze(float *vertical, float *horizontal) { - *vertical = this->gazeV; - *horizontal = this->gazeH; +void Avatar::getLeftGaze(float *vertical, float *horizontal) { + *vertical = this->leftGazeV_; + *horizontal = this->leftGazeH_; } void Avatar::setSpeechText(const char *speechText) { diff --git a/src/Avatar.h b/src/Avatar.h index 5a908ce..fb695ae 100644 --- a/src/Avatar.h +++ b/src/Avatar.h @@ -38,14 +38,18 @@ class Avatar { float breath; // eyes variables - // float eyeOpenRatio; - float leftEyeOpenRatio_; float rightEyeOpenRatio_; + float rightGazeV_; + float rightGazeH_; + + float leftEyeOpenRatio_; + float leftGazeV_; + float leftGazeH_; + bool isAutoBlink_; float mouthOpenRatio; - float gazeV; - float gazeH; + float rotation; float scale; ColorPalette palette; @@ -69,15 +73,17 @@ class Avatar { Expression getExpression(); void setBreath(float f); float getBreath(); - void setGaze(float vertical, float horizontal); - void getGaze(float *vertical, float *horizontal); + void setRightGaze(float vertical, float horizontal); + void getRightGaze(float *vertical, float *horizontal); + void setLeftGaze(float vertical, float horizontal); + void getLeftGaze(float *vertical, float *horizontal); void setExpression(Expression exp); // eyes functions void setEyeOpenRatio(float ratio); - void setLeftEyeOpenRatio(float ratio); - float getLeftEyeOpenRatio(); void setRightEyeOpenRatio(float ratio); float getRightEyeOpenRatio(); + void setLeftEyeOpenRatio(float ratio); + float getLeftEyeOpenRatio(); void setIsAutoBlink(bool b); bool getIsAutoBlink(); diff --git a/src/DrawContext.cpp b/src/DrawContext.cpp index 528fd44..c8a476f 100644 --- a/src/DrawContext.cpp +++ b/src/DrawContext.cpp @@ -7,20 +7,29 @@ namespace m5avatar { // DrawContext DrawContext::DrawContext(Expression expression, float breath, - ColorPalette* const palette, Gaze gaze, - float eyeOpenRatio, float mouthOpenRatio, - String speechText, BatteryIconStatus batteryIcon, int32_t batteryLevel, const lgfx::IFont* speechFont) - : DrawContext(expression, breath, palette, gaze, eyeOpenRatio, mouthOpenRatio, speechText, 0, 1, 1, BatteryIconStatus::invisible, 0, speechFont){}; + ColorPalette* const palette, Gaze rightGaze, + float rightEyeOpenRatio, Gaze leftGaze, + float leftEyeOpenRatio, float mouthOpenRatio, + String speechText, BatteryIconStatus batteryIconStatus, + int32_t batteryLevel, const lgfx::IFont* speechFont) + : DrawContext(expression, breath, palette, rightGaze, rightEyeOpenRatio, + leftGaze, leftEyeOpenRatio, mouthOpenRatio, speechText, 0, 1, + 1, BatteryIconStatus::invisible, 0, speechFont){}; DrawContext::DrawContext(Expression expression, float breath, - ColorPalette* const palette, Gaze gaze, - float eyeOpenRatio, float mouthOpenRatio, - String speechText, float rotation, float scale, int colorDepth, BatteryIconStatus batteryIconStatus, int32_t batteryLevel, const lgfx::IFont* speechFont) + ColorPalette* const palette, Gaze rightGaze, + float rightEyeOpenRatio, Gaze leftGaze, + float leftEyeOpenRatio, float mouthOpenRatio, + String speechText, float rotation, float scale, + int colorDepth, BatteryIconStatus batteryIconStatus, + int32_t batteryLevel, const lgfx::IFont* speechFont) : expression{expression}, breath{breath}, - eyeOpenRatio{eyeOpenRatio}, + rightGaze{rightGaze}, + rightEyeOpenRatio{rightEyeOpenRatio}, + leftGaze{leftGaze}, + leftEyeOpenRatio{leftEyeOpenRatio}, mouthOpenRatio{mouthOpenRatio}, - gaze{gaze}, palette{palette}, speechText{speechText}, rotation{rotation}, @@ -28,13 +37,19 @@ DrawContext::DrawContext(Expression expression, float breath, colorDepth{colorDepth}, batteryIconStatus(batteryIconStatus), batteryLevel(batteryLevel), - speechFont{speechFont}{} + speechFont{speechFont} {} Expression DrawContext::getExpression() const { return expression; } float DrawContext::getMouthOpenRatio() const { return mouthOpenRatio; } -float DrawContext::getEyeOpenRatio() const { return eyeOpenRatio; } +Gaze DrawContext::getLeftGaze() const { return leftGaze; } + +float DrawContext::getLeftEyeOpenRatio() const { return leftEyeOpenRatio; } + +Gaze DrawContext::getRightGaze() const { return rightGaze; } + +float DrawContext::getRightEyeOpenRatio() const { return rightEyeOpenRatio; } float DrawContext::getBreath() const { return breath; } @@ -42,9 +57,7 @@ float DrawContext::getRotation() const { return rotation; } float DrawContext::getScale() const { return scale; } -String DrawContext::getspeechText() const { return speechText; } - -Gaze DrawContext::getGaze() const { return gaze; } +String DrawContext::getspeechText() const { return speechText; } ColorPalette* const DrawContext::getColorPalette() const { return palette; } @@ -52,7 +65,9 @@ int DrawContext::getColorDepth() const { return colorDepth; } const lgfx::IFont* DrawContext::getSpeechFont() const { return speechFont; } -BatteryIconStatus DrawContext::getBatteryIconStatus() const { return batteryIconStatus; } +BatteryIconStatus DrawContext::getBatteryIconStatus() const { + return batteryIconStatus; +} int32_t DrawContext::getBatteryLevel() const { return batteryLevel; } diff --git a/src/DrawContext.h b/src/DrawContext.h index 0e831ae..4606a43 100644 --- a/src/DrawContext.h +++ b/src/DrawContext.h @@ -7,10 +7,10 @@ #define ERACER_COLOR 0x0000 -#include "M5GFX.h" #include "ColorPalette.h" #include "Expression.h" #include "Gaze.h" +#include "M5GFX.h" #ifndef ARDUINO #include @@ -23,42 +23,57 @@ class DrawContext { private: Expression expression; float breath; - float eyeOpenRatio; + + // left eye + Gaze leftGaze; + float leftEyeOpenRatio; + // right eye + Gaze rightGaze; + float rightEyeOpenRatio; + float mouthOpenRatio; - Gaze gaze; - ColorPalette * const palette; + + ColorPalette* const palette; String speechText; float rotation = 0.0; float scale = 1.0; int colorDepth = 1; BatteryIconStatus batteryIconStatus = BatteryIconStatus::invisible; int32_t batteryLevel = 0; - const lgfx::IFont* speechFont = nullptr; // = &fonts::lgfxJapanGothicP_16; // = &fonts::efontCN_10; + const lgfx::IFont* speechFont = + nullptr; // = &fonts::lgfxJapanGothicP_16; // = &fonts::efontCN_10; public: DrawContext() = delete; DrawContext(Expression expression, float breath, ColorPalette* const palette, - Gaze gaze, float eyeOpenRatio, float mouthOpenRatio, - String speechText, BatteryIconStatus batteryIconStatus, int32_t batteryLevel, const lgfx::IFont* speechFont); + Gaze rightGaze, float rightEyeOpenRatio, Gaze leftGaze, + float leftEyeOpenRatio, float mouthOpenRatio, String speechText, + BatteryIconStatus batteryIconStatus, int32_t batteryLevel, + const lgfx::IFont* speechFont); DrawContext(Expression expression, float breath, ColorPalette* const palette, - Gaze gaze, float eyeOpenRatio, float mouthOpenRatio, - String speechText, float rotation, float scale, int colorDepth, BatteryIconStatus batteryIconStatus, int32_t batteryLevel, const lgfx::IFont* speechFont); + Gaze rightGaze, float rightEyeOpenRatio, Gaze leftGaze, + float leftEyeOpenRatio, float mouthOpenRatio, String speechText, + float rotation, float scale, int colorDepth, + BatteryIconStatus batteryIconStatus, int32_t batteryLevel, + const lgfx::IFont* speechFont); ~DrawContext() = default; DrawContext(const DrawContext& other) = delete; DrawContext& operator=(const DrawContext& other) = delete; Expression getExpression() const; float getBreath() const; - float getEyeOpenRatio() const; + float getRightEyeOpenRatio() const; + Gaze getRightGaze() const; + float getLeftEyeOpenRatio() const; + Gaze getLeftGaze() const; float getMouthOpenRatio() const; float getScale() const; float getRotation() const; - Gaze getGaze() const; ColorPalette* const getColorPalette() const; String getspeechText() const; int getColorDepth() const; BatteryIconStatus getBatteryIconStatus() const; int32_t getBatteryLevel() const; - const lgfx::IFont* getSpeechFont() const; + const lgfx::IFont* getSpeechFont() const; }; } // namespace m5avatar diff --git a/src/Eye.cpp b/src/Eye.cpp index 736a2ce..e786f96 100644 --- a/src/Eye.cpp +++ b/src/Eye.cpp @@ -14,12 +14,17 @@ void Eye::draw(M5Canvas *spi, BoundingRect rect, DrawContext *ctx) { Expression exp = ctx->getExpression(); uint32_t x = rect.getCenterX(); uint32_t y = rect.getCenterY(); - Gaze g = ctx->getGaze(); - float openRatio = ctx->getEyeOpenRatio(); + Gaze g = this->isLeft ? ctx->getLeftGaze() : ctx->getRightGaze(); + float openRatio = + this->isLeft ? ctx->getLeftEyeOpenRatio() : ctx->getRightEyeOpenRatio(); uint32_t offsetX = g.getHorizontal() * 3; uint32_t offsetY = g.getVertical() * 3; - uint16_t primaryColor = ctx->getColorDepth() == 1 ? 1 : ctx->getColorPalette()->get(COLOR_PRIMARY); - uint16_t backgroundColor = ctx->getColorDepth() == 1 ? 0 : ctx->getColorPalette()->get(COLOR_BACKGROUND); + uint16_t primaryColor = ctx->getColorDepth() == 1 + ? 1 + : ctx->getColorPalette()->get(COLOR_PRIMARY); + uint16_t backgroundColor = + ctx->getColorDepth() == 1 ? 0 + : ctx->getColorPalette()->get(COLOR_BACKGROUND); if (openRatio > 0) { spi->fillCircle(x + offsetX, y + offsetY, r, primaryColor); From d35f146110e7cb1b504b1f725e651269da125bde Mon Sep 17 00:00:00 2001 From: botamochi6277 Date: Wed, 17 Apr 2024 01:01:21 +0900 Subject: [PATCH 4/4] Add winking example --- examples/wink-demo/wink-demo.ino | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/wink-demo/wink-demo.ino b/examples/wink-demo/wink-demo.ino index 64dec77..5965bac 100644 --- a/examples/wink-demo/wink-demo.ino +++ b/examples/wink-demo/wink-demo.ino @@ -2,9 +2,16 @@ #include m5avatar::Avatar avatar; +m5avatar::ColorPalette* palettes[2]; void setup() { M5.begin(); + + palettes[0] = new m5avatar::ColorPalette(); + palettes[1] = new m5avatar::ColorPalette(); + palettes[1]->set(COLOR_PRIMARY, TFT_YELLOW); + palettes[1]->set(COLOR_BACKGROUND, TFT_DARKCYAN); + avatar.init(); // start drawing } @@ -17,6 +24,8 @@ void loop() { } if (M5.BtnB.wasPressed()) { avatar.setIsAutoBlink(!avatar.getIsAutoBlink()); + avatar.setColorPalette( + *palettes[static_cast(!avatar.getIsAutoBlink())]); } if (M5.BtnC.wasPressed()) { // switch left eye