]> git.localhorst.tv Git - ffmpeg-test.git/commitdiff
refine drawing game
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 15 Oct 2024 12:19:32 +0000 (14:19 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Tue, 15 Oct 2024 12:19:32 +0000 (14:19 +0200)
src/app/Application.h
src/app/DrawingGame.h
src/app/Game.h
src/app/Timer.h [new file with mode: 0644]
src/ws/Connection.cpp

index 24b68c5a3a75fad954dffe8f312053d232cccb41..f17ee82743cb22bf0a688ef1d9a90b86676b3bfa 100644 (file)
@@ -130,9 +130,9 @@ private:
        }
 
        void HandleTwitch(const twitch::IRCMessage &msg) {
-               std::string text = msg.GetText();
-               if (text.length() < 2 || text[0] != '$') return;
-               drawing_game.QueueCommands(text);
+               if (state.HasGame()) {
+                       state.GetGame().Handle(msg);
+               }
        }
 
 private:
index f42499aaa06ebca8579df0855455033756055590..080ee613669c909fc1a83bd89e22fb078810ca12 100644 (file)
@@ -4,7 +4,9 @@
 #include <sstream>
 #include <vector>
 
+#include "Clock.h"
 #include "Game.h"
+#include "Timer.h"
 #include "../gfx/ColorRGB.h"
 #include "../pango/Layout.h"
 
@@ -18,17 +20,28 @@ public:
        , w(w), h(h), x(0), y(0)
        , step_size(1)
        , color_intensity(9)
+       , brush{ 0, 0, 0 }
        , pos{ 760, 100 }
        , font_color{ 1, 1, 1 }
        , cursor_font("DejaVu Sans 16px")
        , cursor_layout(ctx.CreateLayout())
