[gimp] It's alive!



commit fd6d4931c8184825d642bfebe69d045ce36f89e7
Author: Ell <ell_se yahoo com>
Date:   Sun Apr 1 01:18:35 2018 +0000

    It's alive!

 app/widgets/gimpcairo-wilber.c |  352 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 336 insertions(+), 16 deletions(-)
---
diff --git a/app/widgets/gimpcairo-wilber.c b/app/widgets/gimpcairo-wilber.c
index 4519640..30fcf7e 100644
--- a/app/widgets/gimpcairo-wilber.c
+++ b/app/widgets/gimpcairo-wilber.c
@@ -34,9 +34,21 @@
 #include "gimpcairo-wilber.h"
 
 
-static void   gimp_cairo_eyes (cairo_t *cr,
-                               gdouble  x,
-                               gdouble  y);
+static void   gimp_cairo_wilber_internal (GtkWidget *widget,
+                                          cairo_t   *cr,
+                                          gdouble    x,
+                                          gdouble    y,
+                                          gdouble    factor,
+                                          gdouble    max_eye_angle);
+static void   gimp_cairo_eyes            (GtkWidget *widget,
+                                          cairo_t   *cr,
+                                          gdouble    x,
+                                          gdouble    y,
+                                          gdouble    factor,
+                                          gdouble    max_eye_angle);
+
+
+static gboolean pointer_eyes = TRUE;
 
 
 void
