diff options
Diffstat (limited to 'src/ColorTransformation.vala')
-rw-r--r-- | src/ColorTransformation.vala | 425 |
1 files changed, 185 insertions, 240 deletions
diff --git a/src/ColorTransformation.vala b/src/ColorTransformation.vala index 435d3f4..8595e96 100644 --- a/src/ColorTransformation.vala +++ b/src/ColorTransformation.vala @@ -26,9 +26,9 @@ public struct RGBAnalyticPixel { public RGBAnalyticPixel.from_quantized_components(uchar red_quantized, uchar green_quantized, uchar blue_quantized) { - this.red = ((float) red_quantized) * INV_255; - this.green = ((float) green_quantized) * INV_255; - this.blue = ((float) blue_quantized) * INV_255; + this.red = rgb_lookup_table[red_quantized]; + this.green = rgb_lookup_table[green_quantized]; + this.blue = rgb_lookup_table[blue_quantized]; } public RGBAnalyticPixel.from_hsv(HSVAnalyticPixel hsv_pixel) { @@ -86,118 +86,14 @@ public struct HSVAnalyticPixel { public HSVAnalyticPixel.from_quantized_components(uchar hue_quantized, uchar saturation_quantized, uchar light_value_quantized) { - this.hue = ((float) hue_quantized) * INV_255; - this.saturation = ((float) saturation_quantized) * INV_255; - this.light_value = ((float) light_value_quantized) * INV_255; + this.hue = rgb_lookup_table[hue_quantized]; + this.saturation = rgb_lookup_table[saturation_quantized]; + this.light_value = rgb_lookup_table[light_value_quantized]; } - public HSVAnalyticPixel.from_rgb(RGBAnalyticPixel p) { - float max_component = float.max(float.max(p.red, p.green), p.blue); - float min_component = float.min(float.min(p.red, p.green), p.blue); + public extern HSVAnalyticPixel.from_rgb(RGBAnalyticPixel p); - light_value = max_component; - saturation = (max_component != 0.0f) ? ((max_component - min_component) / - max_component) : 0.0f; - - if (saturation == 0.0f) { - hue = 0.0f; /* hue is undefined in the zero saturation case */ - } else { - float delta = max_component - min_component; - if (p.red == max_component) { - hue = (p.green - p.blue) / delta; - } else if (p.green == max_component) { - hue = 2.0f + ((p.blue - p.red) / delta); - } else if (p.blue == max_component) { - hue = 4.0f + ((p.red - p.green) / delta); - } - - hue *= 60.0f; - if (hue < 0.0f) - hue += 360.0f; - - hue /= 360.0f; /* normalize hue */ - } - - hue = hue.clamp(0.0f, 1.0f); - saturation = saturation.clamp(0.0f, 1.0f); - light_value = light_value.clamp(0.0f, 1.0f); - } - - public RGBAnalyticPixel to_rgb() { - RGBAnalyticPixel result = RGBAnalyticPixel(); - - if (saturation == 0.0f) { - result.red = light_value; - result.green = light_value; - result.blue = light_value; - } else { - float hue_denorm = hue * 360.0f; - if (hue_denorm == 360.0f) - hue_denorm = 0.0f; - - float hue_hexant = hue_denorm / 60.0f; - - int hexant_i_part = (int) hue_hexant; - - float hexant_f_part = hue_hexant - ((float) hexant_i_part); - - /* the p, q, and t quantities from section 13.3 of Foley, et. al. */ - float p = light_value * (1.0f - saturation); - float q = light_value * (1.0f - (saturation * hexant_f_part)); - float t = light_value * (1.0f - (saturation * (1.0f - hexant_f_part))); - switch (hexant_i_part) { - /* the (r, g, b) components of the output pixel are computed - from the light_value, p, q, and t quantities differently - depending on which "hexant" (1/6 of a full rotation) of the - HSV color cone the hue lies in. For example, if the hue lies - in the yellow hexant, the dominant channels in the output - are red and green, so we map relatively more of the light_value - into these colors than if, say, the hue were to lie in the - cyan hexant. See chapter 13 of Foley, et. al. for more - information. */ - case 0: - result.red = light_value; - result.green = t; - result.blue = p; - break; - - case 1: - result.red = q; - result.green = light_value; - result.blue = p; - break; - - case 2: - result.red = p; - result.green = light_value; - result.blue = t; - break; - - case 3: - result.red = p; - result.green = q; - result.blue = light_value; - break; - - case 4: - result.red = t; - result.green = p; - result.blue = light_value; - break; - - case 5: - result.red = light_value; - result.green = p; - result.blue = q; - break; - - default: - error("bad color hexant in HSV-to-RGB conversion"); - } - } - - return result; - } + public extern RGBAnalyticPixel to_rgb(); public bool equals(ref HSVAnalyticPixel rhs) { return ((hue == rhs.hue) && (saturation == rhs.saturation) && @@ -212,7 +108,8 @@ public struct HSVAnalyticPixel { public enum CompositionMode { NONE, - RGB_MATRIX + RGB_MATRIX, + HSV_LOOKUP } public enum PixelFormat { @@ -369,16 +266,21 @@ public class PixelTransformationBundle { public abstract class PixelTransformation { private PixelTransformationType type; + private PixelFormat preferred_format; - public PixelTransformation(PixelTransformationType type) { + public PixelTransformation(PixelTransformationType type, + PixelFormat preferred_format) { this.type = type; + this.preferred_format = preferred_format; } public PixelTransformationType get_transformation_type() { return type; } - public abstract PixelFormat get_preferred_format(); + public PixelFormat get_preferred_format() { + return this.preferred_format; + } public virtual CompositionMode get_composition_mode() { return CompositionMode.NONE; @@ -418,7 +320,7 @@ public class RGBTransformation : PixelTransformation { protected bool identity = true; public RGBTransformation(PixelTransformationType type) { - base(type); + base(type, PixelFormat.RGB); // Can't initialize these in their member declarations because of a valac bug that // I've been unable to produce a minimal test case for to report (JN). May be @@ -431,10 +333,6 @@ public class RGBTransformation : PixelTransformation { 0.0f, 0.0f, 0.0f, 1.0f }; } - public override PixelFormat get_preferred_format() { - return PixelFormat.RGB; - } - public override CompositionMode get_composition_mode() { return CompositionMode.RGB_MATRIX; } @@ -558,27 +456,7 @@ public class RGBTransformation : PixelTransformation { return (transform_pixel_rgb(p.to_rgb())).to_hsv(); } - public override RGBAnalyticPixel transform_pixel_rgb(RGBAnalyticPixel p) { - float red_out = (p.red * matrix_entries[0]) + - (p.green * matrix_entries[1]) + - (p.blue * matrix_entries[2]) + - matrix_entries[3]; - red_out = red_out.clamp(0.0f, 1.0f); - - float green_out = (p.red * matrix_entries[4]) + - (p.green * matrix_entries[5]) + - (p.blue * matrix_entries[6]) + - matrix_entries[7]; - green_out = green_out.clamp(0.0f, 1.0f); - - float blue_out = (p.red * matrix_entries[8]) + - (p.green * matrix_entries[9]) + - (p.blue * matrix_entries[10]) + - matrix_entries[11]; - blue_out = blue_out.clamp(0.0f, 1.0f); - - return RGBAnalyticPixel.from_components(red_out, green_out, blue_out); - } + public extern override RGBAnalyticPixel transform_pixel_rgb(RGBAnalyticPixel p); public override bool is_identity() { return identity; @@ -596,17 +474,46 @@ public class RGBTransformation : PixelTransformation { } public abstract class HSVTransformation : PixelTransformation { + protected float remap_table[256]; + public HSVTransformation(PixelTransformationType type) { - base(type); + base(type, PixelFormat.HSV); } - - public override PixelFormat get_preferred_format() { - return PixelFormat.HSV; + + public override CompositionMode get_composition_mode() { + return CompositionMode.HSV_LOOKUP; } public override RGBAnalyticPixel transform_pixel_rgb(RGBAnalyticPixel p) { return (transform_pixel_hsv(p.to_hsv())).to_rgb(); } + + public override void compose_with(PixelTransformation other) { + if (other.get_composition_mode() != CompositionMode.HSV_LOOKUP) { + error("HSVTransformation: compose_with(): wrong"); + } + + var hsv_trans = (HSVTransformation) other; + + // We can do this because ALL HSV transformations actually only + // operate on the light_value + for (var i = 0; i < 256; i++) { + var idx = (int) (this.remap_table[i] * 255.0f); + this.remap_table[i] = hsv_trans.remap_table[idx].clamp (0.0f, 1.0f); + } + } + + public override HSVAnalyticPixel transform_pixel_hsv(HSVAnalyticPixel pixel) { + int remap_index = (int)(pixel.light_value * 255.0f); + + HSVAnalyticPixel result = pixel; + result.light_value = remap_table[remap_index]; + + result.light_value = result.light_value.clamp(0.0f, 1.0f); + + return result; + } + } public class TintTransformation : RGBTransformation { @@ -775,9 +682,9 @@ public class ContrastTransformation : RGBTransformation { public class PixelTransformer { private Gee.ArrayList<PixelTransformation> transformations = new Gee.ArrayList<PixelTransformation>(); - private PixelTransformation[] optimized_transformations = null; - private int optimized_slots_used = 0; - + public PixelTransformation[] optimized_transformations = null; + public int optimized_slots_used = 0; + public PixelTransformer() { } @@ -817,33 +724,7 @@ public class PixelTransformer { } } - private RGBAnalyticPixel apply_transformations(RGBAnalyticPixel p) { - PixelFormat current_format = PixelFormat.RGB; - RGBAnalyticPixel p_rgb = p; - HSVAnalyticPixel p_hsv = HSVAnalyticPixel(); - - for (int i = 0; i < optimized_slots_used; i++) { - PixelTransformation trans = optimized_transformations[i]; - if (trans.get_preferred_format() == PixelFormat.RGB) { - if (current_format == PixelFormat.HSV) { - p_rgb = p_hsv.to_rgb(); - current_format = PixelFormat.RGB; - } - p_rgb = trans.transform_pixel_rgb(p_rgb); - } else { - if (current_format == PixelFormat.RGB) { - p_hsv = p_rgb.to_hsv(); - current_format = PixelFormat.HSV; - } - p_hsv = trans.transform_pixel_hsv(p_hsv); - } - } - - if (current_format == PixelFormat.HSV) - p_rgb = p_hsv.to_rgb(); - - return p_rgb; - } + private extern RGBAnalyticPixel apply_transformations(RGBAnalyticPixel p); /* NOTE: this method allows the same transformation to be added multiple times. There's nothing wrong with this behavior as of today, @@ -889,31 +770,52 @@ public class PixelTransformer { int dest_num_channels = dest.get_n_channels(); int dest_rowstride = dest.get_rowstride(); unowned uchar[] dest_pixels = dest.get_pixels(); - - int cache_pixel_ticker = 0; - for (int j = 0; j < dest_height; j++) { - int row_start_index = j * dest_rowstride; - int row_end_index = row_start_index + (dest_width * dest_num_channels); - for (int i = row_start_index; i < row_end_index; i += dest_num_channels) { - RGBAnalyticPixel pixel = RGBAnalyticPixel.from_components( - fp_pixel_cache[cache_pixel_ticker], - fp_pixel_cache[cache_pixel_ticker + 1], - fp_pixel_cache[cache_pixel_ticker + 2]); + var jobs = (int) GLib.get_num_processors() - 1; - cache_pixel_ticker += 3; + uint slice_length = dest_height; + if (jobs > 0) { + slice_length = (dest_height + (jobs - 1)) / jobs; + } - pixel = apply_transformations(pixel); + var threads = new GLib.Thread<void *>[jobs]; + + unowned float[] cache = fp_pixel_cache; + for (var job = 0; job < jobs; job++) { + var row = job * slice_length; + var slice_height = (row + slice_length).clamp(0, dest_height); + threads[job] = new GLib.Thread<void*>("shotwell-worker", () => { + uint cache_pixel_ticker = row * dest_width * 3; + for (uint j = row; j < slice_height; j++) { + uint row_start_index = j * dest_rowstride; + uint row_end_index = row_start_index + (dest_width * dest_num_channels); + for (uint i = row_start_index; i < row_end_index; i += dest_num_channels) { + RGBAnalyticPixel pixel = RGBAnalyticPixel.from_components( + cache[cache_pixel_ticker], + cache[cache_pixel_ticker + 1], + cache[cache_pixel_ticker + 2]); + + cache_pixel_ticker += 3; + + pixel = apply_transformations(pixel); + + dest_pixels[i] = (uchar) (pixel.red * 255.0f); + dest_pixels[i + 1] = (uchar) (pixel.green * 255.0f); + dest_pixels[i + 2] = (uchar) (pixel.blue * 255.0f); + } + } - dest_pixels[i] = (uchar) (pixel.red * 255.0f); - dest_pixels[i + 1] = (uchar) (pixel.green * 255.0f); - dest_pixels[i + 2] = (uchar) (pixel.blue * 255.0f); - } + return null; + }); + } + + foreach (var thread in threads) { + thread.join(); } } public void transform_to_other_pixbuf(Gdk.Pixbuf source, Gdk.Pixbuf dest, - Cancellable? cancellable = null) { + Cancellable? cancellable = null, int jobs = -1) { if (source.width != dest.width) error("PixelTransformer: source and destination pixbufs must have the same width"); @@ -934,28 +836,50 @@ public class PixelTransformer { int rowbytes = n_channels * width; unowned uchar[] source_pixels = source.get_pixels(); unowned uchar[] dest_pixels = dest.get_pixels(); - for (int j = 0; j < height; j++) { - int row_start_index = j * rowstride; - int row_end_index = row_start_index + rowbytes; - for (int i = row_start_index; i < row_end_index; i += n_channels) { - RGBAnalyticPixel current_pixel = RGBAnalyticPixel.from_quantized_components( - source_pixels[i], source_pixels[i + 1], source_pixels[i + 2]); + if (jobs == -1) { + jobs = (int) GLib.get_num_processors() - 1; + } - current_pixel = apply_transformations(current_pixel); + uint slice_length = height; + if (jobs > 0) { + slice_length = (height + (jobs - 1)) / jobs; + } - dest_pixels[i] = current_pixel.quantized_red(); - dest_pixels[i + 1] = current_pixel.quantized_green(); - dest_pixels[i + 2] = current_pixel.quantized_blue(); - } + var threads = new GLib.Thread<void*>[jobs]; - if ((cancellable != null) && (cancellable.is_cancelled())) { - return; - } + for (var job = 0; job < jobs; job++) { + var row = job * slice_length; + var slice_height = (row + slice_length).clamp(0, height); + + threads[job] = new GLib.Thread<void*>("shotwell-worker", () => { + for (var j = row; j < slice_height; j++) { + this.apply_transformation(j, rowstride, rowbytes, n_channels, source_pixels, + dest_pixels); + + if ((cancellable != null) && (cancellable.is_cancelled())) { + break; + } + } + + return null; + }); + } + + foreach (var thread in threads) { + thread.join(); } } + + private extern void apply_transformation(uint row, + int rowstride, + int rowbytes, + int n_channels, + uchar[] source_pixels, + uchar[] dest_pixels); + } -class RGBHistogram { +public class RGBHistogram { private const uchar MARKED_BACKGROUND = 30; private const uchar MARKED_FOREGROUND = 210; private const uchar UNMARKED_BACKGROUND = 120; @@ -1253,7 +1177,6 @@ public class IntensityHistogram { } public class ExpansionTransformation : HSVTransformation { - private float[] remap_table = null; private const float LOW_DISCARD_MASS = 0.02f; private const float HIGH_DISCARD_MASS = 0.02f; @@ -1263,8 +1186,6 @@ public class ExpansionTransformation : HSVTransformation { public ExpansionTransformation(IntensityHistogram histogram) { base(PixelTransformationType.TONE_EXPANSION); - remap_table = new float[256]; - float LOW_KINK_MASS = LOW_DISCARD_MASS; low_kink = 0; while (histogram.get_cumulative_probability(low_kink) < LOW_KINK_MASS) @@ -1315,9 +1236,6 @@ public class ExpansionTransformation : HSVTransformation { } private void build_remap_table() { - if (remap_table == null) - remap_table = new float[256]; - float low_kink_f = ((float) low_kink) / 255.0f; float high_kink_f = ((float) high_kink) / 255.0f; @@ -1335,17 +1253,6 @@ public class ExpansionTransformation : HSVTransformation { remap_table[i] = 1.0f; } - public override HSVAnalyticPixel transform_pixel_hsv(HSVAnalyticPixel pixel) { - int remap_index = (int)(pixel.light_value * 255.0f); - - HSVAnalyticPixel result = pixel; - result.light_value = remap_table[remap_index]; - - result.light_value = result.light_value.clamp(0.0f, 1.0f); - - return result; - } - public override string to_string() { return "{ %d, %d }".printf(low_kink, high_kink); } @@ -1374,7 +1281,6 @@ public class ShadowDetailTransformation : HSVTransformation { private const float TONAL_WIDTH = 1.0f; private float intensity = 0.0f; - private float[] remap_table = null; public const float MIN_PARAMETER = 0.0f; public const float MAX_PARAMETER = 32.0f; @@ -1389,7 +1295,6 @@ public class ShadowDetailTransformation : HSVTransformation { HermiteGammaApproximationFunction func = new HermiteGammaApproximationFunction(TONAL_WIDTH); - remap_table = new float[256]; for (int i = 0; i < 256; i++) { float x = ((float) i) / 255.0f; float weight = func.evaluate(x); @@ -1397,12 +1302,6 @@ public class ShadowDetailTransformation : HSVTransformation { } } - public override HSVAnalyticPixel transform_pixel_hsv(HSVAnalyticPixel pixel) { - HSVAnalyticPixel result = pixel; - result.light_value = (remap_table[(int)(pixel.light_value * 255.0f)]).clamp(0.0f, 1.0f); - return result; - } - public override PixelTransformation copy() { return new ShadowDetailTransformation(intensity); } @@ -1448,7 +1347,6 @@ public class HighlightDetailTransformation : HSVTransformation { private const float TONAL_WIDTH = 1.0f; private float intensity = 0.0f; - private float[] remap_table = null; public const float MIN_PARAMETER = -32.0f; public const float MAX_PARAMETER = 0.0f; @@ -1463,7 +1361,6 @@ public class HighlightDetailTransformation : HSVTransformation { HermiteGammaApproximationFunction func = new HermiteGammaApproximationFunction(TONAL_WIDTH); - remap_table = new float[256]; for (int i = 0; i < 256; i++) { float x = ((float) i) / 255.0f; float weight = func.evaluate(1.0f - x); @@ -1471,12 +1368,6 @@ public class HighlightDetailTransformation : HSVTransformation { } } - public override HSVAnalyticPixel transform_pixel_hsv(HSVAnalyticPixel pixel) { - HSVAnalyticPixel result = pixel; - result.light_value = (remap_table[(int)(pixel.light_value * 255.0f)]).clamp(0.0f, 1.0f); - return result; - } - public override PixelTransformation copy() { return new HighlightDetailTransformation(intensity); } @@ -1562,3 +1453,57 @@ public PixelTransformationBundle create_auto_enhance_adjustments(Gdk.Pixbuf pixb } } +public const float rgb_lookup_table[] = { + 0.0f/255.0f, 1.0f/255.0f, 2.0f/255.0f, 3.0f/255.0f, 4.0f/255.0f, + 5.0f/255.0f, 6.0f/255.0f, 7.0f/255.0f, 8.0f/255.0f, 9.0f/255.0f, + 10.0f/255.0f, 11.0f/255.0f, 12.0f/255.0f, 13.0f/255.0f, 14.0f/255.0f, + 15.0f/255.0f, 16.0f/255.0f, 17.0f/255.0f, 18.0f/255.0f, 19.0f/255.0f, + 20.0f/255.0f, 21.0f/255.0f, 22.0f/255.0f, 23.0f/255.0f, 24.0f/255.0f, + 25.0f/255.0f, 26.0f/255.0f, 27.0f/255.0f, 28.0f/255.0f, 29.0f/255.0f, + 30.0f/255.0f, 31.0f/255.0f, 32.0f/255.0f, 33.0f/255.0f, 34.0f/255.0f, + 35.0f/255.0f, 36.0f/255.0f, 37.0f/255.0f, 38.0f/255.0f, 39.0f/255.0f, + 40.0f/255.0f, 41.0f/255.0f, 42.0f/255.0f, 43.0f/255.0f, 44.0f/255.0f, + 45.0f/255.0f, 46.0f/255.0f, 47.0f/255.0f, 48.0f/255.0f, 49.0f/255.0f, + 50.0f/255.0f, 51.0f/255.0f, 52.0f/255.0f, 53.0f/255.0f, 54.0f/255.0f, + 55.0f/255.0f, 56.0f/255.0f, 57.0f/255.0f, 58.0f/255.0f, 59.0f/255.0f, + 60.0f/255.0f, 61.0f/255.0f, 62.0f/255.0f, 63.0f/255.0f, 64.0f/255.0f, + 65.0f/255.0f, 66.0f/255.0f, 67.0f/255.0f, 68.0f/255.0f, 69.0f/255.0f, + 70.0f/255.0f, 71.0f/255.0f, 72.0f/255.0f, 73.0f/255.0f, 74.0f/255.0f, + 75.0f/255.0f, 76.0f/255.0f, 77.0f/255.0f, 78.0f/255.0f, 79.0f/255.0f, + 80.0f/255.0f, 81.0f/255.0f, 82.0f/255.0f, 83.0f/255.0f, 84.0f/255.0f, + 85.0f/255.0f, 86.0f/255.0f, 87.0f/255.0f, 88.0f/255.0f, 89.0f/255.0f, + 90.0f/255.0f, 91.0f/255.0f, 92.0f/255.0f, 93.0f/255.0f, 94.0f/255.0f, + 95.0f/255.0f, 96.0f/255.0f, 97.0f/255.0f, 98.0f/255.0f, 99.0f/255.0f, + 100.0f/255.0f, 101.0f/255.0f, 102.0f/255.0f, 103.0f/255.0f, 104.0f/255.0f, + 105.0f/255.0f, 106.0f/255.0f, 107.0f/255.0f, 108.0f/255.0f, 109.0f/255.0f, + 110.0f/255.0f, 111.0f/255.0f, 112.0f/255.0f, 113.0f/255.0f, 114.0f/255.0f, + 115.0f/255.0f, 116.0f/255.0f, 117.0f/255.0f, 118.0f/255.0f, 119.0f/255.0f, + 120.0f/255.0f, 121.0f/255.0f, 122.0f/255.0f, 123.0f/255.0f, 124.0f/255.0f, + 125.0f/255.0f, 126.0f/255.0f, 127.0f/255.0f, 128.0f/255.0f, 129.0f/255.0f, + 130.0f/255.0f, 131.0f/255.0f, 132.0f/255.0f, 133.0f/255.0f, 134.0f/255.0f, + 135.0f/255.0f, 136.0f/255.0f, 137.0f/255.0f, 138.0f/255.0f, 139.0f/255.0f, + 140.0f/255.0f, 141.0f/255.0f, 142.0f/255.0f, 143.0f/255.0f, 144.0f/255.0f, + 145.0f/255.0f, 146.0f/255.0f, 147.0f/255.0f, 148.0f/255.0f, 149.0f/255.0f, + 150.0f/255.0f, 151.0f/255.0f, 152.0f/255.0f, 153.0f/255.0f, 154.0f/255.0f, + 155.0f/255.0f, 156.0f/255.0f, 157.0f/255.0f, 158.0f/255.0f, 159.0f/255.0f, + 160.0f/255.0f, 161.0f/255.0f, 162.0f/255.0f, 163.0f/255.0f, 164.0f/255.0f, + 165.0f/255.0f, 166.0f/255.0f, 167.0f/255.0f, 168.0f/255.0f, 169.0f/255.0f, + 170.0f/255.0f, 171.0f/255.0f, 172.0f/255.0f, 173.0f/255.0f, 174.0f/255.0f, + 175.0f/255.0f, 176.0f/255.0f, 177.0f/255.0f, 178.0f/255.0f, 179.0f/255.0f, + 180.0f/255.0f, 181.0f/255.0f, 182.0f/255.0f, 183.0f/255.0f, 184.0f/255.0f, + 185.0f/255.0f, 186.0f/255.0f, 187.0f/255.0f, 188.0f/255.0f, 189.0f/255.0f, + 190.0f/255.0f, 191.0f/255.0f, 192.0f/255.0f, 193.0f/255.0f, 194.0f/255.0f, + 195.0f/255.0f, 196.0f/255.0f, 197.0f/255.0f, 198.0f/255.0f, 199.0f/255.0f, + 200.0f/255.0f, 201.0f/255.0f, 202.0f/255.0f, 203.0f/255.0f, 204.0f/255.0f, + 205.0f/255.0f, 206.0f/255.0f, 207.0f/255.0f, 208.0f/255.0f, 209.0f/255.0f, + 210.0f/255.0f, 211.0f/255.0f, 212.0f/255.0f, 213.0f/255.0f, 214.0f/255.0f, + 215.0f/255.0f, 216.0f/255.0f, 217.0f/255.0f, 218.0f/255.0f, 219.0f/255.0f, + 220.0f/255.0f, 221.0f/255.0f, 222.0f/255.0f, 223.0f/255.0f, 224.0f/255.0f, + 225.0f/255.0f, 226.0f/255.0f, 227.0f/255.0f, 228.0f/255.0f, 229.0f/255.0f, + 230.0f/255.0f, 231.0f/255.0f, 232.0f/255.0f, 233.0f/255.0f, 234.0f/255.0f, + 235.0f/255.0f, 236.0f/255.0f, 237.0f/255.0f, 238.0f/255.0f, 239.0f/255.0f, + 240.0f/255.0f, 241.0f/255.0f, 242.0f/255.0f, 243.0f/255.0f, 244.0f/255.0f, + 245.0f/255.0f, 246.0f/255.0f, 247.0f/255.0f, 248.0f/255.0f, 249.0f/255.0f, + 250.0f/255.0f, 251.0f/255.0f, 252.0f/255.0f, 253.0f/255.0f, 254.0f/255.0f, + 255.0f/255.0f, +}; |