-       , text_dirty(true) {
+       , text_dirty(true)
+       , draw_timer(150) {
+               cursor_layout.SetFont(cursor_font);
                cells.resize(w * h, base_color);
        }
 
 public:
+       virtual void Handle(const twitch::IRCMessage &msg) {
+               std::string text = msg.GetText();
+               if (!text.empty()) {
+                       QueueCommands(text);
+               }
+       }
+
        virtual void Update(cairo::Context &ctx, const Clock &now) {
-               if (!command_queue.empty()) {
+               int amount = draw_timer.ActivationsBetween(last_update, now);
+               while (amount > 0 && !command_queue.empty()) {
                        const char c = command_queue.back();
                        command_queue.pop_back();
                        if (!command_queue.empty()) {
@@ -36,10 +49,12 @@ public:
                        } else {
                                InterpretCharacter(c);
                        }
+                       --amount;
                }
                if (text_dirty) {
                        UpdateText(ctx);
                }
+               last_update = now;
        }
 
        virtual void Render(cairo::Context &ctx) const {
@@ -48,6 +63,16 @@ public:
                ctx.DrawLayout(cursor_layout);
 
                gfx::Rectangle r{ 0, 0, 10, 10 };
+               r.x = pos.x + (w - 1) * r.w;
+               r.y = pos.y + 30 - 2 * r.h;
+               ctx.SetSourceColor(brush);
+               ctx.Rectangle(r);
+               ctx.Fill();
+               ctx.SetSourceColor({ 0.5, 0.5, 0.5 });
+               ctx.SetLineWidth(1);
+               ctx.Rectangle(r);
+               ctx.Stroke();
+
                for (int cy = 0; cy < h; ++cy) {
                        for (int cx = 0; cx < w; ++cx) {
                                r.x = pos.x + cx * r.w;
@@ -89,95 +114,90 @@ public:
                        case '5': case '6': case '7': case '8': case '9':
                                if (IsMovementCharacter(next)) {
                                        SetStepSize(c - '0');
-                               } else {
+                               } else if (IsColorCharacter(next)) {
                                        SetColorIntensity(c - '0');
                                }
                                break;
-                       case 'u': case 'U':
-                       case 'n': case 'N':
+                       case 'w': case 'W':
+                       case 'i': case 'I':
                                MoveUp();
                                break;
-                       case 'd': case 'D':
                        case 's': case 'S':
+                       case 'k': case 'K':
                                MoveDown();
                                break;
-                       case 'l': case 'L':
-                       case 'w': case 'W':
+                       case 'a': case 'A':
+                       case 'j': case 'J':
                                MoveLeft();
                                break;
-                       case 'r': case 'R':
-                       case 'e': case 'E':
+                       case 'd': case 'D':
+                       case 'l': case 'L':
                                MoveRight();
                                break;
-                       case 'a': case 'A':
+                       case 'r': case 'R':
                                SetRed();
                                break;
-                       case 'b': case 'B':
+                       case 'g': case 'G':
                                SetGreen();
                                break;
-                       case 'c': case 'C':
+                       case 'b': case 'B':
                                SetBlue();
                                break;
-                       case 'f': case 'F':
-                               ClearRed();
-                               break;
-                       case 'g': case 'G':
-                               ClearGreen();
-                               break;
-                       case 'h': case 'H':
-                               ClearBlue();
-                               break;
-                       case 'i': case 'I':
-                               SetYellow();
-                               break;
-                       case 'j': case 'J':
+                       case 'c': case 'C':
                                SetCyan();
                                break;
-                       case 'k': case 'K':
-                               SetMagenta();
-                               break;
                        case 'm': case 'M':
-                               ClearYellow();
-                               break;
-                       case 'o': case 'O':
-                               ClearCyan();
+                               SetMagenta();
                                break;
-                       case 'p': case 'P':
-                               ClearMagenta();
+                       case 'y': case 'Y':
+                               SetYellow();
                                break;
                        case 'q': case 'Q':
-                               InvertRed();
+                               Pick();
                                break;
+                       case 'e': case 'E':
+                       case 'f': case 'F':
+                       case 'h': case 'H':
+                       case 'n': case 'N':
+                       case 'o': case 'O':
+                       case 'p': case 'P':
                        case 't': case 'T':
-                               InvertGreen();
-                               break;
+                       case 'u': case 'U':
                        case 'v': case 'V':
-                               InvertBlue();
+                               Paste();
                                break;
                        case 'x': case 'X':
-                               InvertColor();
-                               break;
-                       case 'y': case 'Y':
-                               SetColor({ 1, 1, 1 });
-                               break;
                        case 'z': case 'Z':
-                               SetColor({ 0, 0, 0 });
+                               InvertColor();
                                break;
                        default:
                                break;
                }
        }
 
+       bool IsColorCharacter(char c) const {
+               switch (c) {
+                       case 'r': case 'R':
+                       case 'g': case 'G':
+                       case 'b': case 'B':
+                       case 'c': case 'C':
+                       case 'm': case 'M':
+                       case 'y': case 'Y':
+                               return true;
+               }
+               return false;
+       }
+
        bool IsMovementCharacter(char c) const {
                switch (c) {
-                       case 'u': case 'U':
-                       case 'n': case 'N':
-                       case 'd': case 'D':
+                       case 'w': case 'W':
+                       case 'a': case 'A':
                        case 's': case 'S':
+                       case 'd': case 'D':
+                       case 'i': case 'I':
+                       case 'j': case 'J':
+                       case 'k': case 'K':
                        case 'l': case 'L':
-                       case 'w': case 'W':
-                       case 'r': case 'R':
-                       case 'e': case 'E':
                                return true;
                }
                return false;
@@ -217,96 +237,66 @@ public:
        }
 
        void SetRed() {
-               cells[y * w + x].r = double(color_intensity) / 9.0;
+               brush.r = double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
        void SetGreen() {
-               cells[y * w + x].g = double(color_intensity) / 9.0;
+               brush.g = double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
        void SetBlue() {
-               cells[y * w + x].b = double(color_intensity) / 9.0;
-       }
-
-       void ClearRed() {
-               cells[y * w + x].r = 0;
-       }
-
-       void ClearGreen() {
-               cells[y * w + x].g = 0;
-       }
-
-       void ClearBlue() {
-               cells[y * w + x].b = 0;
-       }
-
-       void SetYellow() {
-               cells[y * w + x].r = double(color_intensity) / 9.0;
-               cells[y * w + x].g = double(color_intensity) / 9.0;
+               brush.b = double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
        void SetCyan() {
-               cells[y * w + x].g = double(color_intensity) / 9.0;
-               cells[y * w + x].b = double(color_intensity) / 9.0;
+               brush.r = 1.0 - double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
        void SetMagenta() {
-               cells[y * w + x].r = double(color_intensity) / 9.0;
-               cells[y * w + x].b = double(color_intensity) / 9.0;
-       }
-
-       void ClearYellow() {
-               cells[y * w + x].r = 0;
-               cells[y * w + x].g = 0;
-       }
-
-       void ClearCyan() {
-               cells[y * w + x].g = 0;
-               cells[y * w + x].b = 0;
+               brush.g = 1.0 - double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
-       void ClearMagenta() {
-               cells[y * w + x].r = 0;
-               cells[y * w + x].b = 0;
-       }
-
-       void InvertRed() {
-               cells[y * w + x].r = 1.0 - cells[y * w + x].r;
+       void SetYellow() {
+               brush.b = 1.0 - double(color_intensity) / 9.0;
+               SetColorIntensity(9);
        }
 
-       void InvertGreen() {
-               cells[y * w + x].g = 1.0 - cells[y * w + x].g;
+       void Pick() {
+               brush = CurrentCell();
        }
 
-       void InvertBlue() {
-               cells[y * w + x].b = 1.0 - cells[y * w + x].b;
+       void Paste() {
+               CurrentCell() = brush;
        }
 
        void InvertColor() {
-               cells[y * w + x].r = 1.0 - cells[y * w + x].r;
-               cells[y * w + x].g = 1.0 - cells[y * w + x].g;
-               cells[y * w + x].b = 1.0 - cells[y * w + x].b;
+               brush.r = 1.0 - brush.r;
+               brush.g = 1.0 - brush.g;
+               brush.b = 1.0 - brush.b;
        }
 
        void SetColorIntensity(int m) {
-               int new_intensity = std::max(0, std::min(9, m));
-               text_dirty = new_intensity != color_intensity;
-               color_intensity = new_intensity;
+               color_intensity = std::max(0, std::min(9, m));
        }
 
        void SetStepSize(int m) {
-               int new_size = std::max(0, std::min(9, m));
-               text_dirty = new_size != step_size;
-               step_size = new_size;
+               step_size = std::max(0, std::min(9, m));
+       }
+
+       gfx::ColorRGB &CurrentCell() {
+               return cells[y * w + x];
        }
 
 private:
        void UpdateText(cairo::Context &ctx) {
                if (!text_dirty) return;
                std::stringstream out;
-               out << "Cursor: " << x << ", " << y;
-               out << "  Schrittgröße: " << step_size;
-               out << "  Deckkraft: " << color_intensity;
+               out << "Cursor: " << (x + 1) << ", " << (y + 1);
                cursor_layout.SetText(out.str());
                ctx.UpdateLayout(cursor_layout);
                text_dirty = false;
@@ -317,6 +307,7 @@ private:
        int w, h, x, y;
        int step_size;
        int color_intensity;
+       gfx::ColorRGB brush;
 
        std::string command_queue;
 
@@ -327,6 +318,9 @@ private:
        pango::Layout cursor_layout;
        bool text_dirty;
 
+       Clock last_update;
+       Timer draw_timer;
+
 };
 
 }
index eabc3ce0d17262f31d29bcba3c268458a1540440..c8512e1a6729c5ed11921e233beef3375dc690f1 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "Clock.h"
 #include "../cairo/Context.h"
+#include "../twitch/IRCMessage.h"
 
 namespace app {
 
@@ -13,6 +14,8 @@ public:
        }
 
 public:
+       virtual void Handle(const twitch::IRCMessage &) = 0;
+
        virtual void Update(cairo::Context &, const Clock &) = 0;
 
        virtual void Render(cairo::Context &) const = 0;
diff --git a/src/app/Timer.h b/src/app/Timer.h
new file mode 100644 (file)
index 0000000..0944358
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef TEST_APP_TIMER_H_
+#define TEST_APP_TIMER_H_
+
+#include "Clock.h"
+
+namespace app {
+
+class Timer {
+
+public:
+       explicit Timer(int64_t interval)
+       : start(), interval(interval) {
+       }
+       Timer(const Clock &start, int64_t interval)
+       : start(start), interval(interval) {
+       }
+       ~Timer() {
+       }
+
+public:
+       int ActivationsAt(const Clock &now) const {
+               const Clock diff(now.Difference(start));
+               return diff.GetMS() / interval;
+       }
+
+       int ActivationsBetween(const Clock &from, const Clock &till) const {
+               return ActivationsAt(till) - ActivationsAt(from);
+       }
+
+private:
+       Clock start;
+       int64_t interval;
+
+};
+
+}
+
+#endif
index 2109aff7d1b3e77d89365b9ab40ad1ea2a83df19..82e9c02292472d6a1c346e9237e4ccd229c61772 100644 (file)
@@ -91,7 +91,7 @@ int HttpsConnection::ProtoCallback(lws_callback_reasons reason, void *in, size_t
                        break;
                case LWS_CALLBACK_WSI_CREATE:
                case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION:
-               case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
+               case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL:
                case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
                        break;
                default:
@@ -217,7 +217,7 @@ int TwitchConnection::ProtoCallback(lws_callback_reasons reason, void *in, size_
                        break;
                case LWS_CALLBACK_CLIENT_CLOSED:
                        connected = false;
-                       std::cout << "twitch connection closed :/" << std::endl;
+                       std::cout << "twitch connection closed" << std::endl;
                        break;
                case LWS_CALLBACK_CLIENT_RECEIVE:
                        if (lws_is_first_fragment(wsi)) {