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
-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):
('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),
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
</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'/>
* (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)
int get_size()
{
- return size;
+ return ccdb_size;
}
#ifndef SWIG
PrecalcData * precalcData[4];
int precalcDataIndex;
- ColorChanger()
+ ColorChangerCrossedBowl()
{
precalcDataIndex = -1;
for (int i=0; i<4; i++) {
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;
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)
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;
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;
}
}
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);
}
--- /dev/null
+/* 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);
+ }
+};
#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"
%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"