/* Copyright 1994, 1995 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_qCConv[] = "$Id: qCConv.c 63 2004-12-24 18:19:43Z ctm $"; #endif #include "rsys/common.h" #include "QuickDraw.h" /* cmy and rgb color spaces are simply complements */ P2 (PUBLIC pascal trap, void, CMY2RGB, CMYColor *, cmy_color, RGBColor *, rgb_color) { rgb_color->red = ~cmy_color->cyan; rgb_color->green = ~cmy_color->magenta; rgb_color->blue = ~cmy_color->yellow; } P2 (PUBLIC pascal trap, void, RGB2CMY, RGBColor *, rgb_color, CMYColor *, cmy_color) { /* use `bar = ~foo' instead of `bar = CW (MaxSmallFract - CW (foo))' to compute the complement value */ cmy_color->cyan = ~rgb_color->red; cmy_color->magenta = ~rgb_color->green; cmy_color->yellow = ~rgb_color->blue; } #define SF_MULT(x,y) (((x) * (y)) / 65535) #define SF_DIV(x,y) (((x) * 65535) / (y)) #define C_TO_SF(c) ((c) * 65535) #define SF_TO_C(sf) ((sf) / 65535) #define ANGLE_TO_SF(angle) (C_TO_SF (angle) / 360) static inline unsigned short value (unsigned long n1, unsigned long n2, unsigned long hue) { if (hue < ANGLE_TO_SF (60)) return CW (n1 + SF_MULT (n2 - n1, SF_MULT (hue, C_TO_SF (6)))); else if (hue < ANGLE_TO_SF (180)) return CW (n2); else if (hue < ANGLE_TO_SF (240)) return CW (n1 + SF_MULT (n2 - n1, SF_MULT (ANGLE_TO_SF (240) - hue, C_TO_SF (6)))); else return CW (n1); } P2 (PUBLIC pascal trap, void, HSL2RGB, HSLColor *, hsl_color, RGBColor *, rgb_color) { if (hsl_color->saturation == CWC (0)) { rgb_color->red = hsl_color->lightness; rgb_color->green = hsl_color->lightness; rgb_color->blue = hsl_color->lightness; } else { unsigned long m1, m2; /* the hue represents a angle in the range [0, 360) */ unsigned long h = CW (hsl_color->hue); unsigned long s = CW (hsl_color->saturation); unsigned long l = CW (hsl_color->lightness); if (l <= (MaxSmallFract / 2)) m2 = SF_MULT (l, (C_TO_SF (1) + s)); else m2 = l + s - SF_MULT (l, s); m1 = SF_MULT (l, C_TO_SF (2)) - m2; rgb_color->red = value (m1, m2, (h >= ANGLE_TO_SF (240)) ? (h - ANGLE_TO_SF (240)) : (h + ANGLE_TO_SF (120))); rgb_color->green = value (m1, m2, h); rgb_color->blue = value (m1, m2, (h < ANGLE_TO_SF (120)) ? (h + ANGLE_TO_SF (240)) : (h - ANGLE_TO_SF (120))); } } P2 (PUBLIC pascal trap, void, RGB2HSL, RGBColor *, rgb_color, HSLColor *, hsl_color) { unsigned long r = CW (rgb_color->red); unsigned long g = CW (rgb_color->green); unsigned long b = CW (rgb_color->blue); unsigned long max = MAX (r, MAX (g, b)); unsigned long min = MIN (r, MIN (g, b)); unsigned long h; unsigned long s; unsigned long l = (min + max) / 2; if (min == max) { /* achromatic case, because all rgb color components are equal */ s = 0; /* the value of h in this case is meaningless, should investigate what the Mac color conversion routines do */ h = 0; } else { unsigned long delta = max - min; if (l <= (MaxSmallFract / 2)) { s = SF_DIV (delta, max + min); gui_assert (s <= MaxSmallFract); } else { s = SF_DIV (delta, C_TO_SF (2) - max - min); gui_assert (s <= MaxSmallFract); } if (r == max) { if (g >= b) h = SF_MULT (SF_DIV (g - b, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (360) - SF_MULT (SF_DIV (b - g, delta), ANGLE_TO_SF (60)); } else if (g == max) { if (b >= r) h = ANGLE_TO_SF (120) + SF_MULT (SF_DIV (b - r, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (120) - SF_MULT (SF_DIV (r - b, delta), ANGLE_TO_SF (60)); } else if (b == max) { if (r >= g) h = ANGLE_TO_SF (240) + SF_MULT (SF_DIV (r - g, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (240) - SF_MULT (SF_DIV (g - r, delta), ANGLE_TO_SF (60)); } else gui_fatal("r = 0x%lx, g = 0x%lx, b = 0x%lx", r, g, b); } hsl_color->hue = CW (h); hsl_color->saturation = CW (s); hsl_color->lightness = CW (l); } P2 (PUBLIC pascal trap, void, HSV2RGB, HSVColor *, hsv_color, RGBColor *, rgb_color) { if (hsv_color->saturation == CWC (0)) { rgb_color->red = hsv_color->value; rgb_color->green = hsv_color->value; rgb_color->blue = hsv_color->value; } else { /* the hue represents a angle in the range [0, 360) */ unsigned long h = CW (hsv_color->hue); unsigned long s = CW (hsv_color->saturation); unsigned long v = CW (hsv_color->value); /* one of the six color verticies of the hex cone, [0, 6) */ unsigned sextant = SF_TO_C (h * 6); /* `fractional' portion of h, in the range [0,1] */ /* unsigned long f = 6 * (h % ANGLE_TO_SF (60)); */ unsigned long f = 6 * (h - ANGLE_TO_SF (sextant * 60)); unsigned long p = SF_MULT (v, C_TO_SF (1) - s); unsigned long q = SF_MULT (v, C_TO_SF (1) - SF_MULT (s, f)); unsigned long t = SF_MULT (v, (C_TO_SF (1) - SF_MULT (s, C_TO_SF (1) - f))); switch (sextant) { case 0: rgb_color->red = CW (v); rgb_color->green = CW (t); rgb_color->blue = CW (p); break; case 1: rgb_color->red = CW (q); rgb_color->green = CW (v); rgb_color->blue = CW (p); break; case 2: rgb_color->red = CW (p); rgb_color->green = CW (v); rgb_color->blue = CW (t); break; case 3: rgb_color->red = CW (p); rgb_color->green = CW (q); rgb_color->blue = CW (v); break; case 4: rgb_color->red = CW (t); rgb_color->green = CW (p); rgb_color->blue = CW (v); break; case 5: case 6: rgb_color->red = CW (v); rgb_color->green = CW (p); rgb_color->blue = CW (q); break; default: gui_fatal ("sextant = %d", sextant); } } } P2 (PUBLIC pascal trap, void, RGB2HSV, RGBColor *, rgb_color, HSVColor *, hsv_color) { unsigned long r = CW (rgb_color->red); unsigned long g = CW (rgb_color->green); unsigned long b = CW (rgb_color->blue); unsigned long max = MAX (r, MAX (g, b)); unsigned long min = MIN (r, MIN (g, b)); unsigned long h; unsigned long s; unsigned long v = max; if (max != 0) { s = SF_DIV (max - min, max); gui_assert (s <= MaxSmallFract); } else s = 0; if (s == 0) { /* the value of h in this case is meaningless, should investigate what the Mac color conversion routines do */ h = 0; } else { unsigned long delta = max - min; if (r == max) { if (g >= b) h = SF_MULT (SF_DIV (g - b, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (360) - SF_MULT (SF_DIV (b - g, delta), ANGLE_TO_SF (60)); } else if (g == max) { if (b >= r) h = ANGLE_TO_SF (120) + SF_MULT (SF_DIV (b - r, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (120) - SF_MULT (SF_DIV (r - b, delta), ANGLE_TO_SF (60)); } else if (b == max) { if (r >= g) h = ANGLE_TO_SF (240) + SF_MULT (SF_DIV (r - g, delta), ANGLE_TO_SF (60)); else h = ANGLE_TO_SF (240) - SF_MULT (SF_DIV (g - r, delta), ANGLE_TO_SF (60)); } else gui_fatal ("r = 0x%lx, g = 0x%lx, b = 0x%lx", r, g, b); } hsv_color->hue = CW (h); hsv_color->saturation = CW (s); hsv_color->value = CW (v); } P1 (PUBLIC pascal trap, SmallFract, Fix2SmallFract, Fixed, f) { return f & 0xFFFF; } P1 (PUBLIC pascal trap, Fixed, SmallFract2Fix, SmallFract, sf) { return sf; }