1 /*
2 DSFML - The Simple and Fast Multimedia Library for D
3 
4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose, including commercial applications,
10 and to alter it and redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 
15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
16 
17 3. This notice may not be removed or altered from any source distribution
18 */
19 
20 module dsfml.graphics.color;
21 
22 import std.math, std.traits;
23 
24 import std.algorithm;
25 
26 /++
27  + Color is a utility struct for manipulating 32-bits RGBA colors.
28  + 
29  + Authors: Laurent Gomila, Jeremy DeHaan
30  + See_Also: http://sfml-dev.org/documentation/2.0/classsf_1_1Color.php#details
31  +/
32 struct Color
33 {
34 	ubyte r; /// Red component
35 	ubyte g; /// Green component
36 	ubyte b; /// Blue component
37 	ubyte a = 255; /// Alpha component
38 
39 	static immutable Black = Color(0, 0, 0, 255);
40 	static immutable White = Color(255, 255, 255, 255);
41 	static immutable Red = Color(255, 0, 0, 255);
42 	static immutable Green = Color(0, 255, 0,255);
43 	static immutable Blue = Color(0, 0, 255,255);
44 	static immutable Yellow = Color(255, 255, 0, 255);
45 	static immutable Magenta = Color(255, 0, 255, 255);
46 	static immutable Cyan = Color(0, 255, 255, 255);
47 	static immutable Transparent = Color(0, 0, 0, 0);
48 
49 	string toString() const
50 	{
51 		import std.conv;
52 		return "R: " ~ text(r) ~ " G: " ~ text(g) ~ " B: " ~ text(b) ~ " A: " ~ text(a);
53 	}
54 
55 	Color opBinary(string op)(Color otherColor) const
56 		if((op == "+") || (op == "-"))
57 	{
58 		static if(op == "+")
59 		{
60 			return Color(cast(ubyte)min(r+otherColor.r, 255),
61 			             cast(ubyte)min(g+otherColor.g, 255),
62 			             cast(ubyte)min(b+otherColor.b, 255),
63 			             cast(ubyte)min(a+otherColor.a, 255));
64 		}
65 		static if(op == "-")
66 		{
67 			return Color(cast(ubyte)max(r-otherColor.r, 0),
68 			             cast(ubyte)max(g-otherColor.g, 0),
69 			             cast(ubyte)max(b-otherColor.b, 0),
70 			             cast(ubyte)max(a-otherColor.a, 0));
71 		}
72 	}
73 	
74 	Color opBinary(string op, E)(E num) const
75 		if(isNumeric!(E) && ((op == "*") || (op == "/")))
76 	{
77 		static if(op == "*")
78 		{
79 			//actually dividing or multiplying by a negative
80 			if(num < 1)
81 			{
82 				return Color(cast(ubyte)max(r*num, 0),
83 				             cast(ubyte)max(g*num, 0),
84 				             cast(ubyte)max(b*num, 0),
85 				             cast(ubyte)max(a*num, 0));
86 			}
87 			else
88 			{
89 				return Color(cast(ubyte)min(r*num, 255),
90 			             	 cast(ubyte)min(g*num, 255),
91 			             	 cast(ubyte)min(b*num, 255),
92 			            	 cast(ubyte)min(a*num, 255));
93 			}
94 		}
95 		static if(op == "/")
96 		{
97 			//actually multiplying or dividing by a negative
98 			if(num < 1)
99 			{
100 				return Color(cast(ubyte)min(r/num, 255),
101 				             cast(ubyte)min(g/num, 255),
102 				             cast(ubyte)min(b/num, 255),
103 				             cast(ubyte)min(a/num, 255));
104 			}
105 			else
106 			{
107 				return Color(cast(ubyte)max(r/num, 0),
108 			    	         cast(ubyte)max(g/num, 0),
109 			       	   		 cast(ubyte)max(b/num, 0),
110 			       		     cast(ubyte)max(a/num, 0));
111 			}
112 		}
113 	}
114 	
115 	ref Color opOpAssign(string op)(Color otherColor)
116 		if((op == "+") || (op == "-"))
117 	{
118 		static if(op == "+")
119 		{
120 			r = cast(ubyte)min(r+otherColor.r, 255);
121 			g = cast(ubyte)min(g+otherColor.g, 255);
122 			b = cast(ubyte)min(b+otherColor.b, 255);
123 			a = cast(ubyte)min(a+otherColor.a, 255);
124 			return this;
125 		}
126 		static if(op == "-")
127 		{
128 			r = cast(ubyte)max(r-otherColor.r, 0);
129 			g = cast(ubyte)max(g-otherColor.g, 0);
130 			b = cast(ubyte)max(b-otherColor.b, 0);
131 			a = cast(ubyte)max(a-otherColor.a, 0);
132 			return this;
133 		}
134 	}
135 	
136 	ref Color opOpAssign(string op, E)(E num)
137 		if(isNumeric!(E) && ((op == "*") || (op == "/")))
138 	{
139 		static if(op == "*")
140 		{
141 			//actually dividing or multiplying by a negative
142 			if(num < 1)
143 			{
144 				r = cast(ubyte)max(r*num, 0);
145 				g = cast(ubyte)max(g*num, 0);
146 				b = cast(ubyte)max(b*num, 0);
147 				a = cast(ubyte)max(a*num, 0);
148 			}
149 			else
150 			{
151 				r = cast(ubyte)min(r*num, 255);
152 				g = cast(ubyte)min(g*num, 255);
153 				b = cast(ubyte)min(b*num, 255);
154 				a = cast(ubyte)min(a*num, 255);
155 			}
156 
157 			return this;
158 		}
159 		static if(op == "/")
160 		{
161 			//actually multiplying or dividing by a negative
162 			if( num < 1)
163 			{
164 				r = cast(ubyte)min(r/num, 255);
165 				g = cast(ubyte)min(g/num, 255);
166 				b = cast(ubyte)min(b/num, 255);
167 				a = cast(ubyte)min(a/num, 255);
168 			}
169 			else
170 			{
171 				r = cast(ubyte)max(r/num, 0);
172 				g = cast(ubyte)max(g/num, 0);
173 				b = cast(ubyte)max(b/num, 0);
174 				a = cast(ubyte)max(a/num, 0);
175 			}
176 
177 			return this;
178 		}
179 	}
180 	
181 	bool opEquals(Color otherColor) const
182 	{
183 		return ((r == otherColor.r) && (g == otherColor.g) && (b == otherColor.b) && (a == otherColor.a));
184 	}
185 }
186 
187 unittest
188 {
189 	version(DSFML_Unittest_Graphics)
190 	{
191 		import std.stdio;
192 
193 		writeln("Unit test for Color");
194 
195 		//will perform arithmatic on Color to make sure everything works right.
196 
197 		Color color = Color(100,100,100, 100);
198 
199 		color*= 2;//(200, 200, 200, 200)
200 
201 		color = color *.5;//(100, 100, 100, 100)
202 
203 		color = color / 2;//(50, 50, 50, 50)
204 
205 		color/= 2;//(25, 25, 25, 25)
206 
207 		color+= Color(40,20,10,5);//(65,45, 35, 30)
208 
209 
210 		color-= Color(5,10,20,40);//(60, 35, 15, 0)
211 
212 		color = color + Color(40, 20, 10, 5);//(100, 55, 25, 5)
213 
214 		color = color - Color(5, 10, 20, 40);//(95, 45, 5, 0)
215 
216 		assert(color == Color(95, 45, 5, 0));
217 
218 		writeln();
219 	}
220 }