[gimp/wip/alxsa/mypaint-brush-v2] Implement draw_dab_2 API



commit d2ac22c4413ae3d3b68c457cb3961a7fa7771b4a
Author: Alx Sa <cmyk student gmail com>
Date:   Sat Oct 8 17:47:22 2022 +0000

    Implement draw_dab_2 API

 app/core/gimpmybrush-load.c    |  26 ++++---
 app/core/gimpmybrush.c         |   4 +-
 app/paint/gimpmybrushcore.c    |   2 -
 app/paint/gimpmybrushoptions.c |   4 +-
 app/paint/gimpmybrushsurface.c | 159 +++++++++++++++++++++++++++++++++--------
 5 files changed, 150 insertions(+), 45 deletions(-)
---
diff --git a/app/core/gimpmybrush-load.c b/app/core/gimpmybrush-load.c
index eeca69347d..61e1e32898 100644
--- a/app/core/gimpmybrush-load.c
+++ b/app/core/gimpmybrush-load.c
@@ -139,25 +139,29 @@ gimp_mybrush_load (GimpContext   *context,
     mypaint_brush_get_base_value (mypaint_brush,
                                   MYPAINT_BRUSH_SETTING_HARDNESS);
 
-  brush->priv->pigment =
+  brush->priv->eraser =
     mypaint_brush_get_base_value (mypaint_brush,
-                                  MYPAINT_BRUSH_SETTING_PAINT_MODE);
+                                  MYPAINT_BRUSH_SETTING_ERASER) > 0.5f;
 
-  brush->priv->posterize =
+  brush->priv->offset_by_random =
     mypaint_brush_get_base_value (mypaint_brush,
-                                  MYPAINT_BRUSH_SETTING_POSTERIZE);
+                                  MYPAINT_BRUSH_SETTING_OFFSET_BY_RANDOM);
 
-  brush->priv->posterize_num =
+  /* Version 2 MyPaint Brush options */
+  brush->priv->pigment =
     mypaint_brush_get_base_value (mypaint_brush,
-                                  MYPAINT_BRUSH_SETTING_POSTERIZE_NUM);
+                                  MYPAINT_BRUSH_SETTING_PAINT_MODE);
 
-  brush->priv->eraser =
+  brush->priv->posterize =
     mypaint_brush_get_base_value (mypaint_brush,
-                                  MYPAINT_BRUSH_SETTING_ERASER) > 0.5f;
+                                  MYPAINT_BRUSH_SETTING_POSTERIZE);
 
-  brush->priv->offset_by_random =
-    mypaint_brush_get_base_value (mypaint_brush,
-                                  MYPAINT_BRUSH_SETTING_OFFSET_BY_RANDOM);
+  if (! mypaint_brush_is_constant (mypaint_brush, MYPAINT_BRUSH_SETTING_POSTERIZE_NUM))
+    brush->priv->posterize_num =
+      mypaint_brush_get_base_value (mypaint_brush,
+                                    MYPAINT_BRUSH_SETTING_POSTERIZE_NUM);
+  else
+    brush->priv->posterize_num = 1.0f;
 
   mypaint_brush_unref (mypaint_brush);
 
diff --git a/app/core/gimpmybrush.c b/app/core/gimpmybrush.c
index 5117a3ead3..1a04bfa76c 100644
--- a/app/core/gimpmybrush.c
+++ b/app/core/gimpmybrush.c
@@ -101,7 +101,7 @@ gimp_mybrush_init (GimpMybrush *brush)
   brush->priv->radius        = 1.0;
   brush->priv->opaque        = 1.0;
   brush->priv->hardness      = 1.0;
-  brush->priv->pigment       = 0.0;
+  brush->priv->pigment       = -0.1;
   brush->priv->posterize     = 0.0;
   brush->priv->posterize_num = 1.0;
   brush->priv->eraser        = FALSE;
@@ -270,7 +270,7 @@ gimp_mybrush_get_hardness (GimpMybrush *brush)
 gdouble
 gimp_mybrush_get_pigment (GimpMybrush *brush)
 {
-  g_return_val_if_fail (GIMP_IS_MYBRUSH (brush), -1.0);
+  g_return_val_if_fail (GIMP_IS_MYBRUSH (brush), -0.1);
 
   return brush->priv->pigment;
 }
