/* This file is part of MyPaint. * Copyright (C) 2008 by Martin Renold * * 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 size = 256; class ColorChanger { 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 size; } #ifndef SWIG struct PrecalcData { int h; int s; int v; //signed char s; //signed char v; }; PrecalcData * precalcData[4]; int precalcDataIndex; ColorChanger() { 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; int s_radius = size/2.6; PrecalcData * result; width = size; height = size; result = (PrecalcData*)malloc(sizeof(PrecalcData)*width*height); width_inv = 1.0/width; height_inv = 1.0/height; i = 0; for (y=0; y 0) dxs = dx - stripe_width; else dxs = dx + stripe_width; if (dy > 0) dys = dy - stripe_width; else dys = dy + stripe_width; float r = sqrt(SQR(dxs)+SQR(dys)); // hue if (r < s_radius) { if (dx > 0) h = 90*SQR2(r/s_radius); else h = 360 - 90*SQR2(r/s_radius); s = 256*(atan2f(abs(dxs),dys)/M_PI) - 128; } else { h = 180 + 180*atan2f(dys,-dxs)/M_PI; v = 255*(r-s_radius)/(diag-s_radius) - 128; } // horizontal and vertical lines int min = ABS(dx); if (ABS(dy) < min) min = ABS(dy); if (min < stripe_width) { h = 0; // x-axis = value, y-axis = saturation v = dx*v_factor + factor2_func(dx)*v_factor2; s = - (dy*s_factor + factor2_func(dy)*s_factor2); // but not both at once if (ABS(dx) > ABS(dy)) { // horizontal stripe s = 0.0; } else { // vertical stripe v = 0.0; } } else { // diagonal lines min = ABS(dx+dy); if (ABS(dx-dy) < min) min = ABS(dx-dy); if (min < stripe_width) { h = 0; // x-axis = value, y-axis = saturation v = dx*v_factor + factor2_func(dx)*v_factor2; s = - (dy*s_factor + factor2_func(dy)*s_factor2); // both at once } } 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; h -= floor(h); 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) == size); assert(PyArray_DIM(arr, 1) == 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= 0); assert(pre != NULL); int x = CLAMP(x_, 0, size); int y = CLAMP(y_, 0, size); pre += y*size + x; get_hsv(h, s, v, pre); return Py_BuildValue("fff",h,s,v); } };