OSDN Git Service

add back previous color changer
authorMartin Renold <martinxyz@gmx.ch>
Sun, 23 Oct 2011 19:17:02 +0000 (21:17 +0200)
committerMartin Renold <martinxyz@gmx.ch>
Sun, 23 Oct 2011 19:24:29 +0000 (21:24 +0200)
Rename current color changer to "crossed bowl".
Add back previous color changer under the name "wash".
Why does everything have to have a name again?

https://gna.org/bugs/?17764

gui/colorselectionwindow.py
gui/drawwindow.py
gui/menu.xml
lib/colorchanger_crossed_bowl.hpp [moved from lib/colorchanger.hpp with 89% similarity]
lib/colorchanger_wash.hpp [new file with mode: 0644]
lib/mypaintlib.hpp
lib/mypaintlib.i

index 599a6d6..2c261d9 100644 (file)
@@ -105,8 +105,12 @@ class ColorSelectorPopup(windowing.PopupWindow):
 
 
 
-class ColorChangerPopup(ColorSelectorPopup):
-    backend_class = mypaintlib.ColorChanger
+class ColorChangerWashPopup(ColorSelectorPopup):
+    backend_class = mypaintlib.ColorChangerWash
+    outside_popup_timeout = 0.050
+
+class ColorChangerCrossedBowlPopup(ColorSelectorPopup):
+    backend_class = mypaintlib.ColorChangerCrossedBowl
     outside_popup_timeout = 0.050
 
 class ColorRingPopup(ColorSelectorPopup):
index 59602a4..0e3dfe6 100644 (file)
@@ -212,7 +212,8 @@ class Window (windowing.MainWindow, layout.MainWindow):
             ('ColorMenu',    None, _('Color')),
             ('ColorPickerPopup',    gtk.STOCK_COLOR_PICKER, _('Pick Color'), 'r', None, self.popup_cb),
             ('ColorHistoryPopup',  None, _('Color History'), 'x', None, self.popup_cb),
-            ('ColorChangerPopup', None, _('Color Changer'), 'v', None, self.popup_cb),
+            ('ColorChangerCrossedBowlPopup', None, _('Color Changer (crossed bowl)'), 'v', None, self.popup_cb),
+            ('ColorChangerWashPopup', None, _('Color Changer (washed)'), 'c', None, self.popup_cb),
             ('ColorRingPopup',  None, _('Color Ring'), None, None, self.popup_cb),
             ('ColorDetailsDialog', None, _("Color Details"), None, None, self.color_details_dialog_cb),
 
@@ -349,20 +350,27 @@ class Window (windowing.MainWindow, layout.MainWindow):
     def init_stategroups(self):
         sg = stategroup.StateGroup()
         p2s = sg.create_popup_state
-        changer = p2s(colorselectionwindow.ColorChangerPopup(self.app))
+        changer_crossed_bowl = p2s(colorselectionwindow.ColorChangerCrossedBowlPopup(self.app))
+        changer_wash = p2s(colorselectionwindow.ColorChangerWashPopup(self.app))
         ring = p2s(colorselectionwindow.ColorRingPopup(self.app))
         hist = p2s(historypopup.HistoryPopup(self.app, self.app.doc.model))
         pick = self.colorpick_state = p2s(colorpicker.ColorPicker(self.app, self.app.doc.model))
 
         self.popup_states = {
-            'ColorChangerPopup': changer,
+            'ColorChangerCrossedBowlPopup': changer_crossed_bowl,
+            'ColorChangerWashPopup': changer_wash,
             'ColorRingPopup': ring,
             'ColorHistoryPopup': hist,
             'ColorPickerPopup': pick,
             }
-        changer.next_state = ring
-        ring.next_state = changer
-        changer.autoleave_timeout = None
+
+        # not sure how useful this is; we can't cycle at the moment
+        changer_crossed_bowl.next_state = ring
+        ring.next_state = changer_wash
+        changer_wash.next_state = ring
+
+        changer_wash.autoleave_timeout = None
+        changer_crossed_bowl.autoleave_timeout = None
         ring.autoleave_timeout = None
 
         pick.max_key_hit_duration = 0.0
index 0320db6..4fcc0cd 100644 (file)
     </menu>
     <menu action='ColorMenu'>
       <menuitem action='ColorSelectionWindow'/>
