PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Datatypes/Color.cs

#
C# | 988 lines | 560 code | 89 blank | 339 comment | 13 complexity | 3ca85ffd6206a7af1216ab0c8d41b1c8 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.ComponentModel;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Runtime.InteropServices;
  6. using Delta.Utilities.Helpers;
  7. using NUnit.Framework;
  8. namespace Delta.Utilities.Datatypes
  9. {
  10. /// <summary>
  11. /// Color datatype, originally contained 4 floats for all the color
  12. /// components. Now we still got those, but as properties because the
  13. /// internal format is a packed uint RGBA value (4 bytes instead of 16):
  14. /// R for red, G for green, B for blue and A for alpha, all between 0 and 1.
  15. /// </summary>
  16. /// <remarks>
  17. /// The change to uint (and thanks to unions to the 4 byte values RedByte,
  18. /// GreenByte, BlueByte, and AlphaByte) was done to increase rendering
  19. /// performance. Especially on mobile platforms bandwidth is key and
  20. /// reducing the amount of data send to the vertex and fragment shaders
  21. /// can speed up rendering a lot (e.g. 36 bytes per vertex lead to max. 33
  22. /// fps on the iPad, while 16 bytes (2 floats for position, 2 ushorts for UV
  23. /// and 4 bytes for color) is almost 3 times faster!
  24. /// Here can find a lot of "color codes": System.Drawing.Color
  25. /// Use Reflector or the MSDN documentation to learn more.
  26. /// http://www.htmlhelp.com/cgi-bin/color.cgi
  27. /// http://www.pamramsey.com/colors.htm
  28. /// </remarks>
  29. [Serializable]
  30. [StructLayout(LayoutKind.Explicit)]
  31. [DebuggerDisplay("Color(R={R}, G={G}, B={B}, A={A})")]
  32. [Description("Expand to edit this Color")]
  33. [TypeConverter(typeof(ExpandableObjectConverter))]
  34. public struct Color : ISaveLoadBinary, IEquatable<Color>
  35. {
  36. #region Constants
  37. /// <summary>
  38. /// Represents the size in bytes of that R,G,B,A Color (just 4 bytes).
  39. /// </summary>
  40. public const int DataSize = 4;
  41. /// <summary>
  42. /// Strings of the known color names that can be passed into FromColor!
  43. /// Note: These names are not used in ToString, but they may be used for
  44. /// UI, ComboBoxes, DropDown lists, etc.
  45. /// </summary>
  46. public static readonly string[] KnownColorNames = new string[]
  47. {
  48. "Black",
  49. "BlackHalfTransparent",
  50. "Grey",
  51. "White",
  52. "WhiteHalfTransparent",
  53. "Transparent",
  54. "Red",
  55. "Green",
  56. "Blue",
  57. "Yellow",
  58. "CornflowerBlue",
  59. "DarkBlue",
  60. "Purple",
  61. "Cyan",
  62. "Teal",
  63. "Orange",
  64. "Brown",
  65. "Gold",
  66. "LightGrey",
  67. "LightRed",
  68. "LightGreen",
  69. "LightPurple",
  70. "LightBlue",
  71. "LightTeal",
  72. "LightOrange",
  73. "DarkGrey"
  74. };
  75. /// <summary>
  76. /// Unused color, all values including alpha are set to 0. Usually used to
  77. /// indicate that a color is unused, e.g. if Graphic.Instances.ClearColor
  78. /// is set to Unused, we won't clear the backbuffer with the ClearColor
  79. /// (which is a bit faster for games that do not need to have the
  80. /// backbuffer cleared). Note that we usually have premultiplied alpha
  81. /// so it is faster to check if Alpha == 0 to see if a color is unused!
  82. /// </summary>
  83. public static readonly Color Unused =
  84. new Color(0.0f, 0.0f, 0.0f, 0.0f);
  85. /// <summary>
  86. /// Transparent color (0, 0, 0, 0), same as Unused.
  87. /// </summary>
  88. public static readonly Color Transparent = Unused;
  89. /// <summary>
  90. /// Black color (0, 0, 0), but has alpha (1), use Unused for (0, 0, 0, 0)
  91. /// </summary>
  92. public static readonly Color Black =
  93. new Color(0.0f, 0.0f, 0.0f);
  94. /// <summary>
  95. /// Black color (0, 0, 0) but with an alpha value of 0.5
  96. /// </summary>
  97. public static readonly Color BlackHalfTransparent =
  98. new Color(Black, 0.5f);
  99. /// <summary>
  100. /// Grey color (0.5, 0.5, 0.5) = (127, 127, 127)
  101. /// http://en.wikipedia.org/wiki/Grey
  102. /// </summary>
  103. public static readonly Color Grey =
  104. new Color(0.5f, 0.5f, 0.5f);
  105. /// <summary>
  106. /// White color (1, 1, 1)
  107. /// </summary>
  108. public static readonly Color White =
  109. new Color(1.0f, 1.0f, 1.0f);
  110. /// <summary>
  111. /// White color (1, 1, 1) but with an alpha value of 0.5
  112. /// </summary>
  113. public static readonly Color WhiteHalfTransparent =
  114. new Color(White, 0.5f);
  115. /// <summary>
  116. /// Red color (1, 0, 0)
  117. /// </summary>
  118. public static readonly Color Red =
  119. new Color(1.0f, 0.0f, 0.0f);
  120. /// <summary>
  121. /// Green color (0, 1, 0)
  122. /// </summary>
  123. public static readonly Color Green =
  124. new Color(0.0f, 1.0f, 0.0f);
  125. /// <summary>
  126. /// Blue color (0, 0, 1)
  127. /// </summary>
  128. public static readonly Color Blue =
  129. new Color(0.0f, 0.0f, 1.0f);
  130. /// <summary>
  131. /// Yellow color (1, 1, 0)
  132. /// </summary>
  133. public static readonly Color Yellow =
  134. new Color(1.0f, 1.0f, 0.0f);
  135. /// <summary>
  136. /// CornflowerBlue color (0.39, 0.58, 0.93)
  137. /// </summary>
  138. public static readonly Color CornflowerBlue =
  139. new Color(0.392f, 0.584f, 0.93f);
  140. /// <summary>
  141. /// Dark blue color (0.19, 0.28, 0.43)
  142. /// </summary>
  143. public static readonly Color DarkBlue =
  144. new Color(0.192f, 0.284f, 0.43f);
  145. /// <summary>
  146. /// Purple color (0.5, 0, 0.5)
  147. /// </summary>
  148. public static readonly Color Purple =
  149. new Color(0.5f, 0, 0.5f);
  150. /// <summary>
  151. /// Cyan color (0.0, 1.0, 1.0)
  152. /// </summary>
  153. public static readonly Color Cyan =
  154. new Color(0.0f, 1.0f, 1.0f);
  155. /// <summary>
  156. /// Teal color (0, 0.5, 0.5)
  157. /// </summary>
  158. public static readonly Color Teal =
  159. new Color(0, 0.5f, 0.5f);
  160. /// <summary>
  161. /// Orange color (1, 0.65, 0)
  162. /// </summary>
  163. public static readonly Color Orange =
  164. new Color(1, 0.65f, 0);
  165. /// <summary>
  166. /// Brown color (0.65, 0.16, 0.16)
  167. /// </summary>
  168. public static readonly Color Brown =
  169. new Color(0.65f, 0.165f, 0.165f);
  170. /// <summary>
  171. /// Gold color (1.0, 0.84, 0.0)
  172. /// </summary>
  173. public static readonly Color Gold =
  174. new Color(1.0f, 0.843f, 0.0f);
  175. /// <summary>
  176. /// Light grey color (0.65, 0.65, 0.65) = (165, 165, 165)
  177. /// http://en.wikipedia.org/wiki/Grey
  178. /// </summary>
  179. public static readonly Color LightGrey =
  180. new Color(0.65f, 0.65f, 0.65f);
  181. /// <summary>
  182. /// LightRed color (1, 0.25, 0.25)
  183. /// </summary>
  184. public static readonly Color LightRed =
  185. new Color(1.0f, 0.25f, 0.25f);
  186. /// <summary>
  187. /// LightGreen color (0.25, 1, 0.25)
  188. /// </summary>
  189. public static readonly Color LightGreen =
  190. new Color(0.25f, 1.0f, 0.25f);
  191. /// <summary>
  192. /// LightPurple color (0.576, 0.44, 0.86)
  193. /// </summary>
  194. public static readonly Color LightPurple =
  195. new Color(0.576f, 0.44f, 0.86f);
  196. /// <summary>
  197. /// LightBlue color (0.65f, 0.795f, 1.0f)
  198. /// </summary>
  199. public static readonly Color LightBlue =
  200. new Color(0.65f, 0.795f, 1.0f);
  201. /// <summary>
  202. /// LightTeal color (0.25, 0.8, 0.8)
  203. /// </summary>
  204. public static readonly Color LightTeal =
  205. new Color(0.25f, 0.8f, 0.8f);
  206. /// <summary>
  207. /// LightOrange color (1, 0.8, 0.25)
  208. /// </summary>
  209. public static readonly Color LightOrange =
  210. new Color(1, 0.8f, 0.25f);
  211. /// <summary>
  212. /// Dark grey color (0.35, 0.35, 0.35) = (89, 89, 89)
  213. /// http://en.wikipedia.org/wiki/Grey
  214. /// </summary>
  215. public static readonly Color DarkGrey =
  216. new Color(0.35f, 0.35f, 0.35f);
  217. #endregion
  218. #region FromString (Static)
  219. /// <summary>
  220. /// Convert a string to a Color. The expected format is
  221. /// (r.r, g.g, b.b, a.a), e.g. (0.2, 0.3, 0.4, 1.0). Alpha is optional.
  222. /// </summary>
  223. /// <param name="colorString">String containing the color values</param>
  224. /// <returns>
  225. /// Color from the colorString or White if no valid string was used.
  226. /// </returns>
  227. public static Color FromString(string colorString)
  228. {
  229. // First remove the brackets and split the string up into seperate values
  230. colorString = colorString.Replace("(", "");
  231. colorString = colorString.Replace(")", "");
  232. string[] colorStrings = colorString.Split(
  233. new[]
  234. {
  235. ',', ' '
  236. },
  237. StringSplitOptions.RemoveEmptyEntries);
  238. // Then check if the length is 4 for 4 values and return the new vector.
  239. // If the length is not 4 than return Vector.Zero.
  240. if (colorStrings.Length == 4)
  241. {
  242. return new Color(
  243. colorStrings[0].FromInvariantString(1.0f),
  244. colorStrings[1].FromInvariantString(1.0f),
  245. colorStrings[2].FromInvariantString(1.0f),
  246. colorStrings[3].FromInvariantString(1.0f));
  247. }
  248. if (colorStrings.Length == 3)
  249. {
  250. return new Color(
  251. colorStrings[0].FromInvariantString(1.0f),
  252. colorStrings[1].FromInvariantString(1.0f),
  253. colorStrings[2].FromInvariantString(1.0f));
  254. }
  255. // Check if it is one of the supported color names
  256. switch (colorString)
  257. {
  258. case "Black":
  259. return Black;
  260. case "BlackHalfTransparent":
  261. return BlackHalfTransparent;
  262. case "Grey":
  263. return Grey;
  264. case "White":
  265. return White;
  266. case "WhiteHalfTransparent":
  267. return WhiteHalfTransparent;
  268. case "Transparent":
  269. return Transparent;
  270. case "Red":
  271. return Red;
  272. case "Green":
  273. return Green;
  274. case "Blue":
  275. return Blue;
  276. case "Yellow":
  277. return Yellow;
  278. case "CornflowerBlue":
  279. return CornflowerBlue;
  280. case "DarkBlue":
  281. return DarkBlue;
  282. case "Purple":
  283. return Purple;
  284. case "Cyan":
  285. return Cyan;
  286. case "Teal":
  287. return Teal;
  288. case "Orange":
  289. return Orange;
  290. case "Brown":
  291. return Brown;
  292. case "Gold":
  293. return Gold;
  294. case "LightGrey":
  295. return LightGrey;
  296. case "LightRed":
  297. return LightRed;
  298. case "LightGreen":
  299. return LightGreen;
  300. case "LightPurple":
  301. return LightPurple;
  302. case "LightBlue":
  303. return LightBlue;
  304. case "LightTeal":
  305. return LightTeal;
  306. case "LightOrange":
  307. return LightOrange;
  308. case "DarkGrey":
  309. return DarkGrey;
  310. }
  311. // Not found? Then just return White, the default for loading colors.
  312. return White;
  313. }
  314. #endregion
  315. #region Lerp (Static)
  316. /// <summary>
  317. /// Lerp (interpolate) between to colors based on the given amount between
  318. /// 0.0 and 1.0. If the amount value is closer to 0, the output color will
  319. /// be more like c1, otherwise it will be closer to c2.
  320. /// </summary>
  321. /// <param name="c1">Color 1</param>
  322. /// <param name="c2">Color 2</param>
  323. /// <param name="amount">Amount for interpolation</param>
  324. /// <returns>Color in between c1 and c2</returns>
  325. public static Color Lerp(Color c1, Color c2, float amount)
  326. {
  327. return new Color(
  328. MathHelper.Lerp(c1.R, c2.R, amount),
  329. MathHelper.Lerp(c1.G, c2.G, amount),
  330. MathHelper.Lerp(c1.B, c2.B, amount),
  331. MathHelper.Lerp(c1.A, c2.A, amount));
  332. }
  333. #endregion
  334. #region Random (Static)
  335. /// <summary>
  336. /// Returns a random color (0-1, 0-1, 0-1)
  337. /// </summary>
  338. public static Color Random
  339. {
  340. get
  341. {
  342. return new Color(
  343. RandomHelper.RandomFloat(0, 1),
  344. RandomHelper.RandomFloat(0, 1),
  345. RandomHelper.RandomFloat(0, 1));
  346. }
  347. }
  348. #endregion
  349. #region SolidColors (Static)
  350. /// <summary>
  351. /// List of 15 predefined solid colors, which look better than random
  352. /// colors if used for profiling or effects (Red, Blue,
  353. /// Green, Yellow, Purple, Teal, Orange, White, Brown, Gray,
  354. /// CornflowerBlue, Gold, LightGreen, LightRed, LightPurple).
  355. /// </summary>
  356. public static Color[] SolidColors = new[]
  357. {
  358. Red,
  359. Blue,
  360. Green,
  361. Yellow,
  362. Purple,
  363. Teal,
  364. Orange,
  365. White,
  366. LightGreen,
  367. LightRed,
  368. LightPurple,
  369. LightTeal,
  370. LightBlue,
  371. LightOrange,
  372. Brown,
  373. LightGrey,
  374. CornflowerBlue,
  375. Gold,
  376. };
  377. #endregion
  378. #region LightColors (Static)
  379. /// <summary>
  380. /// List of 15 predefined solid colors, which look better than random
  381. /// colors if used for profiling or effects (Red, Blue,
  382. /// Green, Yellow, Purple, Teal, Orange, White, Brown, Gray,
  383. /// CornflowerBlue, Gold, LightGreen, LightRed, LightPurple).
  384. /// </summary>
  385. public static Color[] LightColors = new[]
  386. {
  387. White,
  388. LightRed,
  389. CornflowerBlue,
  390. LightBlue,
  391. LightGreen,
  392. LightOrange,
  393. };
  394. #endregion
  395. #region NextSolidColor (Static)
  396. /// <summary>
  397. /// Returns the next solid color from a predefined array (Red, Blue,
  398. /// Green, Yellow, Purple, Teal, Orange, White, Brown, Gray,
  399. /// CornflowerBlue, Gold, LightGreen, LightRed, LightPurple).
  400. /// </summary>
  401. public static Color NextSolidColor
  402. {
  403. get
  404. {
  405. return SolidColors[(SolidColorNumber++) % SolidColors.Length];
  406. }
  407. }
  408. #endregion
  409. #region NextLightColor (Static)
  410. /// <summary>
  411. /// Returns the next light color from a predefined array (White,
  412. /// LightRed, CornflowerBlue, LightBlue, LightGreen, LightOrange).
  413. /// </summary>
  414. public static Color NextLightColor
  415. {
  416. get
  417. {
  418. return LightColors[(LightColorNumber++) % LightColors.Length];
  419. }
  420. }
  421. #endregion
  422. #region Framework Union Defines (Public)
  423. #endregion
  424. #region PackedRGBA (Public)
  425. /// <summary>
  426. /// This color as 4 packed bytes in an uint value. This is the same format
  427. /// used for OpenGL colors, xna colors and RGBA values in general :)
  428. /// </summary>
  429. [FieldOffset(0)]
  430. public uint PackedRGBA;
  431. #endregion
  432. #region RedByte (Public)
  433. /// <summary>
  434. /// Red byte in a range of [0,255]. Use the property R for a float [0,1].
  435. /// </summary>
  436. [FieldOffset(0)]
  437. public byte RedByte;
  438. #endregion
  439. #region GreenByte (Public)
  440. /// <summary>
  441. /// Green byte in a range of [0,255]. Use the property G for a float [0,1].
  442. /// </summary>
  443. [FieldOffset(1)]
  444. public byte GreenByte;
  445. #endregion
  446. #region BlueByte (Public)
  447. /// <summary>
  448. /// Blue byte in a range of [0,255]. Use the property B for a float [0,1].
  449. /// </summary>
  450. [FieldOffset(2)]
  451. public byte BlueByte;
  452. #endregion
  453. #region AlphaByte (Public)
  454. /// <summary>
  455. /// Alpha channel byte in a range of [0,255]. Use the property B for a
  456. /// float [0,1]. 0=transparent, 255 (or A=1)=fully visible. Note: Like
  457. /// xna 4.0 we use premultiplied alpha by default, which makes
  458. /// multiplying colors a little easier (just newAlpha*Color).
  459. /// </summary>
  460. [FieldOffset(3)]
  461. public byte AlphaByte;
  462. #endregion
  463. #region R (Public)
  464. /// <summary>
  465. /// Red channel (in a range of [0,1], caller has to make sure not to set
  466. /// this to any crazy value). Set to the RedByte value of this color.
  467. /// </summary>
  468. [Browsable(true)]
  469. [DisplayName("Red")]
  470. public float R
  471. {
  472. get
  473. {
  474. return RedByte / 255.0f;
  475. }
  476. set
  477. {
  478. RedByte = (byte)(value * 255.0f);
  479. }
  480. }
  481. #endregion
  482. #region G (Public)
  483. /// <summary>
  484. /// Green channel (in a range of [0,1]). Set to the GreenByte value of
  485. /// this color.
  486. /// </summary>
  487. [Browsable(true)]
  488. [DisplayName("Green")]
  489. public float G
  490. {
  491. get
  492. {
  493. return GreenByte / 255.0f;
  494. }
  495. set
  496. {
  497. GreenByte = (byte)(value * 255.0f);
  498. }
  499. }
  500. #endregion
  501. #region B (Public)
  502. /// <summary>
  503. /// Blue channel (in a range of [0,1]). Set to the BlueByte value of this
  504. /// color.
  505. /// </summary>
  506. [Browsable(true)]
  507. [DisplayName("Blue")]
  508. public float B
  509. {
  510. get
  511. {
  512. return BlueByte / 255.0f;
  513. }
  514. set
  515. {
  516. BlueByte = (byte)(value * 255.0f);
  517. }
  518. }
  519. #endregion
  520. #region A (Public)
  521. /// <summary>
  522. /// Alpha channel (in a range of [0,1]). 0=transparent, 1=fully visible.
  523. /// Note: Like XNA 4.0 we use premultiplied alpha by default, which makes
  524. /// multiplying colors a little easier (just newAlpha*Color). Set to the
  525. /// AlphaByte value of this color.
  526. /// </summary>
  527. [Browsable(true)]
  528. [DisplayName("Alpha")]
  529. public float A
  530. {
  531. get
  532. {
  533. return AlphaByte / 255.0f;
  534. }
  535. set
  536. {
  537. AlphaByte = (byte)(value * 255.0f);
  538. }
  539. }
  540. #endregion
  541. #region Private
  542. #region SolidColorNumber (Private)
  543. /// <summary>
  544. /// Current index for NextSolidColor, will increase each call.
  545. /// </summary>
  546. private static int SolidColorNumber;
  547. #endregion
  548. #region LightColorNumber (Private)
  549. /// <summary>
  550. /// Current index for NextLightColor, will increase each call.
  551. /// </summary>
  552. private static int LightColorNumber;
  553. #endregion
  554. #endregion
  555. #region Constructors
  556. /// <summary>
  557. /// Creates a color with an alpha of 1.0
  558. /// </summary>
  559. /// <param name="setBaseColor">Sets the "base color" RGB</param>
  560. /// <param name="setA">Set alpha channel in a range of [0,1]</param>
  561. public Color(Color setBaseColor, float setA)
  562. : this(setBaseColor.R, setBaseColor.G, setBaseColor.B, setA)
  563. {
  564. }
  565. /// <summary>
  566. /// Creates a color with an alpha of 1.0
  567. /// </summary>
  568. /// <param name="setR">Set red channel in a range of [0,1]</param>
  569. /// <param name="setG">Set green channel in a range of [0,1]</param>
  570. /// <param name="setB">Set blue channel in a range of [0,1]</param>
  571. public Color(float setR, float setG, float setB)
  572. : this(setR, setG, setB, 1.0f)
  573. {
  574. }
  575. /// <summary>
  576. /// Creates a color with values for R, G, B, A.
  577. /// </summary>
  578. /// <param name="setR">Set red channel in a range of [0,1]</param>
  579. /// <param name="setG">Set green channel in a range of [0,1]</param>
  580. /// <param name="setB">Set blue channel in a range of [0,1]</param>
  581. /// <param name="setA">Set alpha channel in a range of [0,1]</param>
  582. public Color(float setR, float setG, float setB, float setA)
  583. // Needed now because of PackedRGBA, XNA and SlimDx unions
  584. : this()
  585. {
  586. // If any value is above 10 interpret it as a byte value, not a float!
  587. // This is basically not allowed in the Delta Engine, but if any byte
  588. // values come into this method (e.g. via FromString), fix the issue.
  589. if (setR > 10)
  590. {
  591. setR = setR / 255.0f;
  592. }
  593. if (setG > 10)
  594. {
  595. setG = setG / 255.0f;
  596. }
  597. if (setB > 10)
  598. {
  599. setB = setB / 255.0f;
  600. }
  601. if (setA > 10)
  602. {
  603. setA = setA / 255.0f;
  604. }
  605. // Note: Nothing is clamped here, make sure the input does not go out of
  606. // range at the caller level.
  607. RedByte = (byte)(setR * 255.0f);
  608. GreenByte = (byte)(setG * 255.0f);
  609. BlueByte = (byte)(setB * 255.0f);
  610. AlphaByte = (byte)(setA * 255.0f);
  611. }
  612. /// <summary>
  613. /// Creates a color from the byte RGB values in the range [0-255] for each
  614. /// channel.
  615. /// </summary>
  616. /// <param name="setR">The red value in the range [0-255].</param>
  617. /// <param name="setG">The green value in the range [0-255].</param>
  618. /// <param name="setB">The blue value in the range [0-255].</param>
  619. public Color(byte setR, byte setG, byte setB)
  620. // Needed now because of PackedRGBA, XNA and SlimDx unions
  621. : this()
  622. {
  623. RedByte = setR;
  624. GreenByte = setG;
  625. BlueByte = setB;
  626. AlphaByte = 255;
  627. }
  628. /// <summary>
  629. /// Creates a color from the byte RGBA values in the range [0-255] for each
  630. /// channel.
  631. /// </summary>
  632. /// <param name="setR">The red value in the range [0-255].</param>
  633. /// <param name="setG">The green value in the range [0-255].</param>
  634. /// <param name="setB">The blue value in the range [0-255].</param>
  635. /// <param name="setA">The alpha value in the range [0-255].</param>
  636. public Color(byte setR, byte setG, byte setB, byte setA)
  637. // Needed now because of PackedRGBA, XNA and SlimDx unions
  638. : this()
  639. {
  640. RedByte = setR;
  641. GreenByte = setG;
  642. BlueByte = setB;
  643. AlphaByte = setA;
  644. }
  645. /// <summary>
  646. /// Create color from binary data stream (e.g. to load vertices or
  647. /// material data).
  648. /// </summary>
  649. /// <param name="setReader">setReader</param>
  650. public Color(BinaryReader setReader)
  651. : this()
  652. {
  653. Load(setReader);
  654. }
  655. #endregion
  656. #region IEquatable<Color> Members
  657. /// <summary>
  658. /// Equals
  659. /// </summary>
  660. /// <param name="other">Other</param>
  661. /// <returns>Value indicating the equality of two colors</returns>
  662. public bool Equals(Color other)
  663. {
  664. return PackedRGBA == other.PackedRGBA;
  665. }
  666. #endregion
  667. #region ISaveLoadBinary Members
  668. /// <summary>
  669. /// Load the color values from a stream (4 bytes).
  670. /// </summary>
  671. /// <param name="reader">The stream that will be used.</param>
  672. public void Load(BinaryReader reader)
  673. {
  674. PackedRGBA = reader.ReadUInt32();
  675. }
  676. /// <summary>
  677. /// Saves the color out to a stream (4 bytes).
  678. /// </summary>
  679. /// <param name="writer">The stream that will be used.</param>
  680. public void Save(BinaryWriter writer)
  681. {
  682. writer.Write(PackedRGBA);
  683. }
  684. #endregion
  685. #region op_Multiply (Operator)
  686. /// <summary>
  687. /// Multiply operator to multiply all color values with a number.
  688. /// </summary>
  689. /// <param name="c1">Color to multiply</param>
  690. /// <param name="brightScale">Bright scale</param>
  691. /// <returns>Color</returns>
  692. public static Color operator *(Color c1, float brightScale)
  693. {
  694. return new Color(
  695. c1.R * brightScale,
  696. c1.G * brightScale,
  697. c1.B * brightScale,
  698. c1.A * brightScale);
  699. }
  700. /// <summary>
  701. /// Multiply operator to multiply two colors (each value will be multiplied)
  702. /// </summary>
  703. /// <param name="c1">Color 1</param>
  704. /// <param name="c2">Color 2</param>
  705. /// <returns>Color</returns>
  706. public static Color operator *(Color c1, Color c2)
  707. {
  708. return new Color(c1.R * c2.R, c1.G * c2.G, c1.B * c2.B, c1.A * c2.A);
  709. }
  710. #endregion
  711. #region op_Equality (Operator)
  712. /// <summary>
  713. /// Check for equality
  714. /// </summary>
  715. /// <param name="value1">Value 1</param>
  716. /// <param name="value2">Value 2</param>
  717. /// <returns>True if the values are equal, false otherwise</returns>
  718. public static bool operator ==(Color value1, Color value2)
  719. {
  720. return value1.PackedRGBA == value2.PackedRGBA;
  721. }
  722. #endregion
  723. #region op_Inequality (Operator)
  724. /// <summary>
  725. /// Check for inequality
  726. /// </summary>
  727. /// <param name="value1">Value 1</param>
  728. /// <param name="value2">Value 2</param>
  729. /// <returns>True if the values are not equal</returns>
  730. public static bool operator !=(Color value1, Color value2)
  731. {
  732. return value1.PackedRGBA != value2.PackedRGBA;
  733. }
  734. #endregion
  735. #region GetHashCode (Public)
  736. /// <summary>
  737. /// Get hash code
  738. /// </summary>
  739. /// <returns>hash code</returns>
  740. public override int GetHashCode()
  741. {
  742. return PackedRGBA.GetHashCode();
  743. }
  744. #endregion
  745. #region Equals (Public)
  746. /// <summary>
  747. /// Equals
  748. /// </summary>
  749. /// <param name="obj">Object to compare to</param>
  750. /// <returns>True if the values are equal, false otherwise</returns>
  751. public override bool Equals(object obj)
  752. {
  753. if (obj is Color)
  754. {
  755. return Equals((Color)obj);
  756. }
  757. return base.Equals(obj);
  758. }
  759. #endregion
  760. #region ToString (Public)
  761. /// <summary>
  762. /// To string
  763. /// </summary>
  764. /// <returns>string</returns>
  765. public override string ToString()
  766. {
  767. //return String.Format("({0}, {1}, {2}, {3})", R, G, B, A);
  768. return ToString("(", ")");
  769. }
  770. /// <summary>
  771. /// To string
  772. /// </summary>
  773. /// <param name="closeBrace">closeBrace</param>
  774. /// <param name="openBrace">openBrace</param>
  775. /// <returns>string</returns>
  776. public string ToString(string openBrace, string closeBrace)
  777. {
  778. return openBrace + R.ToInvariantString("0.00") +
  779. ", " + G.ToInvariantString("0.00") +
  780. ", " + B.ToInvariantString("0.00") +
  781. ", " + A.ToInvariantString("0.00") + closeBrace;
  782. }
  783. #endregion
  784. /// <summary>
  785. /// Tests
  786. /// </summary>
  787. internal class ColorTests
  788. {
  789. #region Constructor (Static)
  790. /// <summary>
  791. /// FromIntRGB
  792. /// </summary>
  793. [Test]
  794. public static void Constructor()
  795. {
  796. Color testColor = new Color(255, 0, 127, 255);
  797. Assert.NearlyEqual(testColor.R, 1f);
  798. Assert.NearlyEqual(testColor.G, 0f);
  799. Assert.NearlyEqual(testColor.B, 0.498f);
  800. Assert.NearlyEqual(testColor.A, 1f);
  801. }
  802. #endregion
  803. #region SizeOf (Static)
  804. /// <summary>
  805. /// Checks if the size of Point is exactly 8 bytes (2 floats: X and Y)
  806. /// </summary>
  807. [Test]
  808. public static void SizeOf()
  809. {
  810. // Color consists of 4 bytes: R, G, B, and A
  811. Assert.Equal(4, Marshal.SizeOf(typeof(Color)));
  812. }
  813. #endregion
  814. #region ColorCompare (Static)
  815. /// <summary>
  816. /// Color compare
  817. /// </summary>
  818. [Test]
  819. public static void ColorCompare()
  820. {
  821. Color testColor = Black;
  822. Assert.NotEqual(White, testColor);
  823. Assert.NotEqual(new Color(0, 1, 0), testColor);
  824. Assert.Equal(new Color(0, 0, 0), testColor);
  825. Assert.Equal(Black, testColor);
  826. Assert.Equal(testColor, testColor);
  827. }
  828. #endregion
  829. #region SaveAndLoad (Static)
  830. /// <summary>
  831. /// Save
  832. /// </summary>
  833. [Test]
  834. public static void SaveAndLoad()
  835. {
  836. Color color = Yellow;
  837. #region Saving
  838. MemoryStream memHandle = new MemoryStream();
  839. Assert.Equal(0, memHandle.Position);
  840. BinaryWriter writer = new BinaryWriter(memHandle);
  841. // save all the current data
  842. color.Save(writer);
  843. // and finally check (for saving) if the file was written correctly
  844. Assert.NotEqual(0, memHandle.Length);
  845. #endregion
  846. #region Loading
  847. // then we create an "empty" material
  848. Color loadColor = Unused;
  849. memHandle.Position = 0;
  850. // which we use to load the material values from the the file
  851. // Note: The using closes the file access too
  852. BinaryReader reader = new BinaryReader(memHandle);
  853. loadColor.Load(reader);
  854. // before we finally check if everything is loaded correctly
  855. Assert.Equal(color, loadColor);
  856. #endregion
  857. writer.Close();
  858. reader.Close();
  859. memHandle.Close();
  860. }
  861. #endregion
  862. #region Multiplication (Static)
  863. /// <summary>
  864. /// Multiplication
  865. /// </summary>
  866. [Test]
  867. public static void Multiplication()
  868. {
  869. Assert.Equal(Yellow, Yellow * White);
  870. Assert.Equal(new Color(1, 1, 0, 0.5f),
  871. Yellow * new Color(1, 1, 1, 0.5f));
  872. Assert.Equal(Black, Red * Green);
  873. }
  874. #endregion
  875. #region FromString (Static)
  876. /// <summary>
  877. /// FromString
  878. /// </summary>
  879. [Test]
  880. public static void FromString()
  881. {
  882. Color testColor = Color.FromString("(0.0, 1.0, 0.0, 0.5)");
  883. Assert.Equal(testColor, new Color(0f, 1f, 0f, 0.5f));
  884. }
  885. #endregion
  886. #region Equality
  887. /// <summary>
  888. /// Equality
  889. /// </summary>
  890. [Test]
  891. public void Equality()
  892. {
  893. Assert.Equal(new Color(1f, 1f, 0f, 1f), Yellow);
  894. Assert.NotEqual(White, Yellow);
  895. }
  896. #endregion
  897. }
  898. }
  899. }