mirror of
https://github.com/playfultechnology/esp32-eyes.git
synced 2025-12-06 17:15:42 -08:00
Initial commit
This commit is contained in:
261
Animations.h
Normal file
261
Animations.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _ANIMATIONS_h
|
||||||
|
#define _ANIMATIONS_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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<unsigned long> (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<float>(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<float>(elapsedMillis % Interval) / _t0;
|
||||||
|
}
|
||||||
|
return 1.0f - (static_cast<float>(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<float>(elapsedMillis) / _t0;
|
||||||
|
}
|
||||||
|
else if (elapsedMillis < _t0 + _t1) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 1.0f - (static_cast<float>(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<float>(elapsed - _t0) / _t1;
|
||||||
|
}
|
||||||
|
else if (elapsed < _t0 + _t1 + _t2) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
else if (elapsed < _t0 + _t1 + _t2 + _t3) {
|
||||||
|
return 1.0f - (static_cast<float>(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
|
||||||
69
AsyncTimer.cpp
Normal file
69
AsyncTimer.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "AsyncTimer.h"
|
||||||
|
|
||||||
|
AsyncTimer::AsyncTimer(unsigned long millisInterval) : AsyncTimer(millisInterval, nullptr) {}
|
||||||
|
|
||||||
|
AsyncTimer::AsyncTimer(unsigned long millisInterval, AsyncTimerCallback onFinish) {
|
||||||
|
Interval = millisInterval;
|
||||||
|
OnFinish = onFinish;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncTimer::Start() {
|
||||||
|
Reset();
|
||||||
|
_isActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncTimer::Reset() {
|
||||||
|
_startTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncTimer::Stop() {
|
||||||
|
_isActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncTimer::Update() {
|
||||||
|
if (_isActive == false) return false;
|
||||||
|
|
||||||
|
_isExpired = false;
|
||||||
|
if (static_cast<unsigned long>(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;
|
||||||
|
}
|
||||||
52
AsyncTimer.h
Normal file
52
AsyncTimer.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _ASYNCTIMER_h
|
||||||
|
#define _ASYNCTIMER_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
32
BlinkAssistant.cpp
Normal file
32
BlinkAssistant.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "BlinkAssistant.h"
|
||||||
|
#include "Face.h"
|
||||||
|
|
||||||
|
BlinkAssistant::BlinkAssistant(Face& face) : _face(face), Timer(3500) {
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlinkAssistant::Update() {
|
||||||
|
Timer.Update();
|
||||||
|
|
||||||
|
if (Timer.IsExpired()) {
|
||||||
|
Blink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlinkAssistant::Blink() {
|
||||||
|
_face.LeftEye.BlinkTransformation.Animation.Restart();
|
||||||
|
_face.RightEye.BlinkTransformation.Animation.Restart();
|
||||||
|
Timer.Reset();
|
||||||
|
}
|
||||||
40
BlinkAssistant.h
Normal file
40
BlinkAssistant.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/***************************************************
|
||||||
|
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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _BLINKASSISTANT_h
|
||||||
|
#define _BLINKASSISTANT_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
8
Common.h
Normal file
8
Common.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef COMMON_h
|
||||||
|
#define COMMON_h
|
||||||
|
|
||||||
|
#include <U8g2lib.h>
|
||||||
|
|
||||||
|
extern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;
|
||||||
|
|
||||||
|
#endif
|
||||||
85
Eye.cpp
Normal file
85
Eye.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "Eye.h"
|
||||||
|
|
||||||
|
Eye::Eye(Face& face) : _face(face) {
|
||||||
|
|
||||||
|
this->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();
|
||||||
|
}
|
||||||
62
Eye.h
Normal file
62
Eye.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYE_h
|
||||||
|
#define _EYE_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
41
EyeBlink.cpp
Normal file
41
EyeBlink.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "EyeBlink.h"
|
||||||
|
|
||||||
|
|
||||||
|
EyeBlink::EyeBlink() : Animation(40, 100, 40) { }
|
||||||
|
|
||||||
|
void EyeBlink::Update() {
|
||||||
|
auto t = Animation.GetValue();
|
||||||
|
if(Animation.GetElapsed() > 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);
|
||||||
|
}
|
||||||
|
|
||||||
43
EyeBlink.h
Normal file
43
EyeBlink.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYEBLINK_h
|
||||||
|
#define _EYEBLINK_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
43
EyeConfig.h
Normal file
43
EyeConfig.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYECONFIG_h
|
||||||
|
#define _EYECONFIG_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
216
EyeDrawer.h
Normal file
216
EyeDrawer.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYEDRAWER_h
|
||||||
|
#define _EYEDRAWER_h
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "EyeConfig.h"
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
399
EyePresets.h
Normal file
399
EyePresets.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYEPRESETS_h
|
||||||
|
#define _EYEPRESETS_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
61
EyeTransformation.cpp
Normal file
61
EyeTransformation.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "EyeTransformation.h"
|
||||||
|
|
||||||
|
|
||||||
|
EyeTransformation::EyeTransformation() : Animation(200)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeTransformation::Update()
|
||||||
|
{
|
||||||
|
auto t = Animation.GetValue();
|
||||||
|
Current.MoveX = (Destin.MoveX - Origin.MoveX) * t + Origin.MoveX;
|
||||||
|
Current.MoveY = (Destin.MoveY - Origin.MoveY) * t + Origin.MoveY;
|
||||||
|
Current.ScaleX = (Destin.ScaleX - Origin.ScaleX) * t + Origin.ScaleX;
|
||||||
|
Current.ScaleY = (Destin.ScaleY - Origin.ScaleY) * t + Origin.ScaleY;
|
||||||
|
|
||||||
|
Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeTransformation::Apply()
|
||||||
|
{
|
||||||
|
Output.OffsetX = Input->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
53
EyeTransformation.h
Normal file
53
EyeTransformation.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYETRANSFORMATION_h
|
||||||
|
#define _EYETRANSFORMATION_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
|
|
||||||
35
EyeTransition.cpp
Normal file
35
EyeTransition.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "EyeTransition.h"
|
||||||
|
|
||||||
|
EyeTransition::EyeTransition() : Animation(500){}
|
||||||
|
|
||||||
|
void EyeTransition::Update() {
|
||||||
|
float t = Animation.GetValue();
|
||||||
|
Apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeTransition::Apply(float t) {
|
||||||
|
Origin->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;
|
||||||
|
}
|
||||||
39
EyeTransition.h
Normal file
39
EyeTransition.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYETRANSITION_h
|
||||||
|
#define _EYETRANSITION_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
|
|
||||||
50
EyeVariation.cpp
Normal file
50
EyeVariation.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "EyeVariation.h"
|
||||||
|
|
||||||
|
EyeVariation::EyeVariation() : Animation(0, 1000, 0, 1000, 0){}
|
||||||
|
|
||||||
|
void EyeVariation::Clear() {
|
||||||
|
Values.OffsetX = 0;
|
||||||
|
Values.OffsetY = 0;
|
||||||
|
Values.Height = 0;
|
||||||
|
Values.Width = 0;
|
||||||
|
Values.Slope_Top = 0;
|
||||||
|
Values.Slope_Bottom = 0;
|
||||||
|
Values.Radius_Top = 0;
|
||||||
|
Values.Radius_Bottom = 0;
|
||||||
|
Values.Inverse_Radius_Top = 0;
|
||||||
|
Values.Inverse_Radius_Bottom = 0;
|
||||||
|
Values.Inverse_Offset_Top = 0;
|
||||||
|
Values.Inverse_Offset_Bottom = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeVariation::Update() {
|
||||||
|
auto t = Animation.GetValue();
|
||||||
|
Apply(2.0 * t - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeVariation::Apply(float t) {
|
||||||
|
Output.OffsetX = Input->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;;
|
||||||
|
}
|
||||||
46
EyeVariation.h
Normal file
46
EyeVariation.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _EYEVARIATION_h
|
||||||
|
#define _EYEVARIATION_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
|
|
||||||
96
Face.cpp
Normal file
96
Face.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Face.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
Face::Face(uint16_t screenWidth, uint16_t screenHeight, uint16_t eyeSize)
|
||||||
|
: LeftEye(*this), RightEye(*this), Blink(*this), Look(*this), Behavior(*this), Expression(*this)
|
||||||
|
{
|
||||||
|
Width = screenWidth;
|
||||||
|
Height = screenHeight;
|
||||||
|
EyeSize = eyeSize;
|
||||||
|
|
||||||
|
CenterX = Width / 2;
|
||||||
|
CenterY = Height / 2;
|
||||||
|
|
||||||
|
LeftEye.IsMirrored = true;
|
||||||
|
|
||||||
|
Behavior.Timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::LookFront() {
|
||||||
|
Look.LookAt(0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::LookRight() {
|
||||||
|
Look.LookAt(-1.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::LookLeft() {
|
||||||
|
Look.LookAt(1.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::LookTop() {
|
||||||
|
Look.LookAt(0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::LookBottom() {
|
||||||
|
Look.LookAt(0.0, -1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::Wait(unsigned long milliseconds) {
|
||||||
|
unsigned long start;
|
||||||
|
start = millis();
|
||||||
|
while (millis() - start < milliseconds) {
|
||||||
|
Draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::DoBlink() {
|
||||||
|
Blink.Blink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::Update() {
|
||||||
|
if(RandomBehavior) Behavior.Update();
|
||||||
|
if(RandomLook) Look.Update();
|
||||||
|
if(RandomBlink) Blink.Update();
|
||||||
|
Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Face::Draw() {
|
||||||
|
|
||||||
|
u8g2.clearBuffer();
|
||||||
|
|
||||||
|
// Only clear the section of the screen with the eyes - not the text underneath!
|
||||||
|
//u8g2.setDrawColor(0);
|
||||||
|
//u8g2.drawBox(20, 0, 64, 128);
|
||||||
|
//u8g2.setDrawColor(1);
|
||||||
|
|
||||||
|
LeftEye.CenterX = CenterX - EyeSize / 2 - EyeInterDistance;
|
||||||
|
LeftEye.CenterY = CenterY;
|
||||||
|
LeftEye.Draw();
|
||||||
|
|
||||||
|
RightEye.CenterX = CenterX + EyeSize / 2 + EyeInterDistance;
|
||||||
|
RightEye.CenterY = CenterY;
|
||||||
|
RightEye.Draw();
|
||||||
|
|
||||||
|
//u8g2.setDisplayRotation(U8G2_R3);
|
||||||
|
//_buffer.setPivot(_buffer.width(), 0);//_buffer.height()/2);
|
||||||
|
//_buffer.pushRotated(270, -1);
|
||||||
|
//_buffer.pushSprite(0, 0);
|
||||||
|
|
||||||
|
u8g2.sendBuffer(); // transfer internal memory to the display
|
||||||
|
//u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
|
||||||
|
}
|
||||||
69
Face.h
Normal file
69
Face.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/***************************************************
|
||||||
|
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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _FACE_h
|
||||||
|
#define _FACE_h
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
100
FaceBehavior.cpp
Normal file
100
FaceBehavior.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "Face.h"
|
||||||
|
#include "FaceBehavior.h"
|
||||||
|
#include "FaceEmotions.hpp"
|
||||||
|
|
||||||
|
FaceBehavior::FaceBehavior(Face& face) : _face(face), Timer(500) {
|
||||||
|
Timer.Start();
|
||||||
|
Clear();
|
||||||
|
Emotions[(int)eEmotions::Normal] = 2.0;
|
||||||
|
Emotions[(int)eEmotions::Happy] = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceBehavior::SetEmotion(eEmotions emotion, float value) {
|
||||||
|
Emotions[emotion] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FaceBehavior::GetEmotion(eEmotions emotion) {
|
||||||
|
return Emotions[emotion];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceBehavior::Clear() {
|
||||||
|
for (int emotion = 0; emotion < eEmotions::EMOTIONS_COUNT; emotion++) {
|
||||||
|
Emotions[emotion] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eEmotions FaceBehavior::GetRandomEmotion() {
|
||||||
|
float sum_of_weight = 0;
|
||||||
|
for (int emotion = 0; emotion < eEmotions::EMOTIONS_COUNT; emotion++) {
|
||||||
|
sum_of_weight += Emotions[emotion];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum_of_weight == 0) {
|
||||||
|
return eEmotions::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rand = random(0, 1000 * eEmotions::EMOTIONS_COUNT) / 1000.0;
|
||||||
|
|
||||||
|
float acc = 0;
|
||||||
|
for (int emotion = 0; emotion < eEmotions::EMOTIONS_COUNT; emotion++) {
|
||||||
|
if (Emotions[emotion] == 0) continue;
|
||||||
|
acc += Emotions[emotion] * (eEmotions::EMOTIONS_COUNT - 1) / sum_of_weight;
|
||||||
|
|
||||||
|
if (rand <= acc) {
|
||||||
|
return (eEmotions)emotion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return eEmotions::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceBehavior::Update() {
|
||||||
|
Timer.Update();
|
||||||
|
|
||||||
|
if (Timer.IsExpired()) {
|
||||||
|
Timer.Reset();
|
||||||
|
eEmotions newEmotion = GetRandomEmotion();
|
||||||
|
if (CurrentEmotion != newEmotion) {
|
||||||
|
GoToEmotion(newEmotion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceBehavior::GoToEmotion(eEmotions emotion) {
|
||||||
|
CurrentEmotion = emotion;
|
||||||
|
|
||||||
|
switch (CurrentEmotion) {
|
||||||
|
case eEmotions::Normal: _face.Expression.GoTo_Normal(); break;
|
||||||
|
case eEmotions::Angry: _face.Expression.GoTo_Angry(); break;
|
||||||
|
case eEmotions::Glee: _face.Expression.GoTo_Glee(); break;
|
||||||
|
case eEmotions::Happy: _face.Expression.GoTo_Happy(); break;
|
||||||
|
case eEmotions::Sad: _face.Expression.GoTo_Sad(); break;
|
||||||
|
case eEmotions::Worried: _face.Expression.GoTo_Worried(); break;
|
||||||
|
case eEmotions::Focused: _face.Expression.GoTo_Focused(); break;
|
||||||
|
case eEmotions::Annoyed: _face.Expression.GoTo_Annoyed(); break;
|
||||||
|
case eEmotions::Surprised: _face.Expression.GoTo_Surprised(); break;
|
||||||
|
case eEmotions::Skeptic: _face.Expression.GoTo_Skeptic(); break;
|
||||||
|
case eEmotions::Fustrated: _face.Expression.GoTo_Fustrated(); break;
|
||||||
|
case eEmotions::Unimpressed: _face.Expression.GoTo_Unimpressed(); break;
|
||||||
|
case eEmotions::Sleepy: _face.Expression.GoTo_Sleepy(); break;
|
||||||
|
case eEmotions::Suspicious: _face.Expression.GoTo_Suspicious(); break;
|
||||||
|
case eEmotions::Squint: _face.Expression.GoTo_Squint(); break;
|
||||||
|
case eEmotions::Furious: _face.Expression.GoTo_Furious(); break;
|
||||||
|
case eEmotions::Scared: _face.Expression.GoTo_Scared(); break;
|
||||||
|
case eEmotions::Awe: _face.Expression.GoTo_Awe(); break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
FaceBehavior.h
Normal file
52
FaceBehavior.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/***************************************************
|
||||||
|
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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _FACEBEHAVIOR_h
|
||||||
|
#define _FACEBEHAVIOR_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
|
|
||||||
44
FaceEmotions.hpp
Normal file
44
FaceEmotions.hpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _FACEEMOTIONS_h
|
||||||
|
#define _FACEEMOTIONS_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
181
FaceExpression.cpp
Normal file
181
FaceExpression.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "FaceExpression.h"
|
||||||
|
#include "Face.h"
|
||||||
|
|
||||||
|
FaceExpression::FaceExpression(Face& face) : _face(face)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::ClearVariations()
|
||||||
|
{
|
||||||
|
_face.RightEye.Variation1.Clear();
|
||||||
|
_face.RightEye.Variation2.Clear();
|
||||||
|
_face.LeftEye.Variation1.Clear();
|
||||||
|
_face.LeftEye.Variation2.Clear();
|
||||||
|
_face.RightEye.Variation1.Animation.Restart();
|
||||||
|
_face.LeftEye.Variation1.Animation.Restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Normal()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
|
||||||
|
_face.RightEye.Variation1.Values.Height = 3;
|
||||||
|
_face.RightEye.Variation2.Values.Width = 1;
|
||||||
|
_face.LeftEye.Variation1.Values.Height = 2;
|
||||||
|
_face.LeftEye.Variation2.Values.Width = 2;
|
||||||
|
_face.RightEye.Variation1.Animation.SetTriangle(1000, 0);
|
||||||
|
_face.LeftEye.Variation1.Animation.SetTriangle(1000, 0);
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Normal);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Normal);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Angry()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.Variation1.Values.OffsetY = 2;
|
||||||
|
_face.LeftEye.Variation1.Values.OffsetY = 2;
|
||||||
|
_face.RightEye.Variation1.Animation.SetTriangle(300, 0);
|
||||||
|
_face.LeftEye.Variation1.Animation.SetTriangle(300, 0);
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Angry);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Angry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Glee()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.Variation1.Values.OffsetY = 5;
|
||||||
|
_face.LeftEye.Variation1.Values.OffsetY = 5;
|
||||||
|
_face.RightEye.Variation1.Animation.SetTriangle(300, 0);
|
||||||
|
_face.LeftEye.Variation1.Animation.SetTriangle(300, 0);
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Glee);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Glee);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Happy()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Happy);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Happy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Sad()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Sad);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Sad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Worried()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Worried);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Worried_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Focused()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Focused);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Focused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Annoyed()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Annoyed);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Annoyed_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Surprised()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Surprised);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Surprised);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Skeptic()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Skeptic);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Skeptic_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Fustrated()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Fustrated);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Fustrated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Unimpressed()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Unimpressed);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Unimpressed_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Sleepy()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Sleepy);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Sleepy_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Suspicious()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
_face.RightEye.TransitionTo(Preset_Suspicious);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Suspicious_Alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Squint()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
|
||||||
|
_face.LeftEye.Variation1.Values.OffsetX = 6;
|
||||||
|
_face.LeftEye.Variation2.Values.OffsetY = 6;
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Squint);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Squint_Alt);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Furious()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Furious);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Furious);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Scared()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Scared);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Scared);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FaceExpression::GoTo_Awe()
|
||||||
|
{
|
||||||
|
ClearVariations();
|
||||||
|
|
||||||
|
_face.RightEye.TransitionTo(Preset_Awe);
|
||||||
|
_face.LeftEye.TransitionTo(Preset_Awe);
|
||||||
|
}
|
||||||
53
FaceExpression.h
Normal file
53
FaceExpression.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _FACEEXPRESSION_h
|
||||||
|
#define _FACEEXPRESSION_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
68
LookAssistant.cpp
Normal file
68
LookAssistant.cpp
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#include "LookAssistant.h"
|
||||||
|
#include "Face.h"
|
||||||
|
#include "EyeTransformation.h"
|
||||||
|
|
||||||
|
LookAssistant::LookAssistant(Face& face) : _face(face), Timer(4000)
|
||||||
|
{
|
||||||
|
Timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LookAssistant::LookAt(float x, float y)
|
||||||
|
{
|
||||||
|
int16_t moveX_x;
|
||||||
|
int16_t moveY_x;
|
||||||
|
int16_t moveY_y;
|
||||||
|
float scaleY_x;
|
||||||
|
float scaleY_y;
|
||||||
|
|
||||||
|
moveX_x = -25 * x;
|
||||||
|
moveY_x = -3 * x;
|
||||||
|
moveY_y = 20 * y;
|
||||||
|
scaleY_x = 1.0 - x * 0.2;
|
||||||
|
scaleY_y = 1.0 - (y > 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
44
LookAssistant.h
Normal file
44
LookAssistant.h
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
#ifndef _LOOKASSISTANT_h
|
||||||
|
#define _LOOKASSISTANT_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 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
|
||||||
|
|
||||||
BIN
anki-cozmo-faces-3-1024x576.jpg
Normal file
BIN
anki-cozmo-faces-3-1024x576.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
94
esp32-eyes.ino
Normal file
94
esp32-eyes.ino
Normal file
@@ -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 <http://www.gnu.org/licenses
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
|
// INCLUDES
|
||||||
|
#include "Face.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user