+      <menuitem action='ColorSamplerWindow'/>
+      <separator/>
+      <menuitem action='ColorChangerCrossedBowlPopup'/>
+      <menuitem action='ColorChangerWashPopup'/>
       <menuitem action='ColorRingPopup'/>
-      <menuitem action='ColorChangerPopup'/>
       <menuitem action='ColorPickerPopup'/>
       <menuitem action='ColorHistoryPopup'/>
-      <menuitem action='ColorSamplerWindow'/>
       <separator/>
       <menuitem action='Brighter'/>
       <menuitem action='Darker'/>
similarity index 89%
rename from lib/colorchanger.hpp
rename to lib/colorchanger_crossed_bowl.hpp
index a415727..e3f6edf 100644 (file)
@@ -7,9 +7,9 @@
  * (at your option) any later version.
  */
 
-const int size = 256;
+const int ccdb_size = 256;
 
-class ColorChanger {
+class ColorChangerCrossedBowl {
 public:
   float brush_h, brush_s, brush_v;
   void set_brush_color(float h, float s, float v)
@@ -21,7 +21,7 @@ public:
 
   int get_size() 
   {
-    return size;
+    return ccdb_size;
   }
 
 #ifndef SWIG
@@ -37,7 +37,7 @@ public:
   PrecalcData * precalcData[4];
   int precalcDataIndex;
 
-  ColorChanger()
+  ColorChangerCrossedBowl()
   {
     precalcDataIndex = -1;
     for (int i=0; i<4; i++) {
@@ -53,11 +53,11 @@ public:
 
     int width, height;
     int x, y, i;
-    int s_radius = size/2.6;
+    int s_radius = ccdb_size/2.6;
     PrecalcData * result;
 
-    width = size;
-    height = size;
+    width = ccdb_size;
+    height = ccdb_size;
     result = (PrecalcData*)malloc(sizeof(PrecalcData)*width*height);
 
     i = 0;
@@ -79,7 +79,7 @@ public:
 
         int dx = x-width/2;
         int dy = y-height/2;
-        int diag = sqrt(2)*size/2;
+        int diag = sqrt(2)*ccdb_size/2;
 
         int dxs, dys;
         if (dx > 0) 
@@ -165,8 +165,8 @@ public:
 
     assert(PyArray_ISCARRAY(arr));
     assert(PyArray_NDIM(arr) == 3);
-    assert(PyArray_DIM(arr, 0) == size);
-    assert(PyArray_DIM(arr, 1) == size);
+    assert(PyArray_DIM(arr, 0) == ccdb_size);
+    assert(PyArray_DIM(arr, 1) == ccdb_size);
     assert(PyArray_DIM(arr, 2) == 4);
     pixels = (uint8_t*)((PyArrayObject*)arr)->data;
     
@@ -178,14 +178,14 @@ public:
       pre = precalcData[precalcDataIndex] = precalc_data(2*M_PI*(precalcDataIndex/4.0));
     }
 
-    for (y=0; y<size; y++) {
-      for (x=0; x<size; x++) {
+    for (y=0; y<ccdb_size; y++) {
+      for (x=0; x<ccdb_size; x++) {
 
         get_hsv(h, s, v, pre);
         pre++;
 
         hsv_to_rgb_range_one (&h, &s, &v);
-        uint8_t * p = pixels + 4*(y*size + x);
+        uint8_t * p = pixels + 4*(y*ccdb_size + x);
         p[0] = h; p[1] = s; p[2] = v; p[3] = 255;
       }
     }
@@ -197,9 +197,9 @@ public:
     PrecalcData * pre = precalcData[precalcDataIndex];
     assert(precalcDataIndex >= 0);
     assert(pre != NULL);
-    int x = CLAMP(x_, 0, size);
-    int y = CLAMP(y_, 0, size);
-    pre += y*size + x;
+    int x = CLAMP(x_, 0, ccdb_size);
+    int y = CLAMP(y_, 0, ccdb_size);
+    pre += y*ccdb_size + x;
     get_hsv(h, s, v, pre);
     return Py_BuildValue("fff",h,s,v);
   }
diff --git a/lib/colorchanger_wash.hpp b/lib/colorchanger_wash.hpp
new file mode 100644 (file)
index 0000000..32565e0
--- /dev/null
@@ -0,0 +1,242 @@
+/* This file is part of MyPaint.
+ * Copyright (C) 2008 by Martin Renold <martinxyz@gmx.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+const int ccw_size = 256;
+
+class ColorChangerWash {
+public:
+
+  float brush_h, brush_s, brush_v;
+  void set_brush_color(float h, float s, float v)
+  {
+    brush_h = h;
+    brush_s = s;
+    brush_v = v;
+  }
+
+  int get_size() 
+  {
+    return ccw_size;
+  }
+  
+#ifndef SWIG
+
+  struct PrecalcData {
+    int h;
+    int s;
+    int v;
+    //signed char s;
+    //signed char v;
+  };
+
+  PrecalcData * precalcData[4];
+  int precalcDataIndex;
+
+  ColorChangerWash()
+  {
+    precalcDataIndex = -1;
+    for (int i=0; i<4; i++) {
+      precalcData[i] = NULL;
+    }
+  }
+
+  PrecalcData * precalc_data(float phase0)
+  {
+    // Hint to the casual reader: some of the calculation here do not
+    // what I originally intended. Not everything here will make sense.
+    // It does not matter in the end, as long as the result looks good.
+
+    int width, height;
+    float width_inv, height_inv;
+    int x, y, i;
+    PrecalcData * result;
+
+    width = ccw_size;
+    height = ccw_size;
+    result = (PrecalcData*)malloc(sizeof(PrecalcData)*width*height);
+
+    //phase0 = rand_double (rng) * 2*M_PI;
+
+    width_inv = 1.0/width;
+    height_inv = 1.0/height;
+
+    i = 0;
+    for (y=0; y<height; y++) {
+      for (x=0; x<width; x++) {
+        float h, s, v, s_original, v_original;
+        int dx, dy;
+        float v_factor = 0.8;
+        float s_factor = 0.8;
+        float h_factor = 0.05;
+
+#define factor2_func(x) ((x)*(x)*SIGN(x))
+        float v_factor2 = 0.01;
+        float s_factor2 = 0.01;
+
+
+        h = 0;
+        s = 0;
+        v = 0;
+
+        dx = x-width/2;
+        dy = y-height/2;
+
+        // basically, its x-axis = value, y-axis = saturation
+        v = dx*v_factor + factor2_func(dx)*v_factor2;
+        s = dy*s_factor + factor2_func(dy)*s_factor2;
+
+        v_original = v; s_original = s;
+
+        s=v=0;
+
+        const int stripe_width = 20;
+        float stripe_dist = 0.0;
+        {
+          int min = ABS(dx);
+          if (ABS(dy) < min) min = ABS(dy);
+          if (min > stripe_width) {
+            stripe_dist = float(min - stripe_width) / (ccw_size - stripe_width);
+          }
+        }
+
+        // overlay sine waves to color hue, not visible at center, ampilfying near the border
+        if (1) {
+          float amplitude, phase;
+          float dist, dist2, borderdist;
+          float dx_norm, dy_norm;
+          float angle;
+          dx_norm = dx*width_inv;
+          dy_norm = dy*height_inv;
+
+          dist2 = dx_norm*dx_norm + dy_norm*dy_norm;
+          dist = sqrtf(dist2);
+          borderdist = 0.5 - MAX(ABS(dx_norm), ABS(dy_norm));
+          angle = atan2f(dy_norm, dx_norm);
+          amplitude = 50 + dist2*dist2*dist2*100;
+          phase = phase0 + 2*M_PI* (dist*0 + dx_norm*dx_norm*dy_norm*dy_norm*50) + angle*7;
+          //h = sinf(phase) * amplitude;
+          h = sinf(phase);
+          h = (h>0)?h*h:-h*h;
+          h *= amplitude;
+
+          // calcualte angle to next 45-degree-line
+          angle = ABS(angle)/M_PI;
+          if (angle > 0.5) angle -= 0.5;
+          angle -= 0.25;
+          angle = ABS(angle) * 4;
+          // angle is now in range 0..1
+          // 0 = on a 45 degree line, 1 = on a horizontal or vertical line
+
+          h = h * angle * 1.5;
+
+          // this part is for strong color variations at the borders
+          if (borderdist < 0.3) {
+            float fac;
+            float h_new;
+            fac = (1 - borderdist/0.3);
+            // fac is 1 at the outermost pixels
+            fac = fac*fac*0.6;
+            h_new = (angle+phase0+M_PI/4)*360/(2*M_PI) * 8;
+            while (h_new > h + 360/2) h_new -= 360;
+            while (h_new < h - 360/2) h_new += 360;
+            h = (1-fac)*h + fac*h_new;
+            //h = (angle+M_PI/4)*360/(2*M_PI) * 4;
+          }
+
+          s += 300 * dist * dist * stripe_dist;
+          v += 500 * dist * dist * stripe_dist;
+        }
+
+        {
+          // undo that funky stuff on horizontal and vertical lines
+          if (stripe_dist == 0.0) {
+            h = 0;
+            s = s_original;
+            v = v_original;
+            if (ABS(dx) > ABS(dy)) {
+              // horizontal stripe
+              s = 0.0;
+            } else {
+              // vertical stripe
+              v = 0.0;
+            }
+          }
+        }
+
+        h -= h*h_factor;
+
+        result[i].h = (int)h;
+        result[i].v = (int)v;
+        result[i].s = (int)s;
+        i++;
+      }
+    }
+    return result;
+  }
+
+  void get_hsv(float &h, float &s, float &v, PrecalcData * pre)
+  {
+    h = brush_h + pre->h/360.0;
+    s = brush_s + pre->s/255.0;
+    v = brush_v + pre->v/255.0;
+
+    s = CLAMP(s, 0.0, 1.0);
+    v = CLAMP(v, 0.0, 1.0);
+
+  }
+
+#endif /* #ifndef SWIG */
+
+  void render(PyObject * arr)
+  {
+    uint8_t * pixels;
+    int x, y;
+    float h, s, v;
+
+    assert(PyArray_ISCARRAY(arr));
+    assert(PyArray_NDIM(arr) == 3);
+    assert(PyArray_DIM(arr, 0) == ccw_size);
+    assert(PyArray_DIM(arr, 1) == ccw_size);
+    assert(PyArray_DIM(arr, 2) == 4);
+    pixels = (uint8_t*)((PyArrayObject*)arr)->data;
+    
+    precalcDataIndex++;
+    precalcDataIndex %= 4;
+
+    PrecalcData * pre = precalcData[precalcDataIndex];
+    if (!pre) {
+      pre = precalcData[precalcDataIndex] = precalc_data(2*M_PI*(precalcDataIndex/4.0));
+    }
+
+    for (y=0; y<ccw_size; y++) {
+      for (x=0; x<ccw_size; x++) {
+
+        get_hsv(h, s, v, pre);
+        pre++;
+
+        hsv_to_rgb_range_one (&h, &s, &v);
+        uint8_t * p = pixels + 4*(y*ccw_size + x);
+        p[0] = h; p[1] = s; p[2] = v; p[3] = 255;
+      }
+    }
+  }
+
+  PyObject* pick_color_at(float x_, float y_)
+  {
+    float h,s,v;
+    PrecalcData * pre = precalcData[precalcDataIndex];
+    assert(precalcDataIndex >= 0);
+    assert(pre != NULL);
+    int x = CLAMP(x_, 0, ccw_size);
+    int y = CLAMP(y_, 0, ccw_size);
+    pre += y*ccw_size + x;
+    get_hsv(h, s, v, pre);
+    return Py_BuildValue("fff",h,s,v);
+  }
+};
index 68f88c5..6d439c3 100644 (file)
@@ -6,6 +6,7 @@
 #include "tiledsurface.hpp"
 #include "pixops.hpp"
 #include "colorring.hpp"
-#include "colorchanger.hpp"
+#include "colorchanger_wash.hpp"
+#include "colorchanger_crossed_bowl.hpp"
 #include "gdkpixbuf2numpy.hpp"
 #include "fastpng.hpp"
index 3aa2b4b..7867edd 100644 (file)
@@ -13,7 +13,8 @@ typedef struct { int x, y, w, h; } Rect;
 %include "tiledsurface.hpp"
 %include "pixops.hpp"
 %include "colorring.hpp"
-%include "colorchanger.hpp"
+%include "colorchanger_wash.hpp"
+%include "colorchanger_crossed_bowl.hpp"
 %include "fastpng.hpp"
 
 //from "gdkpixbuf2numpy.hpp"