subdir(src / 'glad')
deps = [dependency('glfw3'), glad_dep]
-srcs = [src/'main.cc', src/'eye.cc', src/'log.cc', src/'mouth.cc', src/'animator.cc']
+srcs = [src/'window.cc', src/'main.cc', src/'animator.cc', src/'state.cc', src/'eye.cc', src/'log.cc', src/'mouth.cc']
executable('gummi',
sources: srcs,
#include <random>
-struct {
- double blink;
-} animation;
-
-std::random_device rd;
-
-const double blinkDuration = 0.2;
-
-void blink(double dt) {
- if (animation.blink < -1) {
- animation.blink = blinkDuration;
- } else if (animation.blink <= 0.0) {
- auto roll = rd();
- if (roll > rd.max() * 0.8)
- animation.blink -= dt;
- } else {
- animation.blink -= dt;
- }
+animator::animator(double duration) {
+ target = duration;
+ current = 0;
+}
- if (animation.blink <= 0.0) {
- eyes[0].blinkFrame = open;
- eyes[1].blinkFrame = open;
- } else {
- const double frameTimings[BLINKFRAME_MAX] {blinkDuration, blinkDuration*0.6, blinkDuration*0.3, 0};
- for (int i = open; i < BLINKFRAME_MAX; i++) {
- auto frame = blinkDuration - animation.blink;
- if (frameTimings[i+1] <= frame && frame <= frameTimings[i]) {
- eyes[0].blinkFrame = (blinkFrame_t)(i+1);
- eyes[1].blinkFrame = (blinkFrame_t)(i+1);
- }
- }
- }
+void animator::update(double deltaTime) {
+ if (target > 0)
+ current += deltaTime;
+ if (target < 0)
+ current -= deltaTime;
}
-void updateAnimations(double dt) {
- blink(dt);
+double animator::getRatio() {
+ return current / target;
}
-void initAnimator() {
- animation.blink = 0.0;
+bool animator::done() {
+ if (target > 0)
+ return current >= target;
+ if (target < 0)
+ return -current >= -target;
+ return true;
}
-void initAnimator();
-void updateAnimations(double dt);
+class animator {
+ public:
+ animator(double duration);
+ ~animator() = default;
+
+ void update(double deltaTime);
+ double getRatio();
+ bool done();
+ private:
+ double target;
+ double current;
+};
eye_t eyes[2];
+blinkFrame_t ratioToBlink(double ratio) {
+ if (ratio > 0.6)
+ return open;
+ if (ratio > 0.3)
+ return blink_60;
+ if (ratio > 0.0)
+ return blink_30;
+ return closed;
+}
+
void setEyeShaderProgram() {
GLint status;
extern eye_t eyes[2];
+blinkFrame_t ratioToBlink(double ratio);
+
void initEyes();
void drawEyes();
#include <iostream>
#include <vector>
+#include "window.h"
#include "log.h"
#include "eye.h"
#include "mouth.h"
-#include "animator.h"
+#include "state.h"
float triangles[] = {
-0.5,0.5,0,
}
int main() {
- GLFWwindow* window;
-
if (!glfwInit()) {
printf("could not initialize glfw\n");
exit(1);
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
- window = glfwCreateWindow(800, 480, "gummi", NULL, NULL);
+ window = glfwCreateWindow(SCREENWIDTH, SCREENHEIGHT, "gummi", NULL, NULL);
if (!window) {
printf("could not create window\n");
useShaders();
- initEyes();
- initMouth();
- initAnimator();
+ initState();
GLuint VBOS[2];
glGenBuffers(2, (GLuint*) &VBOS);
glfwPollEvents();
// update
- updateAnimations(currentTime - lastUpdateTime);
+ updateState(currentTime - lastUpdateTime);
lastUpdateTime = currentTime;
if (currentTime - lastRenderTime > targetRate) {
--- /dev/null
+#include "state.h"
+
+#define GLFW_INCLUDE_NONE
+#include <GLFW/glfw3.h>
+#include <random>
+#include <memory>
+
+#include "animator.h"
+#include "eye.h"
+#include "mouth.h"
+#include "window.h"
+
+constexpr double irritationPerSecond = 1;
+constexpr double irritationThresh = 5;
+
+struct {
+ double leftEyeIrritate;
+ double rightEyeIrritate;
+
+ std::unique_ptr<animator> blinkAnimator;
+ std::random_device rd;
+} state;
+
+void initEyeIrritation() {
+ if (state.blinkAnimator)
+ state.blinkAnimator.release();
+
+ auto initIrr = state.rd() * 0.8 * irritationThresh / state.rd.max();
+
+ state.leftEyeIrritate = initIrr;
+ state.rightEyeIrritate = initIrr;
+ state.blinkAnimator.release();
+}
+
+void initState() {
+ initEyes();
+ initMouth();
+
+ initEyeIrritation();
+}
+
+void closeOnTouched() {
+ double x, y;
+ glfwGetCursorPos(window, &x, &y);
+ int close = 0;
+
+ if (x < SCREENWIDTH/2) {
+ close = 0;
+ } else {
+ close = 1;
+ }
+ eyes[close].blinkFrame = closed;
+ eyes[1-close].blinkFrame = blink_30;
+}
+
+void updateEyeState(double deltaTime) {
+ state.leftEyeIrritate += deltaTime*irritationPerSecond;
+ state.rightEyeIrritate += deltaTime*irritationPerSecond;
+
+ auto press = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1);
+
+ // overwrite when touched
+ if (press == GLFW_PRESS) {
+ closeOnTouched();
+ state.leftEyeIrritate = irritationThresh*0.9;
+ state.rightEyeIrritate = irritationThresh*0.9;
+ return;
+ }
+
+ if (state.blinkAnimator) {
+ state.blinkAnimator->update(deltaTime);
+ auto blinkRatio = state.blinkAnimator->getRatio();
+ auto blinkFrame = ratioToBlink(blinkRatio);
+ eyes[0].blinkFrame = blinkFrame;
+ eyes[1].blinkFrame = blinkFrame;
+
+ if (state.blinkAnimator->done()) {
+ initEyeIrritation();
+ }
+ } else if (state.leftEyeIrritate > irritationThresh || state.rightEyeIrritate > irritationThresh) {
+ state.blinkAnimator = std::make_unique<animator>(0.2);
+ } else {
+ eyes[0].blinkFrame = open;
+ eyes[1].blinkFrame = open;
+ }
+}
+
+void updateState(double deltaTime) {
+ updateEyeState(deltaTime);
+}
--- /dev/null
+void initState();
+void updateState(double deltaTime);
--- /dev/null
+#include "window.h"
+
+GLFWwindow* window;
+
--- /dev/null
+#pragma once
+#include <GLFW/glfw3.h>
+
+#define SCREENWIDTH 800
+#define SCREENHEIGHT 480
+
+extern GLFWwindow* window;