diff options
Diffstat (limited to 'crawl-ref/source/rltiles/tool/tile_colour.cc')
-rw-r--r-- | crawl-ref/source/rltiles/tool/tile_colour.cc | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/crawl-ref/source/rltiles/tool/tile_colour.cc b/crawl-ref/source/rltiles/tool/tile_colour.cc index f1969f37be..b5569ee073 100644 --- a/crawl-ref/source/rltiles/tool/tile_colour.cc +++ b/crawl-ref/source/rltiles/tool/tile_colour.cc @@ -1,4 +1,5 @@ #include "tile_colour.h" +#include <cassert> #include <vector> #include <stdlib.h> #include <stdio.h> @@ -28,6 +29,226 @@ const tile_colour &tile_colour::operator=(const tile_colour &rhs) return (*this); } +unsigned char &tile_colour::operator[](int idx) +{ + assert(idx >= 0 && idx <= 4); + switch (idx) + { + default: + case 0: return r; + case 1: return g; + case 2: return b; + case 3: return a; + } +} + +unsigned char tile_colour::operator[](int idx) const +{ + assert(idx >= 0 && idx <= 4); + switch (idx) + { + default: + case 0: return r; + case 1: return g; + case 2: return b; + case 3: return a; + } +} + +int tile_colour::get_hue() const +{ + int max_rgb = get_max_rgb(); + int min_rgb = get_min_rgb(); + + if (max_rgb == min_rgb) + return (0); + + int diff = max_rgb - min_rgb; + + if (max_rgb == r) + { + return ((60 * (g - b)) / diff + 360) % 360; + } + else if (max_rgb == g) + { + return (60 * (b - r)) / diff + 120; + } + else // if (max_rgb == b) + { + return (60 * (r - g)) / diff + 240; + } +} + +int tile_colour::get_max_rgb() const +{ + int max_rgb = std::max(std::max(r, g), b); + return (max_rgb); +} + +int tile_colour::get_min_rgb() const +{ + int min_rgb = std::min(std::min(r, g), b); + return (min_rgb); +} + +void tile_colour::set_hue(int h) +{ + set_from_hue(h, get_min_rgb(), get_max_rgb()); +} + +void tile_colour::set_from_hue(int h, int min_rgb, int max_rgb) +{ + // http://en.wikipedia.org/wiki/HSL_and_HSV + // H is passed in + // S = diff / max or 0 if max == 0 + // V = max / 255 + + int v = max_rgb; + int s = max_rgb - min_rgb; + + float f = ((float)h / 60.0f) - (int)(h / 60); + + // When calculating P, Q, T, also convert to 0..255 range. + int p = v - s; + int q = v - f * s; + int t = v - (1.0f - f) * s; + + // Sanity bounds. + q = std::max(std::min(q, 255), 0); + t = std::max(std::min(t, 255), 0); + + int h_idx = (h / 60) % 6; + + switch (h_idx) + { + default: + case 0: + r = static_cast<unsigned char>(v); + g = static_cast<unsigned char>(t); + b = static_cast<unsigned char>(p); + break; + case 1: + r = static_cast<unsigned char>(q); + g = static_cast<unsigned char>(v); + b = static_cast<unsigned char>(p); + break; + case 2: + r = static_cast<unsigned char>(p); + g = static_cast<unsigned char>(v); + b = static_cast<unsigned char>(t); + break; + case 3: + r = static_cast<unsigned char>(p); + g = static_cast<unsigned char>(q); + b = static_cast<unsigned char>(v); + break; + case 4: + r = static_cast<unsigned char>(t); + g = static_cast<unsigned char>(p); + b = static_cast<unsigned char>(v); + break; + case 5: + r = static_cast<unsigned char>(v); + g = static_cast<unsigned char>(p); + b = static_cast<unsigned char>(q); + break; + } +} + +void tile_colour::desaturate() +{ + set_from_hue(get_hue(), get_max_rgb(), get_max_rgb()); +} + +float tile_colour::get_lum() const +{ + return ((get_min_rgb() + get_max_rgb()) / (255 * 2.0f)); +} + +float tile_colour::get_sat() const +{ + int min_rgb = get_min_rgb(); + int max_rgb = get_max_rgb(); + int sum = min_rgb + max_rgb; + + float sat; + if (sum == 0) + sat = 0; + else if (sum > 255) + sat = (max_rgb - min_rgb) / (float)(255*2 - min_rgb - max_rgb); + else + sat = (max_rgb - min_rgb) / (float)(min_rgb + max_rgb); + + return (sat); +} + +void tile_colour::set_from_hsl(int hue, float sat, float lum) +{ + float q; + if (lum < 0.5f) + q = lum * (1 + sat); + else + q = lum + sat - (lum * sat); + + float p = 2 * lum - q; + + for (int i = 0; i < 3; ++i) + { + int h = hue + (1 - i) * 120; + if (h < 0) + h += 360; + if (h >= 360) + h -= 360; + + float val; + + if (h < 60) + val = p + (q - p) * h / 60.0f; + else if (h < 180) + val = q; + else if (h < 240) + val = p + (q - p) * (4 - h / 60.0f); + else + val = p; + + int final = val * 255; + final = std::max(0, std::min(255, final)); + (*this)[i] = static_cast<unsigned char>(final); + } +} + +void tile_colour::change_lum(int lum_percent) +{ + int min_rgb = get_min_rgb(); + int max_rgb = get_max_rgb(); + int hue = get_hue(); + + if (min_rgb == max_rgb) + { + int rgb_change = (lum_percent * 255) / 100; + + min_rgb += rgb_change; + max_rgb += rgb_change; + + min_rgb = std::max(0, std::min(255, min_rgb)); + max_rgb = std::max(0, std::min(255, max_rgb)); + + set_from_hue(get_hue(), min_rgb, max_rgb); + return; + } + + float lum_change = lum_percent / 100.0f; + float lum = get_lum() + lum_change; + + if (lum > 1.0f) + lum = 1.0f; + if (lum < 0.0f) + lum = 0.0f; + + float sat = get_sat(); + set_from_hsl(hue, sat, lum); +} + bool write_png(const char *filename, tile_colour *pixels, unsigned int width, unsigned int height) { |