/* brushlib - The MyPaint Brush Library * Copyright (C) 2007-2008 Martin Renold * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. See the COPYING file for more details. */ #ifndef __helpers_h__ #define __helpers_h__ #include #include // MAX, MIN, ABS, CLAMP are already available from gmacros.h #define ROUND(x) ((int) ((x) + 0.5)) #define SIGN(x) ((x)>0?1:(-1)) #define SQR(x) ((x)*(x)) #define MAX3(a, b, c) ((a)>(b)?MAX((a),(c)):MAX((b),(c))) #define MIN3(a, b, c) ((a)<(b)?MIN((a),(c)):MIN((b),(c))) typedef struct { int x, y, w, h; } Rect; // originally from my mass project (mass.sourceforge.net) void ExpandRectToIncludePoint(Rect * r, int x, int y) { if (r->w == 0) { r->w = 1; r->h = 1; r->x = x; r->y = y; } else { if (x < r->x) { r->w += r->x-x; r->x = x; } else if (x >= r->x+r->w) { r->w = x - r->x + 1; } if (y < r->y) { r->h += r->y-y; r->y = y; } else if (y >= r->y+r->h) { r->h = y - r->y + 1; } } } // Optimized version from one in GIMP (noisify.c), where it was // adapted from ppmforge.c, which is part of PBMPLUS. The algorithm // comes from: 'The Science Of Fractal Images'. Peitgen, H.-O., and // Saupe, D. eds. Springer Verlag, New York, 1988. float rand_gauss (GRand * rng) { float sum = 0.0; uint32_t rand1 = g_rand_int(rng); uint32_t rand2 = g_rand_int(rng); sum += rand1 & 0x7FFF; sum += (rand1 >> 16) & 0x7FFF; sum += rand2 & 0x7FFF; sum += (rand2 >> 16) & 0x7FFF; return sum * 5.28596089837e-5 - 3.46410161514; } // stolen from GIMP (gimpcolorspace.c) // (from gimp_rgb_to_hsv) void rgb_to_hsv_float (float *r_ /*h*/, float *g_ /*s*/, float *b_ /*v*/) { float max, min, delta; float h, s, v; float r, g, b; h = 0.0; // silence gcc warning r = *r_; g = *g_; b = *b_; r = CLAMP(r, 0.0, 1.0); g = CLAMP(g, 0.0, 1.0); b = CLAMP(b, 0.0, 1.0); max = MAX3(r, g, b); min = MIN3(r, g, b); v = max; delta = max - min; if (delta > 0.0001) { s = delta / max; if (r == max) { h = (g - b) / delta; if (h < 0.0) h += 6.0; } else if (g == max) { h = 2.0 + (b - r) / delta; } else if (b == max) { h = 4.0 + (r - g) / delta; } h /= 6.0; } else { s = 0.0; h = 0.0; } *r_ = h; *g_ = s; *b_ = v; } // (from gimp_hsv_to_rgb) void hsv_to_rgb_float (float *h_, float *s_, float *v_) { gint i; gdouble f, w, q, t; float h, s, v; float r, g, b; r = g = b = 0.0; // silence gcc warning h = *h_; s = *s_; v = *v_; h = h - floor(h); s = CLAMP(s, 0.0, 1.0); v = CLAMP(v, 0.0, 1.0); gdouble hue; if (s == 0.0) { r = v; g = v; b = v; } else { hue = h; if (hue == 1.0) hue = 0.0; hue *= 6.0; i = (gint) hue; f = hue - i; w = v * (1.0 - s); q = v * (1.0 - (s * f)); t = v * (1.0 - (s * (1.0 - f))); switch (i) { case 0: r = v; g = t; b = w; break; case 1: r = q; g = v; b = w; break; case 2: r = w; g = v; b = t; break; case 3: r = w; g = q; b = v; break; case 4: r = t; g = w; b = v; break; case 5: r = v; g = w; b = q; break; } } *h_ = r; *s_ = g; *v_ = b; } // (from gimp_rgb_to_hsl) void rgb_to_hsl_float (float *r_, float *g_, float *b_) { gdouble max, min, delta; float h, s, l; float r, g, b; // silence gcc warnings h=0; r = *r_; g = *g_; b = *b_; r = CLAMP(r, 0.0, 1.0); g = CLAMP(g, 0.0, 1.0); b = CLAMP(b, 0.0, 1.0); max = MAX3(r, g, b); min = MIN3(r, g, b); l = (max + min) / 2.0; if (max == min) { s = 0.0; h = 0.0; //GIMP_HSL_UNDEFINED; } else { if (l <= 0.5) s = (max - min) / (max + min); else s = (max - min) / (2.0 - max - min); delta = max - min; if (delta == 0.0) delta = 1.0; if (r == max) { h = (g - b) / delta; } else if (g == max) { h = 2.0 + (b - r) / delta; } else if (b == max) { h = 4.0 + (r - g) / delta; } h /= 6.0; if (h < 0.0) h += 1.0; } *r_ = h; *g_ = s; *b_ = l; } static double hsl_value (gdouble n1, gdouble n2, gdouble hue) { gdouble val; if (hue > 6.0) hue -= 6.0; else if (hue < 0.0) hue += 6.0; if (hue < 1.0) val = n1 + (n2 - n1) * hue; else if (hue < 3.0) val = n2; else if (hue < 4.0) val = n1 + (n2 - n1) * (4.0 - hue); else val = n1; return val; } /** * gimp_hsl_to_rgb: * @hsl: A color value in the HSL colorspace * @rgb: The value converted to a value in the RGB colorspace * * Convert a HSL color value to an RGB color value. **/ void hsl_to_rgb_float (float *h_, float *s_, float *l_) { float h, s, l; float r, g, b; h = *h_; s = *s_; l = *l_; h = h - floor(h); s = CLAMP(s, 0.0, 1.0); l = CLAMP(l, 0.0, 1.0); if (s == 0) { /* achromatic case */ r = l; g = l; b = l; } else { gdouble m1, m2; if (l <= 0.5) m2 = l * (1.0 + s); else m2 = l + s - l * s; m1 = 2.0 * l - m2; r = hsl_value (m1, m2, h * 6.0 + 2.0); g = hsl_value (m1, m2, h * 6.0); b = hsl_value (m1, m2, h * 6.0 - 2.0); } *h_ = r; *s_ = g; *l_ = b; } #endif