From 83fbe060b1a44304f4d07c6920f2850610af5ba3 Mon Sep 17 00:00:00 2001 From: alastaira Date: Wed, 6 Sep 2023 16:45:07 +0100 Subject: [PATCH] Initial commit --- Animations.h | 261 +++++++++++++++++++++ AsyncTimer.cpp | 69 ++++++ AsyncTimer.h | 52 +++++ BlinkAssistant.cpp | 32 +++ BlinkAssistant.h | 40 ++++ Common.h | 8 + Eye.cpp | 85 +++++++ Eye.h | 62 +++++ EyeBlink.cpp | 41 ++++ EyeBlink.h | 43 ++++ EyeConfig.h | 43 ++++ EyeDrawer.h | 216 +++++++++++++++++ EyePresets.h | 399 ++++++++++++++++++++++++++++++++ EyeTransformation.cpp | 61 +++++ EyeTransformation.h | 53 +++++ EyeTransition.cpp | 35 +++ EyeTransition.h | 39 ++++ EyeVariation.cpp | 50 ++++ EyeVariation.h | 46 ++++ Face.cpp | 96 ++++++++ Face.h | 69 ++++++ FaceBehavior.cpp | 100 ++++++++ FaceBehavior.h | 52 +++++ FaceEmotions.hpp | 44 ++++ FaceExpression.cpp | 181 +++++++++++++++ FaceExpression.h | 53 +++++ LookAssistant.cpp | 68 ++++++ LookAssistant.h | 44 ++++ anki-cozmo-faces-3-1024x576.jpg | Bin 0 -> 87237 bytes esp32-eyes.ino | 94 ++++++++ 30 files changed, 2436 insertions(+) create mode 100644 Animations.h create mode 100644 AsyncTimer.cpp create mode 100644 AsyncTimer.h create mode 100644 BlinkAssistant.cpp create mode 100644 BlinkAssistant.h create mode 100644 Common.h create mode 100644 Eye.cpp create mode 100644 Eye.h create mode 100644 EyeBlink.cpp create mode 100644 EyeBlink.h create mode 100644 EyeConfig.h create mode 100644 EyeDrawer.h create mode 100644 EyePresets.h create mode 100644 EyeTransformation.cpp create mode 100644 EyeTransformation.h create mode 100644 EyeTransition.cpp create mode 100644 EyeTransition.h create mode 100644 EyeVariation.cpp create mode 100644 EyeVariation.h create mode 100644 Face.cpp create mode 100644 Face.h create mode 100644 FaceBehavior.cpp create mode 100644 FaceBehavior.h create mode 100644 FaceEmotions.hpp create mode 100644 FaceExpression.cpp create mode 100644 FaceExpression.h create mode 100644 LookAssistant.cpp create mode 100644 LookAssistant.h create mode 100644 anki-cozmo-faces-3-1024x576.jpg create mode 100644 esp32-eyes.ino diff --git a/Animations.h b/Animations.h new file mode 100644 index 0000000..3d1f5c1 --- /dev/null +++ b/Animations.h @@ -0,0 +1,261 @@ +/*************************************************** +Copyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +class IAnimation { +public: + virtual float GetValue() = 0; + virtual float GetValue(unsigned long overWriteMillis) = 0; + virtual unsigned long GetElapsed() = 0; + +private: + virtual float Calculate(unsigned long elapsedMillis) = 0; +}; + +class AnimationBase : IAnimation { + public: + AnimationBase(unsigned long interval) : Interval(interval), StarTime(millis()) {} + + unsigned long Interval; + unsigned long StarTime; + + virtual void Restart() { + StarTime = millis(); + } + float GetValue() override final { + return GetValue(GetElapsed()); + } + float GetValue(unsigned long elapsedMillis) override final { + return Calculate(elapsedMillis); + } + unsigned long GetElapsed() override { + return static_cast (millis() - StarTime); + } + + protected: + float Calculate(unsigned long elapsedMillis) override { return 0.0; } +}; + +class DeltaAnimation : public AnimationBase { + public: + unsigned long StarTime; + DeltaAnimation(unsigned long interval) : AnimationBase(interval) {}; + float Calculate(unsigned long elapsedMillis) { + if (elapsedMillis < Interval) { + return 0.0f; + } + else { + return 1.0f; + } + }; +}; + + +class StepAnimation : public AnimationBase { + public: + unsigned long Interval; + unsigned long StarTime; + bool IsActive = true; + StepAnimation(unsigned long interval) : AnimationBase(interval) {}; + + float Calculate(unsigned long elapsedMillis) { + if (elapsedMillis < Interval) { + return 0.0f; + } + return 1.0f; + }; +}; + + +class RampAnimation : public AnimationBase { +public: + + unsigned long StarTime; + bool IsActive = true; + + RampAnimation(unsigned long interval) : AnimationBase(interval) {}; + + float Calculate(unsigned long elapsedMillis) { + if (elapsedMillis < Interval) { + return static_cast(elapsedMillis) / Interval; + } + return 1.0f; + }; +}; + +class TriangleAnimation : public AnimationBase { +public: + + TriangleAnimation(unsigned long interval) : AnimationBase(interval) { + _t0 = interval / 2; + _t1 = interval - _t0; + } + TriangleAnimation(unsigned long t0, unsigned long t1) : AnimationBase(t0 + t1) { + _t0 = t0; + _t1 = t1; + }; + float Calculate(unsigned long elapsedMillis) { + if (elapsedMillis % Interval < _t0) { + return static_cast(elapsedMillis % Interval) / _t0; + } + return 1.0f - (static_cast(elapsedMillis % Interval) - _t0) / _t1; + }; + unsigned long _t0; + unsigned long _t1; +}; + + +class TrapeziumAnimation : public AnimationBase { +public: + TrapeziumAnimation(unsigned long t) : AnimationBase(t) { + _t0 = t / 3; + _t1 = _t0; + _t2 = t - _t0 - _t1; + }; + TrapeziumAnimation(unsigned long t0, unsigned long t1, unsigned long t2) : AnimationBase(t0 + t1 + t2) { + _t0 = t0; + _t1 = t1; + _t2 = t2; + }; + float Calculate(unsigned long elapsedMillis) override { + if (elapsedMillis > Interval) return 0.0; + if (elapsedMillis < _t0) { + return static_cast(elapsedMillis) / _t0; + } + else if (elapsedMillis < _t0 + _t1) { + return 1.0f; + } + else { + return 1.0f - (static_cast(elapsedMillis) - _t1 - _t0) / _t2; + } + }; + + unsigned long _t0; + unsigned long _t1; + unsigned long _t2; +}; + + +class TrapeziumPulseAnimation : public AnimationBase { +public: + TrapeziumPulseAnimation(unsigned long t) : AnimationBase(t) { + _t0 = 0; + _t1 = t / 3; + _t2 = t - _t0 - _t0; + _t3 = _t1; + _t4 = 0; + }; + + TrapeziumPulseAnimation(unsigned long t0, unsigned long t1, unsigned long t2) : AnimationBase(t0 + t1 + t2) { + _t0 = 0; + _t1 = t0; + _t2 = t1; + _t3 = t2; + _t4 = 0; + }; + + TrapeziumPulseAnimation(unsigned long t0, unsigned long t1, unsigned long t2, unsigned long t3, unsigned long t4) : AnimationBase(t0 + t1 + t2 + t3 + t4) { + _t0 = t0; + _t1 = t1; + _t2 = t2; + _t3 = t3; + _t4 = t4; + }; + + float Calculate(unsigned long elapsedMillis) override { + unsigned long elapsed = elapsedMillis % Interval; + + if (elapsed < _t0) { + return 0.0; + } + if (elapsed < _t0 + _t1) { + return static_cast(elapsed - _t0) / _t1; + } + else if (elapsed < _t0 + _t1 + _t2) { + return 1.0f; + } + else if (elapsed < _t0 + _t1 + _t2 + _t3) { + return 1.0f - (static_cast(elapsed) - _t2 - _t1 - _t0) / _t3; + } + return 0.0; + }; + + void SetInterval(uint16_t t) { + _t0 = 0; + _t1 = t / 3; + _t2 = t - _t0 - _t0; + _t3 = _t1; + _t4 = 0; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + void SetTriangle(uint16_t t, uint16_t delay) { + _t0 = 0; + _t1 = t / 2; + _t2 = 0; + _t3 = _t1; + _t4 = delay; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + void SetTriangleCuadrature(uint16_t t, uint16_t delay) { + _t0 = delay; + _t1 = t / 2; + _t2 = 0; + _t3 = _t1; + _t4 = 0; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + void SetPulse(uint16_t t, uint16_t delay) { + _t0 = 0; + _t1 = t / 3; + _t2 = t - _t0 - _t0; + _t3 = _t1; + _t4 = delay; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + void SetPulseCuadrature(uint16_t t, uint16_t delay) { + _t0 = delay; + _t1 = t / 3; + _t2 = t - _t0 - _t0; + _t3 = _t1; + _t4 = 0; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + void SetInterval(uint16_t t0, uint16_t t1, uint16_t t2, uint16_t t3, uint16_t t4) { + _t0 = t0; + _t1 = t1; + _t2 = t2; + _t3 = t3; + _t4 = t4; + Interval = _t0 + _t1 + _t2 + _t3 + _t4; + } + + unsigned long _t0; + unsigned long _t1; + unsigned long _t2; + unsigned long _t3; + unsigned long _t4; +}; + +#endif \ No newline at end of file diff --git a/AsyncTimer.cpp b/AsyncTimer.cpp new file mode 100644 index 0000000..ce68feb --- /dev/null +++ b/AsyncTimer.cpp @@ -0,0 +1,69 @@ +/*************************************************** +Copyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see (millis() - _startTime) >= Interval) { + _isExpired = true; + if (OnFinish != nullptr) OnFinish(); + Reset(); + } + return _isExpired; +} + +void AsyncTimer::SetIntervalMillis(unsigned long interval) { + Interval = interval; +} + +unsigned long AsyncTimer::GetStartTime() { + return _startTime; +} + +unsigned long AsyncTimer::GetElapsedTime() { + return millis() - _startTime; +} + +unsigned long AsyncTimer::GetRemainingTime() { + return Interval - millis() + _startTime; +} + +bool AsyncTimer::IsActive() const { + return _isActive; +} + +bool AsyncTimer::IsExpired() const{ + return _isExpired; +} \ No newline at end of file diff --git a/AsyncTimer.h b/AsyncTimer.h new file mode 100644 index 0000000..86164e8 --- /dev/null +++ b/AsyncTimer.h @@ -0,0 +1,52 @@ +/*************************************************** +Copyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +typedef void(*AsyncTimerCallback)(); + +class AsyncTimer { + public: + AsyncTimer(unsigned long millisInterval); + AsyncTimer(unsigned long millisInterval, AsyncTimerCallback OnFinish); + + void Start(); + void Reset(); + void Stop(); + bool Update(); + + void SetIntervalMillis(unsigned long interval); + + unsigned long GetStartTime(); + unsigned long GetElapsedTime(); + unsigned long GetRemainingTime(); + + bool IsActive() const; + bool IsExpired() const; + + unsigned long Interval; + + AsyncTimerCallback OnFinish; + +private: + bool _isActive; + bool _isExpired; + unsigned long _startTime; +}; +#endif \ No newline at end of file diff --git a/BlinkAssistant.cpp b/BlinkAssistant.cpp new file mode 100644 index 0000000..d75f0c6 --- /dev/null +++ b/BlinkAssistant.cpp @@ -0,0 +1,32 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +#include "Animations.h" +#include "AsyncTimer.h" + +class Face; + +class BlinkAssistant { + protected: + Face& _face; + + public: + BlinkAssistant(Face& face); + + AsyncTimer Timer; + + void Update(); + void Blink(); +}; + +#endif \ No newline at end of file diff --git a/Common.h b/Common.h new file mode 100644 index 0000000..f2671c6 --- /dev/null +++ b/Common.h @@ -0,0 +1,8 @@ +#ifndef COMMON_h +#define COMMON_h + +#include + +extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2; + +#endif \ No newline at end of file diff --git a/Eye.cpp b/Eye.cpp new file mode 100644 index 0000000..ccb00d6 --- /dev/null +++ b/Eye.cpp @@ -0,0 +1,85 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see IsMirrored = false; + + ChainOperators(); + Variation1.Animation._t0 = 200; + Variation1.Animation._t1 = 200; + Variation1.Animation._t2 = 200; + Variation1.Animation._t3 = 200; + Variation1.Animation._t4 = 0; + Variation1.Animation.Interval = 800; + + Variation2.Animation._t0 = 0; + Variation2.Animation._t1 = 200; + Variation2.Animation._t2 = 200; + Variation2.Animation._t3 = 200; + Variation2.Animation._t4 = 200; + Variation2.Animation.Interval = 800; +} + +void Eye::ChainOperators() { + Transition.Origin = &Config; + Transformation.Input = &Config; + Variation1.Input = &(Transformation.Output); + Variation2.Input = &(Variation1.Output); + BlinkTransformation.Input = &(Variation2.Output); + FinalConfig = &(BlinkTransformation.Output); +} + +void Eye::Update() { + Transition.Update(); + Transformation.Update(); + Variation1.Update(); + Variation2.Update(); + BlinkTransformation.Update(); +} + +void Eye::Draw() { + Update(); + EyeDrawer::Draw(CenterX, CenterY, FinalConfig); +} + +void Eye::ApplyPreset(const EyeConfig config) { + Config.OffsetX = this->IsMirrored ? -config.OffsetX : config.OffsetX; + Config.OffsetY = -config.OffsetY; + Config.Height = config.Height; + Config.Width = config.Width; + Config.Slope_Top = this->IsMirrored ? config.Slope_Top : -config.Slope_Top; + Config.Slope_Bottom = this->IsMirrored ? config.Slope_Bottom : -config.Slope_Bottom; + Config.Radius_Top = config.Radius_Top; + Config.Radius_Bottom = config.Radius_Bottom; + Config.Inverse_Radius_Top = config.Inverse_Radius_Top; + Config.Inverse_Radius_Bottom = config.Inverse_Radius_Bottom; + + Transition.Animation.Restart(); +} + +void Eye::TransitionTo(const EyeConfig config) { + Transition.Destin.OffsetX = this->IsMirrored ? -config.OffsetX : config.OffsetX; + Transition.Destin.OffsetY = -config.OffsetY; + Transition.Destin.Height = config.Height; + Transition.Destin.Width = config.Width; + Transition.Destin.Slope_Top = this->IsMirrored ? config.Slope_Top : -config.Slope_Top; + Transition.Destin.Slope_Bottom = this->IsMirrored ? config.Slope_Bottom : -config.Slope_Bottom; + Transition.Destin.Radius_Top = config.Radius_Top; + Transition.Destin.Radius_Bottom = config.Radius_Bottom; + Transition.Destin.Inverse_Radius_Top = config.Inverse_Radius_Top; + Transition.Destin.Inverse_Radius_Bottom = config.Inverse_Radius_Bottom; + + Transition.Animation.Restart(); +} \ No newline at end of file diff --git a/Eye.h b/Eye.h new file mode 100644 index 0000000..6d43947 --- /dev/null +++ b/Eye.h @@ -0,0 +1,62 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Common.h" +#include "Animations.h" +#include "EyeConfig.h" +#include "EyeDrawer.h" +#include "EyeTransition.h" +#include "EyeTransformation.h" +#include "EyeVariation.h" +#include "EyeBlink.h" +#include "EyeVariation.h" + +class Face; + +class Eye { + protected: + Face& _face; + + void Update(); + void ChainOperators(); + + public: + Eye(Face& face); + + uint16_t CenterX; + uint16_t CenterY; + bool IsMirrored = false; + + EyeConfig Config; + EyeConfig* FinalConfig; + + EyeTransition Transition; + EyeTransformation Transformation; + EyeVariation Variation1; + EyeVariation Variation2; + EyeBlink BlinkTransformation; + + void ApplyPreset(const EyeConfig preset); + void TransitionTo(const EyeConfig preset); + void Draw(); +}; + +#endif \ No newline at end of file diff --git a/EyeBlink.cpp b/EyeBlink.cpp new file mode 100644 index 0000000..f7f5644 --- /dev/null +++ b/EyeBlink.cpp @@ -0,0 +1,41 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see Animation.Interval) t = 0.0; + Apply(t * t); +} + + +void EyeBlink::Apply(float t) { + Output.OffsetX = Input->OffsetX; + Output.OffsetY = Input->OffsetY; + + Output.Width = (BlinkWidth - Input->Width) * t + Input->Width; + Output.Height = (BlinkHeight - Input->Height) * t + Input->Height; + + Output.Slope_Top = Input->Slope_Top * (1.0 - t); + Output.Slope_Bottom = Input->Slope_Bottom * (1.0 - t); + Output.Radius_Top = Input->Radius_Top * (1.0 - t); + Output.Radius_Bottom = Input->Radius_Bottom * (1.0 - t); + Output.Inverse_Radius_Top = Input->Inverse_Radius_Top * (1.0 - t); + Output.Inverse_Radius_Bottom = Input->Inverse_Radius_Bottom * (1.0 - t); + Output.Inverse_Offset_Top = Input->Inverse_Offset_Top * (1.0 - t); + Output.Inverse_Offset_Bottom = Input->Inverse_Offset_Bottom * (1.0 - t); +} + diff --git a/EyeBlink.h b/EyeBlink.h new file mode 100644 index 0000000..0f3d594 --- /dev/null +++ b/EyeBlink.h @@ -0,0 +1,43 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +#include "Animations.h" +#include "EyeConfig.h" + +class EyeBlink { + protected: + +public: + EyeBlink(); + + EyeConfig* Input; + EyeConfig Output; + + TrapeziumAnimation Animation; + + int32_t BlinkWidth = 60; + int32_t BlinkHeight = 2; + + void Update(); + void Apply(float t); +}; + +#endif \ No newline at end of file diff --git a/EyeConfig.h b/EyeConfig.h new file mode 100644 index 0000000..e2ad95e --- /dev/null +++ b/EyeConfig.h @@ -0,0 +1,43 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +struct EyeConfig +{ + int16_t OffsetX; + int16_t OffsetY; + + int16_t Height; + int16_t Width; + + float Slope_Top; + float Slope_Bottom; + + int16_t Radius_Top; + int16_t Radius_Bottom; + + int16_t Inverse_Radius_Top; + int16_t Inverse_Radius_Bottom; + + int16_t Inverse_Offset_Top; + int16_t Inverse_Offset_Bottom; +}; + +#endif \ No newline at end of file diff --git a/EyeDrawer.h b/EyeDrawer.h new file mode 100644 index 0000000..c32f236 --- /dev/null +++ b/EyeDrawer.h @@ -0,0 +1,216 @@ +/*************************************************** +Copyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +enum CornerType {T_R, T_L, B_L, B_R}; + +/** + * Contains all functions to draw eye based on supplied (expression-based) config + */ +class EyeDrawer { + public: + static void Draw(int16_t centerX, int16_t centerY, EyeConfig *config) { + // Amount by which corners will be shifted up/down based on requested "slope" + int32_t delta_y_top = config->Height * config->Slope_Top / 2.0; + int32_t delta_y_bottom = config->Height * config->Slope_Bottom / 2.0; + // Full extent of the eye, after accounting for slope added at top and bottom + auto totalHeight = config->Height + delta_y_top - delta_y_bottom; + // If the requested top/bottom radius would exceed the height of the eye, adjust them downwards + if (config->Radius_Bottom > 0 && config->Radius_Top > 0 && totalHeight - 1 < config->Radius_Bottom + config->Radius_Top) { + int32_t corrected_radius_top = (float)config->Radius_Top * (totalHeight - 1) / (config->Radius_Bottom + config->Radius_Top); + int32_t corrected_radius_bottom = (float)config->Radius_Bottom * (totalHeight - 1) / (config->Radius_Bottom + config->Radius_Top); + config->Radius_Top = corrected_radius_top; + config->Radius_Bottom = corrected_radius_bottom; + } + + // Calculate _inside_ corners of eye (TL, TR, BL, and BR) before any slope or rounded corners are applied + int32_t TLc_y = centerY + config->OffsetY - config->Height/2 + config->Radius_Top - delta_y_top; + int32_t TLc_x = centerX + config->OffsetX - config->Width/2 + config->Radius_Top; + int32_t TRc_y = centerY + config->OffsetY - config->Height/2 + config->Radius_Top + delta_y_top; + int32_t TRc_x = centerX + config->OffsetX + config->Width/2 - config->Radius_Top; + int32_t BLc_y = centerY + config->OffsetY + config->Height/2 - config->Radius_Bottom - delta_y_bottom; + int32_t BLc_x = centerX + config->OffsetX - config->Width/2 + config->Radius_Bottom; + int32_t BRc_y = centerY + config->OffsetY + config->Height/2 - config->Radius_Bottom + delta_y_bottom; + int32_t BRc_x = centerX + config->OffsetX + config->Width/2 - config->Radius_Bottom; + + // Calculate interior extents + int32_t min_c_x = min(TLc_x, BLc_x); + int32_t max_c_x = max(TRc_x, BRc_x); + int32_t min_c_y = min(TLc_y, TRc_y); + int32_t max_c_y = max(BLc_y, BRc_y); + + // Fill eye centre + EyeDrawer::FillRectangle(min_c_x, min_c_y, max_c_x, max_c_y, 1); + + // Fill eye outwards to meet edges of rounded corners + EyeDrawer::FillRectangle(TRc_x, TRc_y, BRc_x + config->Radius_Bottom, BRc_y, 1); // Right + EyeDrawer::FillRectangle(TLc_x - config->Radius_Top, TLc_y, BLc_x, BLc_y, 1); // Left + EyeDrawer::FillRectangle(TLc_x, TLc_y - config->Radius_Top, TRc_x, TRc_y, 1); // Top + EyeDrawer::FillRectangle(BLc_x, BLc_y, BRc_x, BRc_y + config->Radius_Bottom, 1); // Bottom + + // Draw slanted edges at top of bottom of eyes + // +ve Slope_Top means eyes slope downwards towards middle of face + if(config->Slope_Top > 0) { + EyeDrawer::FillRectangularTriangle(TLc_x, TLc_y-config->Radius_Top, TRc_x, TRc_y-config->Radius_Top, 0); + EyeDrawer::FillRectangularTriangle(TRc_x, TRc_y-config->Radius_Top, TLc_x, TLc_y-config->Radius_Top, 1); + } + else if(config->Slope_Top < 0) { + EyeDrawer::FillRectangularTriangle(TRc_x, TRc_y-config->Radius_Top, TLc_x, TLc_y-config->Radius_Top, 0); + EyeDrawer::FillRectangularTriangle(TLc_x, TLc_y-config->Radius_Top, TRc_x, TRc_y-config->Radius_Top, 1); + } + // Draw slanted edges at bottom of eyes + if(config->Slope_Bottom > 0) { + EyeDrawer::FillRectangularTriangle(BRc_x+config->Radius_Bottom, BRc_y+config->Radius_Bottom, BLc_x-config->Radius_Bottom, BLc_y+config->Radius_Bottom, 0); + EyeDrawer::FillRectangularTriangle(BLc_x-config->Radius_Bottom, BLc_y+config->Radius_Bottom, BRc_x+config->Radius_Bottom, BRc_y+config->Radius_Bottom, 1); + } + else if (config->Slope_Bottom < 0) { + EyeDrawer::FillRectangularTriangle(BLc_x-config->Radius_Bottom, BLc_y+config->Radius_Bottom, BRc_x+config->Radius_Bottom, BRc_y+config->Radius_Bottom, 0); + EyeDrawer::FillRectangularTriangle(BRc_x+config->Radius_Bottom, BRc_y+config->Radius_Bottom, BLc_x-config->Radius_Bottom, BLc_y+config->Radius_Bottom, 1); + } + + // Draw corners (which extend "outwards" towards corner of screen from supplied coordinate values) + if(config->Radius_Top > 0) { + EyeDrawer::FillEllipseCorner(T_L, TLc_x, TLc_y, config->Radius_Top, config->Radius_Top, 1); + EyeDrawer::FillEllipseCorner(T_R, TRc_x, TRc_y, config->Radius_Top, config->Radius_Top, 1); + } + if(config->Radius_Bottom > 0) { + EyeDrawer::FillEllipseCorner(B_L, BLc_x, BLc_y, config->Radius_Bottom, config->Radius_Bottom, 1); + EyeDrawer::FillEllipseCorner(B_R, BRc_x, BRc_y, config->Radius_Bottom, config->Radius_Bottom, 1); + } + } + + // Draw rounded corners + static void FillEllipseCorner(CornerType corner, int16_t x0, int16_t y0, int32_t rx, int32_t ry, uint16_t color) { + if (rx < 2) return; + if (ry < 2) return; + int32_t x, y; + int32_t rx2 = rx * rx; + int32_t ry2 = ry * ry; + int32_t fx2 = 4 * rx2; + int32_t fy2 = 4 * ry2; + int32_t s; + + if (corner == T_R) { + for(x = 0, y = ry, s = 2 * ry2 + rx2 * (1 - 2 * ry); ry2 * x <= rx2 * y; x++) { + u8g2.drawHLine(x0, y0 - y, x); + if(s >= 0) { + s += fx2 * (1 - y); + y--; + } + s += ry2 * ((4 * x) + 6); + } + for(x = rx, y = 0, s = 2 * rx2 + ry2 * (1 - 2 * rx); rx2 * y <= ry2 * x; y++) { + u8g2.drawHLine(x0, y0 - y, x); + if (s >= 0) { + s += fy2 * (1 - x); + x--; + } + s += rx2 * ((4 * y) + 6); + } + } + + else if (corner == B_R) { + for (x = 0, y = ry, s = 2 * ry2 + rx2 * (1 - 2 * ry); ry2 * x <= rx2 * y; x++) { + u8g2.drawHLine(x0, y0 + y -1, x); + if (s >= 0) { + s += fx2 * (1 - y); + y--; + } + s += ry2 * ((4 * x) + 6); + } + for (x = rx, y = 0, s = 2 * rx2 + ry2 * (1 - 2 * rx); rx2 * y <= ry2 * x; y++) { + u8g2.drawHLine(x0, y0 + y -1, x); + if (s >= 0) { + s += fy2 * (1 - x); + x--; + } + s += rx2 * ((4 * y) + 6); + } + } + + else if (corner == T_L) { + for (x = 0, y = ry, s = 2 * ry2 + rx2 * (1 - 2 * ry); ry2 * x <= rx2 * y; x++) { + u8g2.drawHLine(x0-x, y0 - y, x); + if (s >= 0) { + s += fx2 * (1 - y); + y--; + } + s += ry2 * ((4 * x) + 6); + } + for (x = rx, y = 0, s = 2 * rx2 + ry2 * (1 - 2 * rx); rx2 * y <= ry2 * x; y++) { + u8g2.drawHLine(x0-x, y0 - y, x); + if (s >= 0) { + s += fy2 * (1 - x); + x--; + } + s += rx2 * ((4 * y) + 6); + } + } + + else if (corner == B_L) { + for (x = 0, y = ry, s = 2 * ry2 + rx2 * (1 - 2 * ry); ry2 * x <= rx2 * y; x++) { + u8g2.drawHLine(x0-x, y0 + y - 1, x); + if (s >= 0) { + s += fx2 * (1 - y); + y--; + } + s += ry2 * ((4 * x) + 6); + } + for (x = rx, y = 0, s = 2 * rx2 + ry2 * (1 - 2 * rx); rx2 * y <= ry2 * x; y++) { + u8g2.drawHLine(x0-x, y0 + y , x); + if (s >= 0) { + s += fy2 * (1 - x); + x--; + } + s += rx2 * ((4 * y) + 6); + } + } + } + + // Fill a solid rectangle between specified coordinates + static void FillRectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t color) { + // Always draw from TL->BR + int32_t l = min(x0, x1); + int32_t r = max(x0, x1); + int32_t t = min(y0, y1); + int32_t b = max(y0, y1); + int32_t w = r-l; + int32_t h = b-t; + u8g2.setDrawColor(color); + u8g2.drawBox(l, t, w, h); + u8g2.setDrawColor(1); + } + + static void FillRectangularTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t color) { + u8g2.setDrawColor(color); + u8g2.drawTriangle(x0, y0, x1, y1, x1, y0); + u8g2.setDrawColor(1); + } + + static void FillTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t color) { + u8g2.setDrawColor(color); + u8g2.drawTriangle(x0, y0, x1, y1, x2, y2); + u8g2.setDrawColor(1); + } +}; + +#endif \ No newline at end of file diff --git a/EyePresets.h b/EyePresets.h new file mode 100644 index 0000000..1370da1 --- /dev/null +++ b/EyePresets.h @@ -0,0 +1,399 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "EyeConfig.h" + +static const EyeConfig Preset_Normal = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 40, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 8, + .Radius_Bottom = 8, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Happy = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 10, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 10, + .Radius_Bottom = 0, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Glee = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 8, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 8, + .Radius_Bottom = 0, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 5, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Sad = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 15, + .Width = 40, + .Slope_Top = -0.5, + .Slope_Bottom = 0, + .Radius_Top = 1, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Worried = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 25, + .Width = 40, + .Slope_Top = -0.1, + .Slope_Bottom = 0, + .Radius_Top = 6, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Worried_Alt = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 35, + .Width = 40, + .Slope_Top = -0.2, + .Slope_Bottom = 0, + .Radius_Top = 6, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Focused = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 14, + .Width = 40, + .Slope_Top = 0.2, + .Slope_Bottom = 0, + .Radius_Top = 3, + .Radius_Bottom = 1, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Annoyed = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 12, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 0, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Annoyed_Alt = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 5, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 0, + .Radius_Bottom = 4, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Surprised = { + .OffsetX = -2, + .OffsetY = 0, + .Height = 45, + .Width = 45, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 16, + .Radius_Bottom = 16, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Skeptic = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 40, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 10, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Skeptic_Alt = { + .OffsetX = 0, + .OffsetY = -6, + .Height = 26, + .Width = 40, + .Slope_Top = 0.3, + .Slope_Bottom = 0, + .Radius_Top = 1, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Fustrated = { + .OffsetX = 3, + .OffsetY = -5, + .Height = 12, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 0, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Unimpressed = { + .OffsetX = 3, + .OffsetY = 0, + .Height = 12, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 1, + .Radius_Bottom = 10, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Unimpressed_Alt = { + .OffsetX = 3, + .OffsetY = -3, + .Height = 22, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 1, + .Radius_Bottom = 16, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Sleepy = { + .OffsetX = 0, + .OffsetY = -2, + .Height = 14, + .Width = 40, + .Slope_Top = -0.5, + .Slope_Bottom = -0.5, + .Radius_Top = 3, + .Radius_Bottom = 3, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Sleepy_Alt = { + .OffsetX = 0, + .OffsetY = -2, + .Height = 8, + .Width = 40, + .Slope_Top = -0.5, + .Slope_Bottom = -0.5, + .Radius_Top = 3, + .Radius_Bottom = 3, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Suspicious = { + .OffsetX = 0, + .OffsetY = 0, + .Height = 22, + .Width = 40, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 8, + .Radius_Bottom = 3, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Suspicious_Alt = { + .OffsetX = 0, + .OffsetY = -3, + .Height = 16, + .Width = 40, + .Slope_Top = 0.2, + .Slope_Bottom = 0, + .Radius_Top = 6, + .Radius_Bottom = 3, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Squint = { + .OffsetX = -10, + .OffsetY = -3, + .Height = 35, + .Width = 35, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 8, + .Radius_Bottom = 8, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Squint_Alt = { + .OffsetX = 5, + .OffsetY = 0, + .Height = 20, + .Width = 20, + .Slope_Top = 0, + .Slope_Bottom = 0, + .Radius_Top = 5, + .Radius_Bottom = 5, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Angry = { + .OffsetX = -3, + .OffsetY = 0, + .Height = 20, + .Width = 40, + .Slope_Top = 0.3, + .Slope_Bottom = 0, + .Radius_Top = 2, + .Radius_Bottom = 12, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Furious = { + .OffsetX = -2, + .OffsetY = 0, + .Height = 30, + .Width = 40, + .Slope_Top = 0.4, + .Slope_Bottom = 0, + .Radius_Top = 2, + .Radius_Bottom = 8, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Scared = { + .OffsetX = -3, + .OffsetY = 0, + .Height = 40, + .Width = 40, + .Slope_Top = -0.1, + .Slope_Bottom = 0, + .Radius_Top = 12, + .Radius_Bottom = 8, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +static const EyeConfig Preset_Awe = { + .OffsetX = 2, + .OffsetY = 0, + .Height = 35, + .Width = 45, + .Slope_Top = -0.1, + .Slope_Bottom = 0.1, + .Radius_Top = 12, + .Radius_Bottom = 12, + .Inverse_Radius_Top = 0, + .Inverse_Radius_Bottom = 0, + .Inverse_Offset_Top = 0, + .Inverse_Offset_Bottom = 0 +}; + +#endif \ No newline at end of file diff --git a/EyeTransformation.cpp b/EyeTransformation.cpp new file mode 100644 index 0000000..1960b94 --- /dev/null +++ b/EyeTransformation.cpp @@ -0,0 +1,61 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see OffsetX + Current.MoveX; + Output.OffsetY = Input->OffsetY - Current.MoveY; + Output.Width = Input->Width * Current.ScaleX; + Output.Height = Input->Height * Current.ScaleY; + + Output.Slope_Top = Input->Slope_Top; + Output.Slope_Bottom = Input->Slope_Bottom; + Output.Radius_Top = Input->Radius_Top; + Output.Radius_Bottom = Input->Radius_Bottom; + Output.Inverse_Radius_Top = Input->Inverse_Radius_Top; + Output.Inverse_Radius_Bottom = Input->Inverse_Radius_Bottom; + Output.Inverse_Offset_Top = Input->Inverse_Offset_Top; + Output.Inverse_Offset_Bottom = Input->Inverse_Offset_Bottom; +} + +void EyeTransformation::SetDestin(Transformation transformation) +{ + Origin.MoveX = Current.MoveX; + Origin.MoveY = Current.MoveY; + Origin.ScaleX = Current.ScaleX; + Origin.ScaleY = Current.ScaleY; + + Destin.MoveX = transformation.MoveX; + Destin.MoveY = transformation.MoveY; + Destin.ScaleX = transformation.ScaleX; + Destin.ScaleY = transformation.ScaleY; +} + + diff --git a/EyeTransformation.h b/EyeTransformation.h new file mode 100644 index 0000000..2b79bf4 --- /dev/null +++ b/EyeTransformation.h @@ -0,0 +1,53 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Animations.h" +#include "EyeConfig.h" + +struct Transformation +{ + float MoveX = 0.0; + float MoveY = 0.0; + float ScaleX = 1.0; + float ScaleY = 1.0; +}; + +class EyeTransformation +{ +public: + EyeTransformation(); + + EyeConfig* Input; + EyeConfig Output; + + Transformation Origin; + Transformation Current; + Transformation Destin; + + RampAnimation Animation; + + void Update(); + void Apply(); + void SetDestin(Transformation transformation); +}; + +#endif + diff --git a/EyeTransition.cpp b/EyeTransition.cpp new file mode 100644 index 0000000..c51cf07 --- /dev/null +++ b/EyeTransition.cpp @@ -0,0 +1,35 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see OffsetX = Origin->OffsetX * (1.0 - t) + Destin.OffsetX * t; + Origin->OffsetY = Origin->OffsetY * (1.0 - t) + Destin.OffsetY * t; + Origin->Height = Origin->Height * (1.0 - t) + Destin.Height * t; + Origin->Width = Origin->Width * (1.0 - t) + Destin.Width * t; + Origin->Slope_Top = Origin->Slope_Top * (1.0 - t) + Destin.Slope_Top * t; + Origin->Slope_Bottom = Origin->Slope_Bottom * (1.0 - t) + Destin.Slope_Bottom * t; + Origin->Radius_Top = Origin->Radius_Top * (1.0 - t) + Destin.Radius_Top * t; + Origin->Radius_Bottom = Origin->Radius_Bottom * (1.0 - t) + Destin.Radius_Bottom * t; + Origin->Inverse_Radius_Top = Origin->Inverse_Radius_Top * (1.0 - t) + Destin.Inverse_Radius_Top * t; + Origin->Inverse_Radius_Bottom = Origin->Inverse_Radius_Bottom * (1.0 - t) + Destin.Inverse_Radius_Bottom * t; + Origin->Inverse_Offset_Top = Origin->Inverse_Offset_Top * (1.0 - t) + Destin.Inverse_Offset_Top * t; + Origin->Inverse_Offset_Bottom = Origin->Inverse_Offset_Bottom * (1.0 - t) + Destin.Inverse_Offset_Bottom * t; +} \ No newline at end of file diff --git a/EyeTransition.h b/EyeTransition.h new file mode 100644 index 0000000..bd2b33c --- /dev/null +++ b/EyeTransition.h @@ -0,0 +1,39 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Animations.h" +#include "EyeConfig.h" + +class EyeTransition { +public: + EyeTransition(); + + EyeConfig* Origin; + EyeConfig Destin; + + RampAnimation Animation; + + void Update(); + void Apply(float t); +}; + +#endif + diff --git a/EyeVariation.cpp b/EyeVariation.cpp new file mode 100644 index 0000000..dab835c --- /dev/null +++ b/EyeVariation.cpp @@ -0,0 +1,50 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see OffsetX + Values.OffsetX * t; + Output.OffsetY = Input->OffsetY + Values.OffsetY * t; + Output.Height = Input->Height + Values.Height * t;; + Output.Width = Input->Width + Values.Width * t; + Output.Slope_Top = Input->Slope_Top + Values.Slope_Top * t; + Output.Slope_Bottom = Input->Slope_Bottom + Values.Slope_Bottom * t; + Output.Radius_Top = Input->Radius_Top + Values.Radius_Top * t; + Output.Radius_Bottom = Input->Radius_Bottom + Values.Radius_Bottom * t; + Output.Inverse_Radius_Top = Input->Inverse_Radius_Top + Values.Inverse_Radius_Top * t; + Output.Inverse_Radius_Bottom = Input->Inverse_Radius_Bottom + Values.Inverse_Radius_Bottom * t; + Output.Inverse_Offset_Top = Input->Inverse_Offset_Top + Values.Inverse_Offset_Top * t; + Output.Inverse_Offset_Bottom = Input->Inverse_Offset_Bottom + Values.Inverse_Offset_Bottom * t;; +} \ No newline at end of file diff --git a/EyeVariation.h b/EyeVariation.h new file mode 100644 index 0000000..98a375d --- /dev/null +++ b/EyeVariation.h @@ -0,0 +1,46 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Animations.h" +#include "EyeConfig.h" + +class EyeVariation +{ +public: + EyeVariation(); + + EyeConfig* Input; + EyeConfig Output; + + TrapeziumPulseAnimation Animation; + + EyeConfig Values; + void Clear(); + + void SetInterval(uint16_t t0, uint16_t t1, uint16_t t2, uint16_t t3, uint16_t t4); + + void Update(); + void Apply(float t); +}; + + +#endif + diff --git a/Face.cpp b/Face.cpp new file mode 100644 index 0000000..ee338f3 --- /dev/null +++ b/Face.cpp @@ -0,0 +1,96 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +#include "Common.h" +#include "Animations.h" +#include "EyePresets.h" +#include "Eye.h" +#include "FaceExpression.h" +#include "FaceBehavior.h" +#include "LookAssistant.h" +#include "BlinkAssistant.h" + +class Face { + +public: + Face(uint16_t screenWidth, uint16_t screenHeight, uint16_t eyeSize); + + uint16_t Width; + uint16_t Height; + uint16_t CenterX; + uint16_t CenterY; + uint16_t EyeSize; + uint16_t EyeInterDistance = 4; + + Eye LeftEye; + Eye RightEye; + BlinkAssistant Blink; + LookAssistant Look; + FaceBehavior Behavior; + FaceExpression Expression; + + void Update(); + void DoBlink(); + + bool RandomBehavior = true; + bool RandomLook = true; + bool RandomBlink = true; + + void LookLeft(); + void LookRight(); + void LookFront(); + void LookTop(); + void LookBottom(); + void Wait(unsigned long milliseconds); + +protected: + void Draw(); +}; + +#endif \ No newline at end of file diff --git a/FaceBehavior.cpp b/FaceBehavior.cpp new file mode 100644 index 0000000..8e8b515 --- /dev/null +++ b/FaceBehavior.cpp @@ -0,0 +1,100 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +#include "FaceEmotions.hpp" +#include "AsyncTimer.h" + +class Face; + +class FaceBehavior +{ + protected: + Face& _face; + + public: + FaceBehavior(Face& face); + + eEmotions CurrentEmotion; + + float Emotions[eEmotions::EMOTIONS_COUNT]; + + AsyncTimer Timer; + + void SetEmotion(eEmotions emotion, float value); + float GetEmotion(eEmotions emotion); + + void Clear(); + void Update(); + eEmotions GetRandomEmotion(); + + void GoToEmotion(eEmotions emotion); +}; + +#endif + diff --git a/FaceEmotions.hpp b/FaceEmotions.hpp new file mode 100644 index 0000000..125d400 --- /dev/null +++ b/FaceEmotions.hpp @@ -0,0 +1,44 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +enum eEmotions { + Normal=0, + Angry, + Glee, + Happy, + Sad, + Worried, + Focused, + Annoyed, + Surprised, + Skeptic, + Fustrated, + Unimpressed, + Sleepy, + Suspicious, + Squint, + Furious, + Scared, + Awe, + EMOTIONS_COUNT +}; + +#endif diff --git a/FaceExpression.cpp b/FaceExpression.cpp new file mode 100644 index 0000000..e332b99 --- /dev/null +++ b/FaceExpression.cpp @@ -0,0 +1,181 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 +#include "arduino.h" +#else +#include "WProgram.h" +#endif + +class Face; + +class FaceExpression { + protected: + Face& _face; + + public: + FaceExpression(Face& face); + + void ClearVariations(); + + void GoTo_Normal(); + void GoTo_Angry(); + void GoTo_Glee(); + void GoTo_Happy(); + void GoTo_Sad(); + void GoTo_Worried(); + void GoTo_Focused(); + void GoTo_Annoyed(); + void GoTo_Surprised(); + void GoTo_Skeptic(); + void GoTo_Fustrated(); + void GoTo_Unimpressed(); + void GoTo_Sleepy(); + void GoTo_Suspicious(); + void GoTo_Squint(); + void GoTo_Furious(); + void GoTo_Scared(); + void GoTo_Awe(); +}; + +#endif \ No newline at end of file diff --git a/LookAssistant.cpp b/LookAssistant.cpp new file mode 100644 index 0000000..4a0e41c --- /dev/null +++ b/LookAssistant.cpp @@ -0,0 +1,68 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see 0 ? y : -y) * 0.4; + + transformation.MoveX = moveX_x; + transformation.MoveY = moveY_y; //moveY_x + moveY_y; + transformation.ScaleX = 1.0; + transformation.ScaleY = scaleY_x * scaleY_y; + _face.RightEye.Transformation.SetDestin(transformation); + + moveY_x = +3 * x; + scaleY_x = 1.0 + x * 0.2; + transformation.MoveX = moveX_x; + transformation.MoveY = + moveY_y; //moveY_x + moveY_y; + transformation.ScaleX = 1.0; + transformation.ScaleY = scaleY_x * scaleY_y; + _face.LeftEye.Transformation.SetDestin(transformation); + + _face.RightEye.Transformation.Animation.Restart(); + _face.LeftEye.Transformation.Animation.Restart(); +} + +void LookAssistant::Update() +{ + Timer.Update(); + + if (Timer.IsExpired()) + { + Timer.Reset(); + auto x = random(-50, 50); + auto y = random(-50, 50); + LookAt((float)x / 100, (float)y / 100); + + } + +} + diff --git a/LookAssistant.h b/LookAssistant.h new file mode 100644 index 0000000..e2e93bd --- /dev/null +++ b/LookAssistant.h @@ -0,0 +1,44 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see = 100 + #include "arduino.h" +#else + #include "WProgram.h" +#endif + +#include "EyeTransformation.h" +#include "AsyncTimer.h" + +class Face; + +class LookAssistant +{ + protected: + Face& _face; + + public: + LookAssistant(Face& face); + + Transformation transformation; + + AsyncTimer Timer; + + void LookAt(float x, float y); + void Update(); +}; + +#endif + diff --git a/anki-cozmo-faces-3-1024x576.jpg b/anki-cozmo-faces-3-1024x576.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f23fe4dc207c6f08661e925e7a8b93781d681a74 GIT binary patch literal 87237 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 z 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 literal 0 HcmV?d00001 diff --git a/esp32-eyes.ino b/esp32-eyes.ino new file mode 100644 index 0000000..4d956ed --- /dev/null +++ b/esp32-eyes.ino @@ -0,0 +1,94 @@ +/*************************************************** +Copyright (c) 2020 Luis Llamas +(www.luisllamas.es) + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License along with this program. If not, see +#include "Common.h" + +// DEFINES +#define WIDTH 128 //180 +#define HEIGHT 64 //240 +#define EYE 40 //40 + +// GLOBALS +U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data= */ 5); +Face *face; +String emotionName[] = { + "Normal", + "Angry", + "Glee", + "Happy", + "Sad", + "Worried", + "Focused", + "Annoyed", + "Surprised", + "Skeptic", + "Frustrated", + "Unimpressed", + "Sleepy", + "Suspicious", + "Squint", + "Furious", + "Scared", + "Awe" +}; + +void setup(void) { + Serial.begin(115200); + Serial.println(__FILE__ __DATE__); + face = new Face(WIDTH, HEIGHT, EYE); + + // face->Expression.GoTo_Happy(); + face->Behavior.Clear(); + face->Behavior.SetEmotion(eEmotions::Glee, 1.0); + + // Unlike almost every other Arduino application, I2C address scanner etc., u8g2 library + // requires 8-bit I2C address, so we shift the 7-bit address left by one. + u8g2.setI2CAddress(0x3C<<1); + u8g2.begin(); + u8g2.clearBuffer(); // clear the internal memory + u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font + u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory + u8g2.sendBuffer(); // transfer internal memory to the display +} + +void loop(){ + static uint32_t counter = millis(); + static uint8_t emotionno = 0; + static uint8_t emotionflag = 0; + static uint8_t n = 0; + + if(millis() - counter > 6000) { + counter = millis(); + emotionno = n++; + if(n >= EMOTIONS_COUNT) n = 0; + emotionflag = 1; + } + + if(emotionflag) { + emotionflag = 0; + // Update the eyes' emotion + face->Behavior.Clear(); + face->Behavior.SetEmotion((eEmotions)emotionno, 1.0); + + // Draw a text string + //u8g2.setCursor((WIDTH-(emotionName[emotionno].length() * 5)) / 2, HEIGHT); + //u8g2.print(emotionName[emotionno]); + //u8g2.sendBuffer(); // transfer internal memory to the display + Serial.println(emotionName[emotionno]); + } + + face->Update(); + delay(10); +} \ No newline at end of file