1 module gl3n.ext.hsv; 2 3 private { 4 import std.conv : to; 5 6 import gl3n.linalg : vec3, vec4; 7 import gl3n.math : min, max, floor; 8 9 version(unittest) { 10 import gl3n.math : almost_equal; 11 } 12 } 13 14 /// Converts a 3 dimensional color-vector from the RGB to the HSV colorspace. 15 /// The function assumes that each component is in the range [0, 1]. 16 @safe pure nothrow vec3 rgb2hsv(vec3 inp) { 17 vec3 ret = vec3(0.0f, 0.0f, 0.0f); 18 19 float h_max = max(inp.r, inp.g, inp.b); 20 float h_min = min(inp.r, inp.g, inp.b); 21 float delta = h_max - h_min; 22 23 24 // h 25 if(delta == 0.0f) { 26 ret.x = 0.0f; 27 } else if(inp.r == h_max) { 28 ret.x = (inp.g - inp.b) / delta; // h 29 } else if(inp.g == h_max) { 30 ret.x = 2 + (inp.b - inp.r) / delta; // h 31 } else { 32 ret.x = 4 + (inp.r - inp.g) / delta; // h 33 } 34 35 ret.x = ret.x * 60; 36 if(ret.x < 0) { 37 ret.x = ret.x + 360; 38 } 39 40 // s 41 if(h_max == 0.0f) { 42 ret.y = 0.0f; 43 } else { 44 ret.y = delta / h_max; 45 } 46 47 // v 48 ret.z = h_max; 49 50 return ret; 51 } 52 53 /// Converts a 4 dimensional color-vector from the RGB to the HSV colorspace. 54 /// The alpha value is not touched. This function also assumes that each component is in the range [0, 1]. 55 @safe pure nothrow vec4 rgb2hsv(vec4 inp) { 56 return vec4(rgb2hsv(vec3(inp.rgb)), inp.a); 57 } 58 59 unittest { 60 assert(rgb2hsv(vec3(0.0f, 0.0f, 0.0f)) == vec3(0.0f, 0.0f, 0.0f)); 61 assert(rgb2hsv(vec3(1.0f, 1.0f, 1.0f)) == vec3(0.0f, 0.0f, 1.0f)); 62 63 vec3 hsv = rgb2hsv(vec3(100.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f)); 64 assert(hsv.x == 0.0f && hsv.y == 0.0f && almost_equal(hsv.z, 0.392157, 0.000001)); 65 66 assert(rgb2hsv(vec3(0.0f, 0.0f, 1.0f)) == vec3(240.0f, 1.0f, 1.0f)); 67 } 68 69 /// Converts a 3 dimensional color-vector from the HSV to the RGB colorspace. 70 /// RGB colors will be in the range [0, 1]. 71 /// This function is not marked es pure, since it depends on std.math.floor, which 72 /// is also not pure. 73 @safe nothrow vec3 hsv2rgb(vec3 inp) { 74 if(inp.y == 0.0f) { // s 75 return vec3(inp.zzz); // v 76 } else { 77 float var_h = inp.x * 6; 78 float var_i = to!float(floor(var_h)); 79 float var_1 = inp.z * (1 - inp.y); 80 float var_2 = inp.z * (1 - inp.y * (var_h - var_i)); 81 float var_3 = inp.z * (1 - inp.y * (1 - (var_h - var_i))); 82 83 if(var_i == 0.0f) return vec3(inp.z, var_3, var_1); 84 else if(var_i == 1.0f) return vec3(var_2, inp.z, var_1); 85 else if(var_i == 2.0f) return vec3(var_1, inp.z, var_3); 86 else if(var_i == 3.0f) return vec3(var_1, var_2, inp.z); 87 else if(var_i == 4.0f) return vec3(var_3, var_1, inp.z); 88 else return vec3(inp.z, var_1, var_2); 89 } 90 } 91 92 /// Converts a 4 dimensional color-vector from the HSV to the RGB colorspace. 93 /// The alpha value is not touched and the resulting RGB colors will be in the range [0, 1]. 94 @safe nothrow vec4 hsv2rgb(vec4 inp) { 95 return vec4(hsv2rgb(vec3(inp.xyz)), inp.w); 96 } 97 98 unittest { 99 assert(hsv2rgb(vec3(0.0f, 0.0f, 0.0f)) == vec3(0.0f, 0.0f, 0.0f)); 100 assert(hsv2rgb(vec3(0.0f, 0.0f, 1.0f)) == vec3(1.0f, 1.0f, 1.0f)); 101 102 vec3 rgb = hsv2rgb(vec3(0.0f, 0.0f, 0.392157f)); 103 assert(rgb == vec3(0.392157f, 0.392157f, 0.392157f)); 104 105 assert(hsv2rgb(vec3(300.0f, 1.0f, 1.0f)) == vec3(1.0f, 0.0f, 1.0f)); 106 }