#include "tile_colour.h" #include #include #include #include #include tile_colour tile_colour::background(71, 108, 108, 255); tile_colour tile_colour::transparent(0, 0, 0, 0); tile_colour tile_colour::black(0, 0, 0, 255); bool tile_colour::operator==(const tile_colour &rhs) const { return (r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a); } bool tile_colour::operator!=(const tile_colour &rhs) const { return (r != rhs.r || g != rhs.g || b != rhs.b || a != rhs.a); } const tile_colour &tile_colour::operator=(const tile_colour &rhs) { r = rhs.r; g = rhs.g; b = rhs.b; a = rhs.a; 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(v); g = static_cast(t); b = static_cast(p); break; case 1: r = static_cast(q); g = static_cast(v); b = static_cast(p); break; case 2: r = static_cast(p); g = static_cast(v); b = static_cast(t); break; case 3: r = static_cast(p); g = static_cast(q); b = static_cast(v); break; case 4: r = static_cast(t); g = static_cast(p); b = static_cast(v); break; case 5: r = static_cast(v); g = static_cast(p); b = static_cast(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(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) { FILE *fp = fopen(filename, "wb"); if (!fp) { fprintf(stderr, "Error: Can't open file '%s' for write.\n", filename); return (false); } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return (false); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return (false); } png_init_io(png_ptr, fp); int bit_depth = 8; int colour_type = PNG_COLOR_TYPE_RGB_ALPHA; int interlace_type = PNG_INTERLACE_NONE; int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; int filter_method = PNG_FILTER_TYPE_DEFAULT; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, colour_type, interlace_type, compression_type, filter_method); png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); for (unsigned int y = 0; y < height; y++) row_pointers[y] = (png_byte*)&pixels[y * width]; png_set_rows(png_ptr, info_ptr, row_pointers); int png_transforms = PNG_TRANSFORM_IDENTITY; png_write_png(png_ptr, info_ptr, png_transforms, NULL); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(row_pointers); fclose(fp); return (true); }