| 2883 | static double value(double n1, double n2, double hue) |
| 2884 | { |
| 2885 | if (hue > 360.0) |
| 2886 | hue = hue - 360.0; |
| 2887 | else if (hue < 0.0) |
| 2888 | hue = hue + 360.0; |
| 2889 | |
| 2890 | if (hue < 60.0) |
| 2891 | return n1 + (n2 - n1) * hue / 60.0; |
| 2892 | if (hue < 180.0) |
| 2893 | return n2; |
| 2894 | if (hue < 240.0) |
| 2895 | return n1 + (n2 - n1) * (240.0 - hue) / 60.0; |
| 2896 | return n1; |
| 2897 | } |
| 2898 | |
| 2899 | void Scumm::desaturatePalette(int hueScale, int satScale, int lightScale, int startColor, int endColor) |
| 2900 | { |
| 2901 | // This function scales the HSL (Hue, Saturation and Lightness) |
| 2902 | // components of the palette colours. It's used in CMI when Guybrush |
| 2903 | // walks from the beach towards the swamp. |
| 2904 | // |
| 2905 | // I don't know if this function is correct, but the output seems to |
| 2906 | // match the original fairly closely. |
| 2907 | // |
| 2908 | // FIXME: Rewrite using integer arithmetics only? |
| 2909 | |
| 2910 | if (startColor <= endColor) { |
| 2911 | byte *cptr, *cur; |
| 2912 | int j; |
| 2913 | |
| 2914 | cptr = getPalettePtr() + startColor * 3; |
| 2915 | cur = _currentPalette + startColor * 3; |
| 2916 | |
| 2917 | for (j = startColor; j <= endColor; j++) { |
| 2918 | double R, G, B; |
| 2919 | double H, S, L; |
| 2920 | double min, max; |
| 2921 | int red, green, blue; |
| 2922 | |
| 2923 | R = ((double) *cptr++) / 255.0; |
| 2924 | G = ((double) *cptr++) / 255.0; |
| 2925 | B = ((double) *cptr++) / 255.0; |
| 2926 | |
| 2927 | // RGB to HLS (Foley and VanDam) |
| 2928 | |
| 2929 | min = MIN(R, MIN(G, B)); |
| 2930 | max = MAX(R, MAX(G, B)); |
| 2931 | |
| 2932 | L = (max + min) / 2.0; |
| 2933 | |
| 2934 | if (max != min) { |
| 2935 | if (L <= 0.5) |
| 2936 | S = (max - min) / (max + min); |
| 2937 | else |
| 2938 | S = (max - min) / (2.0 - max - min); |
| 2939 | |
| 2940 | if (R == max) |
| 2941 | H = (G - B) / (max - min); |
| 2942 | else if (G == max) |
| 2943 | H = 2.0 + (B - R) / (max - min); |
| 2944 | else |
| 2945 | H = 4.0 + (R - G) / (max - min); |
| 2946 | |
| 2947 | H = H * 60.0; |
| 2948 | if (H < 0.0) |
| 2949 | H = H + 360.0; |
| 2950 | } else { |
| 2951 | S = 0.0; |
| 2952 | H = 0.0; // undefined |
| 2953 | } |
| 2954 | |
| 2955 | // Scale the result |
| 2956 | |
| 2957 | H = (H * hueScale) / 255.0; |
| 2958 | S = (S * satScale) / 255.0; |
| 2959 | L = (L * lightScale) / 255.0; |
| 2960 | |
| 2961 | // HLS to RGB (Foley and VanDam) |
| 2962 | |
| 2963 | double m1, m2; |
| 2964 | |
| 2965 | if (min != max) { |
| 2966 | if (L <= 0.5) |
| 2967 | m2 = L * (1 + S); |
| 2968 | else |
| 2969 | m2 = L + S - L * S; |
| 2970 | |
| 2971 | m1 = 2.0 * L - m2; |
| 2972 | |
| 2973 | R = value(m1, m2, H + 120); |
| 2974 | G = value(m1, m2, H); |
| 2975 | B = value(m1, m2, H - 120); |
| 2976 | } else { |
| 2977 | R = L; |
| 2978 | G = L; |
| 2979 | B = L; |
| 2980 | } |
| 2981 | |
| 2982 | red = (int) (255.0 * R + 0.5); |
| 2983 | green = (int) (255.0 * G + 0.5); |
| 2984 | blue = (int) (255.0 * B + 0.5); |
| 2985 | |
| 2986 | *cur++ = red; |
| 2987 | *cur++ = green; |
| 2988 | *cur++ = blue; |
| 2989 | } |
| 2990 | |
| 2991 | setDirtyColors(startColor, endColor); |
| 2992 | } |
| 2993 | } |
| 2994 | |