| 2885 | void Scumm::desaturatePalette(int hueScale, int satScale, int valScale, int startColor, int endColor) |
| 2886 | { |
| 2887 | // This is used by CMI when Guybrush walks from the fort towards the |
| 2888 | // swamp. He should gradually fade to gray as he walks into the mist. |
| 2889 | |
| 2890 | // FIXME: The result doesn't look quite like the original. There are |
| 2891 | // several possible explanations for this. Maybe CMI isn't scaling |
| 2892 | // the HSV components of the colour after all, or maybe it uses a |
| 2893 | // simplified version of the algorithm. |
| 2894 | |
| 2895 | // FIXME: Simplify, and eliminate the floating-point arithmetics? |
| 2896 | |
| 2897 | if (startColor <= endColor) { |
| 2898 | byte *cptr, *cur; |
| 2899 | double R, G, B; |
| 2900 | double H, S, V; |
| 2901 | double Rp, Gp, Bp; |
| 2902 | double min, max; |
| 2903 | int j; |
| 2904 | |
| 2905 | cptr = getPalettePtr() + startColor * 3; |
| 2906 | cur = _currentPalette + startColor * 3; |
| 2907 | |
| 2908 | for (j = startColor; j <= endColor; j++) { |
| 2909 | R = ((double) *cptr++) / 255.0; |
| 2910 | G = ((double) *cptr++) / 255.0; |
| 2911 | B = ((double) *cptr++) / 255.0; |
| 2912 | |
| 2913 | // Convert RGB to HSV |
| 2914 | |
| 2915 | min = MIN(R, MIN(G, B)); |
| 2916 | max = MAX(R, MAX(G, B)); |
| 2917 | |
| 2918 | S = (max - min) / max; |
| 2919 | V = max; |
| 2920 | |
| 2921 | Rp = (max - R) / (max - min); |
| 2922 | Gp = (max - G) / (max - min); |
| 2923 | Bp = (max - B) / (max - min); |
| 2924 | |
| 2925 | // The original algorithm says I should test if S is |
| 2926 | // non-zero, but I don't dare to test for that kind of |
| 2927 | // equality with floating-point numbers. |
| 2928 | |
| 2929 | if (fabs(S) > 0.00001) { |
| 2930 | if (R == max && G == min) { |
| 2931 | H = 5 + Bp; |
| 2932 | } else if (R == max && G != min) { |
| 2933 | H = 1 - Gp; |
| 2934 | } else if (G == max && B == min) { |
| 2935 | H = Rp + 1; |
| 2936 | } else if (G == max && B != min) { |
| 2937 | H = 3 - Bp; |
| 2938 | } else if (R == max) { |
| 2939 | H = 3 + Gp; |
| 2940 | } else { |
| 2941 | H = 5 - Rp; |
| 2942 | } |
| 2943 | } else |
| 2944 | H = 0.0; // undefined |
| 2945 | |
| 2946 | H *= 60.0; |
| 2947 | |
| 2948 | // Scale HSV |
| 2949 | |
| 2950 | H = (H * hueScale) / 255.0; |
| 2951 | S = (S * satScale) / 255.0; |
| 2952 | V = (V * valScale) / 255.0; |
| 2953 | |
| 2954 | // Convert HSV to RGB. |
| 2955 | |
| 2956 | double Hex, primary_color, secondary_color; |
| 2957 | double a, b, c; |
| 2958 | |
| 2959 | Hex = H / 60.0; |
| 2960 | primary_color = floor(Hex); |
| 2961 | secondary_color = Hex - primary_color; |
| 2962 | |
| 2963 | a = (1.0 - S) * V; |
| 2964 | b = (1.0 - (S * secondary_color)) * V; |
| 2965 | c = (1.0 - (S * (1.0 - secondary_color))) * V; |
| 2966 | |
| 2967 | switch ((int) Hex) { |
| 2968 | case 0: |
| 2969 | case 6: |
| 2970 | R = V; |
| 2971 | G = c; |
| 2972 | B = a; |
| 2973 | break; |
| 2974 | case 1: |
| 2975 | R = b; |
| 2976 | G = V; |
| 2977 | B = a; |
| 2978 | break; |
| 2979 | case 2: |
| 2980 | R = a; |
| 2981 | G = V; |
| 2982 | B = c; |
| 2983 | break; |
| 2984 | case 3: |
| 2985 | R = a; |
| 2986 | G = b; |
| 2987 | B = V; |
| 2988 | break; |
| 2989 | case 4: |
| 2990 | R = c; |
| 2991 | G = a; |
| 2992 | B = V; |
| 2993 | break; |
| 2994 | case 5: |
| 2995 | R = V; |
| 2996 | G = a; |
| 2997 | B = b; |
| 2998 | break; |
| 2999 | } |
| 3000 | |
| 3001 | int red, green, blue; |
| 3002 | |
| 3003 | red = (int) (255.0 * R + 0.5); |
| 3004 | green = (int) (255.0 * G + 0.5); |
| 3005 | blue = (int) (255.0 * B + 0.5); |
| 3006 | |
| 3007 | if (red > 255) |
| 3008 | red = 255; |
| 3009 | if (green > 255) |
| 3010 | green = 255; |
| 3011 | if (blue > 255) |
| 3012 | blue = 255; |
| 3013 | |
| 3014 | *cur++ = red; |
| 3015 | *cur++ = green; |
| 3016 | *cur++ = blue; |
| 3017 | } |
| 3018 | setDirtyColors(startColor, endColor); |
| 3019 | } |
| 3020 | } |
| 3021 | |