@@ -67,9 +79,10 @@ gimp_cairo_draw_toolbox_wilber (GtkWidget *widget,
 
   cairo_scale (cr, factor, factor);
 
-  gimp_cairo_wilber (cr,
-                     (allocation.width  / factor - wilber_width)  / 2.0,
-                     (allocation.height / factor - wilber_height) / 2.0);
+  gimp_cairo_wilber_internal (widget, cr,
+                              (allocation.width  / factor - wilber_width)  / 2.0,
+                              (allocation.height / factor - wilber_height) / 2.0,
+                              factor, 30.0 * G_PI / 180.0);
 
   cairo_set_source_rgba (cr,
                          style->fg[state].red   / 65535.0,
@@ -122,9 +135,10 @@ gimp_cairo_draw_drop_wilber (GtkWidget *widget,
 
   /*  magic factors depend on the image used, everything else is generic
    */
-  gimp_cairo_wilber (cr,
-                     - wilber_width * 0.6,
-                     allocation.height / factor - wilber_height * 1.1);
+  gimp_cairo_wilber_internal (widget, cr,
+                              - wilber_width * 0.6,
+                              allocation.height / factor - wilber_height * 1.1,
+                              factor, 50.0 * G_PI / 180.0);
 
   cairo_set_source_rgba (cr,
                          style->fg[state].red   / 65535.0,
@@ -135,9 +149,10 @@ gimp_cairo_draw_drop_wilber (GtkWidget *widget,
 
   if (blink)
     {
-      gimp_cairo_eyes (cr,
+      gimp_cairo_eyes (widget, cr,
                        - wilber_width * 0.6,
-                       allocation.height / factor - wilber_height * 1.1);
+                       allocation.height / factor - wilber_height * 1.1,
+                       factor, 50.0 * G_PI / 180.0);
 
       cairo_set_source_rgba (cr,
                              style->fg[state].red   / 65535.0,
@@ -155,7 +170,7 @@ gimp_cairo_draw_drop_wilber (GtkWidget *widget,
  * function to do that.
  */
 static const gchar wilber_path[] =
-  "M 509.72445,438.68864 C 501.47706,469.77945 464.95038,491.54566 431.85915,497.74874 C 438.5216,503.01688 
442.87782,511.227 442.87782,520.37375 C 442.87783,536.24746 429.95607,549.0223 414.08235,549.0223 C 
398.20863,549.0223 385.28688,536.24746 385.28688,520.37375 C 385.28688,511.52403 389.27666,503.61286 
395.57098,498.3364 C 359.36952,495.90384 343.70976,463.95812 343.70975,463.95814 L 342.68134,509.64891 C 
342.68134,514.35021 342.08391,519.96098 340.18378,528.3072 C 339.84664,527.80364 339.51399,527.33515 
339.15537,526.83804 C 330.25511,514.5011 317.25269,507.81431 306.39317,508.76741 C 302.77334,509.08511 
299.47017,510.33348 296.54982,512.4403 C 284.86847,520.86757 284.97665,540.94721 296.84366,557.3965 C 
306.96274,571.42287 322.32232,578.25612 333.8664,574.73254 C 391.94635,615.17624 532.16931,642.41915 
509.72445,438.68864 z M 363.24953,501.1278 C 373.83202,501.12778 382.49549,509.79127 382.49549,520.37375 C 
382.49549,530.95624 373.83201,539.47279 363.24953,539.47279 C
  352.66706,539.47279 344.1505,530.95624 344.1505,520.37375 C 344.15049,509.79129 352.66706,501.1278 
363.24953,501.1278 z M 305.80551,516.1132 C 311.68466,516.11318 316.38344,521.83985 316.38344,528.89486 C 
316.38345,535.94982 311.68467,541.67652 305.80551,541.67652 C 299.92636,541.67652 295.08067,535.94987 
295.08067,528.89486 C 295.08065,521.83985 299.92636,516.1132 305.80551,516.1132 z M 440.821,552.54828 C 
440.821,552.54828 448.7504,554.02388 453.8965,559.45332 C 457.41881,563.16951 457.75208,569.15506 
456.98172,577.37703 C 456.21143,573.8833 454.89571,571.76659 453.8965,569.29666 C 443.01388,582.47662 
413.42981,583.08929 376.0312,569.88433 C 416.63248,578.00493 437.38806,570.56014 449.48903,561.2163 C 
446.29383,557.08917 440.821,552.54828 440.821,552.54828 z M 434.64723,524.59684 C 434.64723,532.23974 
428.44429,538.44268 420.80139,538.44268 C 413.15849,538.44268 406.95555,532.23974 406.95555,524.59684 C 
406.95555,516.95394 413.15849,510.751 420.80139,510.751 C 428.44429,5
 10.751 434.64723,516.95394 434.64723,524.59684 z M 378.00043,522.99931 C 378.00043,527.70264 
374.18324,531.51984 369.47991,531.51984 C 364.77658,531.51984 360.95939,527.70264 360.95939,522.99931 C 
360.95939,518.29599 364.77658,514.47879 369.47991,514.47879 C 374.18324,514.47879 378.00043,518.29599 
378.00043,522.99931 z ";
+  "M 509.72445,438.68864 C 501.47706,469.77945 464.95038,491.54566 431.85915,497.74874 C 438.5216,503.01688 
442.87782,511.227 442.87782,520.37375 C 442.87783,536.24746 429.95607,549.0223 414.08235,549.0223 C 
398.20863,549.0223 385.28688,536.24746 385.28688,520.37375 C 385.28688,511.52403 389.27666,503.61286 
395.57098,498.3364 C 359.36952,495.90384 343.70976,463.95812 343.70975,463.95814 L 342.68134,509.64891 C 
342.68134,514.35021 342.08391,519.96098 340.18378,528.3072 C 339.84664,527.80364 339.51399,527.33515 
339.15537,526.83804 C 330.25511,514.5011 317.25269,507.81431 306.39317,508.76741 C 302.77334,509.08511 
299.47017,510.33348 296.54982,512.4403 C 284.86847,520.86757 284.97665,540.94721 296.84366,557.3965 C 
306.96274,571.42287 322.32232,578.25612 333.8664,574.73254 C 391.94635,615.17624 532.16931,642.41915 
509.72445,438.68864 z M 363.24953,501.1278 C 373.83202,501.12778 382.49549,509.79127 382.49549,520.37375 C 
382.49549,530.95624 373.83201,539.47279 363.24953,539.47279 C
  352.66706,539.47279 344.1505,530.95624 344.1505,520.37375 C 344.15049,509.79129 352.66706,501.1278 
363.24953,501.1278 z M 305.80551,516.1132 C 311.68466,516.11318 316.38344,521.83985 316.38344,528.89486 C 
316.38345,535.94982 311.68467,541.67652 305.80551,541.67652 C 299.92636,541.67652 295.08067,535.94987 
295.08067,528.89486 C 295.08065,521.83985 299.92636,516.1132 305.80551,516.1132 z M 440.821,552.54828 C 
440.821,552.54828 448.7504,554.02388 453.8965,559.45332 C 457.41881,563.16951 457.75208,569.15506 
456.98172,577.37703 C 456.21143,573.8833 454.89571,571.76659 453.8965,569.29666 C 443.01388,582.47662 
413.42981,583.08929 376.0312,569.88433 C 416.63248,578.00493 437.38806,570.56014 449.48903,561.2163 C 
446.29383,557.08917 440.821,552.54828 440.821,552.54828 z ";
 
 static const gchar eyes_path[] =
   "M 434.64723,524.59684 C 434.64723,532.23974 428.44429,538.44268 420.80139,538.44268 C 413.15849,538.44268 
406.95555,532.23974 406.95555,524.59684 C 406.95555,516.95394 413.15849,510.751 420.80139,510.751 C 
428.44429,510.751 434.64723,516.95394 434.64723,524.59684 z M 378.00043,522.99931 C 378.00043,527.70264 
374.18324,531.51984 369.47991,531.51984 C 364.77658,531.51984 360.95939,527.70264 360.95939,522.99931 C 
360.95939,518.29599 364.77658,514.47879 369.47991,514.47879 C 374.18324,514.47879 378.00043,518.29599 
378.00043,522.99931 z ";
@@ -188,6 +203,17 @@ gimp_cairo_wilber (cairo_t *cr,
                    gdouble  x,
                    gdouble  y)
 {
+  gimp_cairo_wilber_internal (NULL, cr, x, y, 1.0, 0.0);
+}
+
+static void
+gimp_cairo_wilber_internal (GtkWidget *widget,
+                            cairo_t   *cr,
+                            gdouble    x,
+                            gdouble    y,
+                            gdouble    factor,
+                            gdouble    max_eye_angle)
+{
   wilber_get_extents (cr);
 
   cairo_save (cr);
@@ -196,12 +222,297 @@ gimp_cairo_wilber (cairo_t *cr,
   cairo_append_path (cr, wilber_cairo_path);
 
   cairo_restore (cr);
+
+  gimp_cairo_eyes (widget, cr, x, y, factor, max_eye_angle);
+}
+
+typedef struct
+{
+  gdouble x;
+  gdouble y;
+  gdouble radius;
+
+  gdouble a;
+  gdouble b;
+  gdouble r;
+} Eye;
+
+static const Eye eyes[2] =
+{
+  { .x      = (344.151 + 382.496) / 2.0,
+    .y      = (501.128 + 539.473) / 2.0,
+    .radius = (382.496 - 344.151) / 2.0,
+
+    .a      = 25.0 * G_PI / 180.0,
+    .b      = 24.0 * G_PI / 180.0,
+    .r      = 0.475
+  },
+
+  { .x      = (385.287 + 442.878) / 2.0,
+    .y      = (491.431 + 549.022) / 2.0,
+    .radius = (442.878 - 385.287) / 2.0,
+
+    .a      = 34.0 * G_PI / 180.0,
+    .b      = 19.0 * G_PI / 180.0,
+    .r      = 0.5
+  }
+};
+
+typedef struct
+{
+  gdouble a;
+  gdouble b;
+} EyeState;
+
+typedef struct
+{
+  EyeState eyes[2];
+  gdouble  x;
+  gdouble  y;
+  gdouble  factor;
+  gdouble  max_eye_angle;
+  gdouble  t;
+  gint     timeout_id;
+} EyesState;
+
+static EyesState *
+eyes_state_new (void)
+{
+  EyesState *state = g_slice_new0 (EyesState);
+  gint       i;
+
+  for (i = 0; i < 2; i++)
+    {
+      state->eyes[i].a = eyes[i].a;
+      state->eyes[i].b = eyes[i].b;
+    }
+
+  state->t = (gdouble) g_get_monotonic_time () / G_TIME_SPAN_SECOND;
+
+  return state;
 }
 
 static void
-gimp_cairo_eyes (cairo_t *cr,
-                 gdouble  x,
-                 gdouble  y)
+eyes_state_free (EyesState *state)
+{
+  if (state->timeout_id)
+    g_source_remove (state->timeout_id);
+
+  g_slice_free (EyesState, state);
+}
+
+static gboolean
+gimp_cairo_pointer_eyes_timeout (GtkWidget *widget)
+{
+  EyesState     *state;
+  gdouble        t;
+  gint           pointer_x;
+  gint           pointer_y;
+  GtkAllocation  allocation;
+  GdkWindow     *window;
+  gint           window_x;
+  gint           window_y;
+  gint           redraw = 2;
+  gint           i;
+
+  state = g_object_get_data (G_OBJECT (widget), "wilber-eyes-state");
+
+  t = (gdouble) g_get_monotonic_time () / G_TIME_SPAN_SECOND;
+
+  gdk_display_get_pointer (gtk_widget_get_display (widget),
+                           NULL, &pointer_x, &pointer_y, NULL);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  window = gtk_widget_get_window (widget);
+
+  if (window)
+    gdk_window_get_origin (window, &window_x, &window_y);
+
+  for (i = 0; i < 2; i++)
+    {
+      const Eye   *eye = &eyes[i];
+      gdouble      a;
+      gdouble      b;
+      gdouble      c;
+      GimpVector3  u;
+      GimpVector3  v;
+      GimpVector3  w;
+
+      if (pointer_eyes)
+        {
+          gdouble screen_x;
+          gdouble screen_y;
+          gdouble z = 220.0 * state->factor;
+          gdouble d;
+
+          screen_x = (eye->x + state->x - wilber_x1) * state->factor;
+          screen_y = (eye->y + state->y - wilber_y1) * state->factor;
+
+          if (! gtk_widget_get_has_window (widget))
+            {
+              screen_x += allocation.x;
+              screen_y += allocation.y;
+            }
+
+          if (window)
+            {
+              screen_x += window_x;
+              screen_y += window_y;
+            }
+
+          d = sqrt (SQR (pointer_x - screen_x) + SQR (pointer_y - screen_y));
+          a = atan2 (pointer_y - screen_y, pointer_x - screen_x);
+          b = atan (d / z);
+          b = MIN (b, state->max_eye_angle);
+        }
+      else
+        {
+          a = eyes[i].a;
+          b = eyes[i].b;
+        }
+
+      if (a == state->eyes[i].a && b == state->eyes[i].b)
+        {
+          redraw--;
+
+          continue;
+        }
+
+      u.x = sin (state->eyes[i].b) * cos (state->eyes[i].a);
+      u.y = sin (state->eyes[i].b) * sin (state->eyes[i].a);
+      u.z = cos (state->eyes[i].b);
+
+      v.x = sin (b) * cos (a);
+      v.y = sin (b) * sin (a);
+      v.z = cos (b);
+
+      c = acos (gimp_vector3_inner_product (&u, &v));
+
+      if (c < 1e-2)
+        {
+          state->eyes[i].a = a;
+          state->eyes[i].b = b;
+
+          continue;
+        }
+
+      c *= 1.0 - exp (-(t - state->t) * 15.0);
+
+      w = gimp_vector3_cross_product (&u, &v);
+      w = gimp_vector3_cross_product (&w, &u);
+      gimp_vector3_normalize (&w);
+
+      v.x = u.x * cos (c) + w.x * sin (c);
+      v.y = u.y * cos (c) + w.y * sin (c);
+      v.z = u.z * cos (c) + w.z * sin (c);
+
+      a = atan2 (v.y, v.x);
+      b = acos (v.z);
+
+      state->eyes[i].a = a;
+      state->eyes[i].b = b;
+    }
+
+  state->t = t;
+
+  if (redraw)
+    {
+      state->timeout_id = 0;
+
+      gtk_widget_queue_draw (widget);
+
+      return G_SOURCE_REMOVE;
+    }
+  else if (! pointer_eyes)
+    {
+      state->timeout_id = 0;
+
+      g_object_set_data (G_OBJECT (widget), "wilber-eyes-state", NULL);
+      gtk_widget_queue_draw (widget);
+
+      return G_SOURCE_REMOVE;
+    }
+
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+gimp_cairo_pointer_eyes (GtkWidget *widget,
+                         cairo_t   *cr,
+                         gdouble    x,
+                         gdouble    y,
+                         gdouble    factor,
+                         gdouble    max_eye_angle)
+{
+  EyesState *state;
+  gint       i;
+
+  state = g_object_get_data (G_OBJECT (widget), "wilber-eyes-state");
+
+  if (! state)
+    {
+      state = eyes_state_new ();
+
+      g_object_set_data_full (G_OBJECT (widget), "wilber-eyes-state", state,
+                              (GDestroyNotify) eyes_state_free);
+    }
+
+  for (i = 0; i < 2; i++)
+    {
+      const Eye *eye = &eyes[i];
+      gdouble    R = eye->radius;
+      gdouble    r = eye->r * eye->radius;
+      gint       j;
+
+      cairo_save (cr);
+
+      cairo_translate (cr, eye->x, eye->y);
+      cairo_rotate (cr, state->eyes[i].a);
+
+      for (j = 0; j < 32; j++)
+        {
+          gdouble a = -2.0 * G_PI * j / 32.0;
+          gdouble u = r * cos (a);
+          gdouble v = r * sin (a);
+          gdouble w = sqrt (SQR (R) - SQR (v));
+          gdouble b = asin (u / w);
+
+          b = CLAMP (b + state->eyes[i].b, -G_PI / 2.0, +G_PI / 2.0);
+          u = w * sin (b);
+
+          if (j == 0)
+            cairo_move_to (cr, u, v);
+          else
+            cairo_line_to (cr, u, v);
+        }
+
+      cairo_close_path (cr);
+
+      cairo_restore (cr);
+    }
+
+  state->x             = x;
+  state->y             = y;
+  state->factor        = factor;
+  state->max_eye_angle = max_eye_angle;
+
+  if (! state->timeout_id)
+    {
+      state->timeout_id =
+        g_timeout_add (17,
+                       (GSourceFunc) gimp_cairo_pointer_eyes_timeout,
+                       widget);
+    }
+}
+
+static void
+gimp_cairo_eyes (GtkWidget *widget,
+                 cairo_t   *cr,
+                 gdouble    x,
+                 gdouble    y,
+                 gdouble    factor,
+                 gdouble    max_eye_angle)
 {
   wilber_get_extents (cr);
   eyes_get_extents (cr);
@@ -209,7 +520,16 @@ gimp_cairo_eyes (cairo_t *cr,
   cairo_save (cr);
 
   cairo_translate (cr, x - wilber_x1, y - wilber_y1);
-  cairo_append_path (cr, eyes_cairo_path);
+  if (widget        &&
+      (pointer_eyes ||
+       g_object_get_data (G_OBJECT (widget), "wilber-eyes-state")))
+    {
+      gimp_cairo_pointer_eyes (widget, cr, x, y, factor, max_eye_angle);
+    }
+  else
+    {
+      cairo_append_path (cr, eyes_cairo_path);
+    }
 
   cairo_restore (cr);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]