diff --git a/app/paint/gimpmybrushcore.c b/app/paint/gimpmybrushcore.c
index fcae5a3dab..1c61c0bded 100644
--- a/app/paint/gimpmybrushcore.c
+++ b/app/paint/gimpmybrushcore.c
@@ -241,8 +241,6 @@ gimp_mybrush_core_paint (GimpPaintCore    *paint_core,
 
     case GIMP_PAINT_STATE_FINISH:
       gimp_symmetry_set_stateful (sym, FALSE);
-      /*mypaint_surface_unref (mypaint_surface2_to_surface (
-                             (MyPaintSurface2 *) mybrush->private->surface));*/
       mybrush->private->surface = NULL;
 
       g_list_free_full (mybrush->private->brushes,
diff --git a/app/paint/gimpmybrushoptions.c b/app/paint/gimpmybrushoptions.c
index 2d1d1a57f6..9ef71d50e3 100644
--- a/app/paint/gimpmybrushoptions.c
+++ b/app/paint/gimpmybrushoptions.c
@@ -125,8 +125,8 @@ gimp_mybrush_options_class_init (GimpMybrushOptionsClass *klass)
   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_PIGMENT,
                            "pigment",
                            _("Pigment"),
-                           NULL,
-                           -1.0, 1.0, -1.0,
+                           _("Enable spectral blending"),
+                           -0.1, 1.0, -0.1,
                            GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_POSTERIZE,
diff --git a/app/paint/gimpmybrushsurface.c b/app/paint/gimpmybrushsurface.c
index a358ba81ba..b7145b9421 100644
--- a/app/paint/gimpmybrushsurface.c
+++ b/app/paint/gimpmybrushsurface.c
@@ -26,6 +26,10 @@
 #include "libgimpmath/gimpmath.h"
 
 #include <cairo.h>
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include "fastapprox/fastpow.h"
 #include "libgimpcolor/gimpcolor.h"
@@ -90,6 +94,9 @@ void
 spectral_to_rgb                  (float    *spectral,
                                   float    *rgb_);
 
+float
+spectral_blend_factor            (float x);
+
 void
 get_color_pixels_accumulate      (float    *mask,
                                   float    *pixel,
@@ -101,7 +108,8 @@ get_color_pixels_accumulate      (float    *mask,
                                   float     paint,
                                   float     pixel_weight,
                                   uint16_t  sample_interval,
-                                  float     random_sample_rate);
+                                  float     random_sample_rate,
+                                  uint16_t  interval_counter);
 
 /* --- Taken from mypaint-tiled-surface.c --- */
 static inline float
@@ -318,18 +326,19 @@ get_color_pixels_accumulate (float   *mask,
                              float   *sum_g,
                              float   *sum_b,
                              float   *sum_a,
-                             float    pixel_weight,
                              float    paint,
+                             float    pixel_weight,
                              uint16_t sample_interval,
-                             float    random_sample_rate)
+                             float    random_sample_rate,
+                             uint16_t interval_counter)
 {
-  uint16_t interval_counter = 0;
   const int random_sample_threshold = (int)(random_sample_rate * G_MAXINT);
   float avg_spectral[10] = {0};
   float avg_rgb[3] = {*sum_r, *sum_g, *sum_b};
   float spec_rgb[3] = {0};
 
   rgb_to_spectral (*sum_r, *sum_g, *sum_b, avg_spectral);
+
   if (interval_counter == 0 || rand() < random_sample_threshold)
     {
       float fac_a, fac_b;
@@ -354,7 +363,8 @@ get_color_pixels_accumulate (float   *mask,
                            spectral);
 
           for (int i = 0; i < 10; i++)
-            avg_spectral[i] = fastpow (spectral[i], fac_a) * fastpow (avg_spectral[i], fac_b);
+            avg_spectral[i] =
+              fastpow (spectral[i], fac_a) * fastpow (avg_spectral[i], fac_b);
         }
 
       if (paint < 1.0f && pixel[ALPHA] > 0)
@@ -365,13 +375,23 @@ get_color_pixels_accumulate (float   *mask,
 
       *sum_a += a;
     }
-  interval_counter = (interval_counter + 1) % sample_interval;
-
   spectral_to_rgb (avg_spectral, spec_rgb);
 
-  *sum_r = (float) spec_rgb[0] * paint + (1.0 - paint) * avg_rgb[0];
-  *sum_g = (float) spec_rgb[1] * paint + (1.0 - paint) * avg_rgb[1];
-  *sum_b = (float) spec_rgb[2] * paint + (1.0 - paint) * avg_rgb[2];
+  *sum_r = spec_rgb[0] * paint + (1.0 - paint) * avg_rgb[0];
+  *sum_g = spec_rgb[1] * paint + (1.0 - paint) * avg_rgb[1];
+  *sum_b = spec_rgb[2] * paint + (1.0 - paint) * avg_rgb[2];
+}
+
+// Fast sigmoid-like function with constant offsets, used to get a
+// fairly smooth transition between additive and spectral blending.
+float
+spectral_blend_factor (float x)
+{
+  const float ver_fac = 1.65; // vertical compression factor
+  const float hor_fac = 8.0f; // horizontal compression factor
+  const float hor_offs = 3.0f; // horizontal offset (slightly left of center)
+  const float b = x * hor_fac - hor_offs;
+  return 0.5 + b / (1 + fabsf(b) * ver_fac);
 }
 /* -- end mypaint code */
 
@@ -836,16 +856,79 @@ gimp_mypaint_surface_draw_dab_2 (MyPaintSurface2 *base_surface,
               g = pixel[GREEN];
               b = pixel[BLUE];
 
-              if (a > 0.0f)
+              if (paint < 0.0f)
                 {
-                  /* By definition the ratio between each color[] and pixel[] component in a 
non-pre-multipled blend always sums to 1.0f.
-                   * Originally this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * 
(1.0f - alpha)) / a",
-                   * instead we only calculate the cheaper term. */
-                  float src_term = (alpha * color_a) / a;
-                  float dst_term = 1.0f - src_term;
-                  r = color_r * src_term + r * dst_term;
-                  g = color_g * src_term + g * dst_term;
-                  b = color_b * src_term + b * dst_term;
+                  if (a > 0.0f)
+                    {
+                      /* By definition the ratio between each color[] and pixel[] component in a 
non-pre-multipled blend always sums to 1.0f.
+                       * Originally this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha 
* (1.0f - alpha)) / a",
+                       * instead we only calculate the cheaper term. */
+                      float src_term = (alpha * color_a) / a;
+                      float dst_term = 1.0f - src_term;
+                      r = color_r * src_term + r * dst_term;
+                      g = color_g * src_term + g * dst_term;
+                      b = color_b * src_term + b * dst_term;
+                    }
+                }
+              else
+                {
+                  if (a > 0.0f)
+                    {
+                      float spectral_a[10]      = {0};
+                      float spectral_b[10]      = {0};
+                      float spectral_result[10] = {0};
+                      float rgb[3]              = {0};
+                      float rgb_result[3]       = {0};
+                      float src_term            = alpha * MAX (normal_mode, 1.5);
+                      float dst_term            = 1.0f - src_term;
+                      float src_term2           = src_term * color_a;
+                      float out_term            = src_term2 + dst_term * pixel[ALPHA];
+                      float fac_a, fac_b;
+                      float spectral_factor, additive_factor;
+
+                      rgb_to_spectral (color_r, color_g, color_b, spectral_a);
+
+                      spectral_factor =
+                        CLAMP (spectral_blend_factor (pixel[ALPHA]), 0.0f, 1.0f);
+                      additive_factor = 1.0 - spectral_factor;
+                      if (additive_factor)
+                        {
+                          rgb[0] = src_term2 * color_r + dst_term * r;
+                          rgb[1] = src_term2 * color_g + dst_term * g;
+                          rgb[2] = src_term2 * color_b + dst_term * b;
+                        }
+
+                      if (spectral_factor && pixel[ALPHA] != 0)
+                        {
+                          /* Convert straightened tile pixel color to a spectral */
+                          rgb_to_spectral (r / pixel[ALPHA],
+                                           g / pixel[ALPHA],
+                                           b / pixel[ALPHA],
+                                           spectral_b);
+
+                          fac_a = src_term / (src_term + dst_term * pixel[ALPHA]);
+                          fac_a *= color_a;
+                          fac_b = 1.0 - fac_a;
+
+                          /* Mix input and tile pixel colors using WGM */
+                          for (int i = 0; i < 10; i++) {
+                            spectral_result[i] =
+                              fastpow (spectral_a[i], fac_a) * fastpow (spectral_b[i], fac_b);
+                          }
+
+                          /* Convert back to RGB */
+                          spectral_to_rgb (spectral_result, rgb_result);
+
+                          for (int i = 0; i < 3; i++)
+                            rgb[i] = (additive_factor * rgb[i]) +
+                              (spectral_factor * rgb_result[i] * out_term);
+                        }
+
+                      pixel[ALPHA] = out_term;
+                      r = rgb[0];
+                      g = rgb[1];
+                      b = rgb[2];
+                    }
                 }
 
               if (colorize > 0.0f && base_alpha > 0.0f)
@@ -873,6 +956,19 @@ gimp_mypaint_surface_draw_dab_2 (MyPaintSurface2 *base_surface,
                     }
                 }
 
+              if (posterize > 0.0f)
+                {
+                  float post_r = ROUND (r * posterize_num) / posterize_num;
+                  float post_g = ROUND (g * posterize_num) / posterize_num;
+                  float post_b = ROUND (b * posterize_num) / posterize_num;
+                  float src_term = opaque * posterize;
+                  float dst_term = 1 - src_term;
+
+                  r = src_term * post_r + dst_term * r;
+                  g = src_term * post_g + dst_term * g;
+                  b = src_term * post_b + dst_term * b;
+                }
+
               if (surface->options->no_erasing)
                 a = MAX (a, pixel[ALPHA]);
 
@@ -988,12 +1084,16 @@ gimp_mypaint_surface_get_color_2 (MyPaintSurface2 *base_surface,
         float *pixel = (float *)iter->items[0].data;
         float *mask;
         int iy, ix;
+        uint16_t interval_counter = 0;
 
         if (surface->paint_mask)
           mask = iter->items[1].data;
         else
           mask = NULL;
 
+        #ifdef _OPENMP
+        #pragma omp parallel for schedule(static)
+        #endif
         for (iy = iter->items[0].roi.y; iy < iter->items[0].roi.y + iter->items[0].roi.height; iy++)
           {
             float yy = (iy + 0.5f - y);
@@ -1025,7 +1125,10 @@ gimp_mypaint_surface_get_color_2 (MyPaintSurface2 *base_surface,
                     #endif
                     get_color_pixels_accumulate (mask, pixel, &sum_weight,
                                                  &sum_r, &sum_g, &sum_b, &sum_a, paint,
-                                                 pixel_weight, sample_interval, random_sample_rate);
+                                                 pixel_weight, sample_interval,
+                                                 random_sample_rate, interval_counter);
+
+                    interval_counter = (interval_counter + 1) % sample_interval;
                   }
                 pixel += 4;
                 if (mask)
@@ -1036,22 +1139,22 @@ gimp_mypaint_surface_get_color_2 (MyPaintSurface2 *base_surface,
 
     if (sum_a > 0.0f && sum_weight > 0.0f)
       {
+        float demul;
+        sum_a /= sum_weight;
+
         if (paint < 0.0f)
           {
             sum_r /= sum_weight;
             sum_g /= sum_weight;
             sum_b /= sum_weight;
           }
-        sum_a /= sum_weight;
 
-        sum_r /= sum_a;
-        sum_g /= sum_a;
-        sum_b /= sum_a;
+        demul = paint < 0.0 ? sum_a : 1.0;
 
         /* FIXME: Clamping is wrong because GEGL allows alpha > 1, this should probably re-multipy things */
-        *color_r = CLAMP(sum_r, 0.0f, 1.0f);
-        *color_g = CLAMP(sum_g, 0.0f, 1.0f);
-        *color_b = CLAMP(sum_b, 0.0f, 1.0f);
+        *color_r = CLAMP(sum_r / demul, 0.0f, 1.0f);
+        *color_g = CLAMP(sum_g / demul, 0.0f, 1.0f);
+        *color_b = CLAMP(sum_b / demul, 0.0f, 1.0f);
         *color_a = CLAMP(sum_a, 0.0f, 1.0f);
       }
   }
@@ -1136,4 +1239,4 @@ gimp_mypaint_surface2_new (GeglBuffer         *buffer,
   surface->dirty                        = *GEGL_RECTANGLE (0, 0, 0, 0);
 
   return surface;
-}
\ No newline at end of file
+}


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