1 using System;
2 using System.Runtime.InteropServices;
3 
4 namespace Godot
5 {
6     /// <summary>
7     /// A color represented by red, green, blue, and alpha (RGBA) components.
8     /// The alpha component is often used for transparency.
9     /// Values are in floating-point and usually range from 0 to 1.
10     /// Some properties (such as CanvasItem.modulate) may accept values
11     /// greater than 1 (overbright or HDR colors).
12     ///
13     /// If you want to supply values in a range of 0 to 255, you should use
14     /// <see cref="Color8"/> and the `r8`/`g8`/`b8`/`a8` properties.
15     /// </summary>
16     [Serializable]
17     [StructLayout(LayoutKind.Sequential)]
18     public struct Color : IEquatable<Color>
19     {
20         /// <summary>
21         /// The color's red component, typically on the range of 0 to 1.
22         /// </summary>
23         public float r;
24 
25         /// <summary>
26         /// The color's green component, typically on the range of 0 to 1.
27         /// </summary>
28         public float g;
29 
30         /// <summary>
31         /// The color's blue component, typically on the range of 0 to 1.
32         /// </summary>
33         public float b;
34 
35         /// <summary>
36         /// The color's alpha (transparency) component, typically on the range of 0 to 1.
37         /// </summary>
38         public float a;
39 
40         /// <summary>
41         /// Wrapper for <see cref="r"/> that uses the range 0 to 255 instead of 0 to 1.
42         /// </summary>
43         /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
44         public int r8
45         {
46             get
47             {
48                 return (int)Math.Round(r * 255.0f);
49             }
50             set
51             {
52                 r = value / 255.0f;
53             }
54         }
55 
56         /// <summary>
57         /// Wrapper for <see cref="g"/> that uses the range 0 to 255 instead of 0 to 1.
58         /// </summary>
59         /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
60         public int g8
61         {
62             get
63             {
64                 return (int)Math.Round(g * 255.0f);
65             }
66             set
67             {
68                 g = value / 255.0f;
69             }
70         }
71 
72         /// <summary>
73         /// Wrapper for <see cref="b"/> that uses the range 0 to 255 instead of 0 to 1.
74         /// </summary>
75         /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
76         public int b8
77         {
78             get
79             {
80                 return (int)Math.Round(b * 255.0f);
81             }
82             set
83             {
84                 b = value / 255.0f;
85             }
86         }
87 
88         /// <summary>
89         /// Wrapper for <see cref="a"/> that uses the range 0 to 255 instead of 0 to 1.
90         /// </summary>
91         /// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
92         public int a8
93         {
94             get
95             {
96                 return (int)Math.Round(a * 255.0f);
97             }
98             set
99             {
100                 a = value / 255.0f;
101             }
102         }
103 
104         /// <summary>
105         /// The HSV hue of this color, on the range 0 to 1.
106         /// </summary>
107         /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value>
108         public float h
109         {
110             get
111             {
112                 float max = Math.Max(r, Math.Max(g, b));
113                 float min = Math.Min(r, Math.Min(g, b));
114 
115                 float delta = max - min;
116 
117                 if (delta == 0)
118                 {
119                     return 0;
120                 }
121 
122                 float h;
123 
124                 if (r == max)
125                 {
126                     h = (g - b) / delta; // Between yellow & magenta
127                 }
128                 else if (g == max)
129                 {
130                     h = 2 + (b - r) / delta; // Between cyan & yellow
131                 }
132                 else
133                 {
134                     h = 4 + (r - g) / delta; // Between magenta & cyan
135                 }
136 
137                 h /= 6.0f;
138 
139                 if (h < 0)
140                 {
141                     h += 1.0f;
142                 }
143 
144                 return h;
145             }
146             set
147             {
148                 this = FromHsv(value, s, v, a);
149             }
150         }
151 
152         /// <summary>
153         /// The HSV saturation of this color, on the range 0 to 1.
154         /// </summary>
155         /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value>
156         public float s
157         {
158             get
159             {
160                 float max = Math.Max(r, Math.Max(g, b));
161                 float min = Math.Min(r, Math.Min(g, b));
162 
163                 float delta = max - min;
164 
165                 return max == 0 ? 0 : delta / max;
166             }
167             set
168             {
169                 this = FromHsv(h, value, v, a);
170             }
171         }
172 
173         /// <summary>
174         /// The HSV value (brightness) of this color, on the range 0 to 1.
175         /// </summary>
176         /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHsv"/>.</value>
177         public float v
178         {
179             get
180             {
181                 return Math.Max(r, Math.Max(g, b));
182             }
183             set
184             {
185                 this = FromHsv(h, s, value, a);
186             }
187         }
188 
189         /// <summary>
190         /// Returns a color according to the standardized name, with the
191         /// specified alpha value. Supported color names are the same as
192         /// the constants defined in <see cref="Colors"/>.
193         /// </summary>
194         /// <param name="name">The name of the color.</param>
195         /// <param name="alpha">The alpha (transparency) component represented on the range of 0 to 1. Default: 1.</param>
196         /// <returns>The constructed color.</returns>
ColorNGodot.Color197         public static Color ColorN(string name, float alpha = 1f)
198         {
199             name = name.Replace(" ", String.Empty);
200             name = name.Replace("-", String.Empty);
201             name = name.Replace("_", String.Empty);
202             name = name.Replace("'", String.Empty);
203             name = name.Replace(".", String.Empty);
204             name = name.ToLower();
205 
206             if (!Colors.namedColors.ContainsKey(name))
207             {
208                 throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
209             }
210 
211             Color color = Colors.namedColors[name];
212             color.a = alpha;
213             return color;
214         }
215 
216         /// <summary>
217         /// Access color components using their index.
218         /// </summary>
219         /// <value>`[0]` is equivalent to `.r`, `[1]` is equivalent to `.g`, `[2]` is equivalent to `.b`, `[3]` is equivalent to `.a`.</value>
220         public float this[int index]
221         {
222             get
223             {
224                 switch (index)
225                 {
226                     case 0:
227                         return r;
228                     case 1:
229                         return g;
230                     case 2:
231                         return b;
232                     case 3:
233                         return a;
234                     default:
235                         throw new IndexOutOfRangeException();
236                 }
237             }
238             set
239             {
240                 switch (index)
241                 {
242                     case 0:
243                         r = value;
244                         return;
245                     case 1:
246                         g = value;
247                         return;
248                     case 2:
249                         b = value;
250                         return;
251                     case 3:
252                         a = value;
253                         return;
254                     default:
255                         throw new IndexOutOfRangeException();
256                 }
257             }
258         }
259 
260         /// <summary>
261         /// Converts a color to HSV values. This is equivalent to using each of
262         /// the `h`/`s`/`v` properties, but much more efficient.
263         /// </summary>
264         /// <param name="hue">Output parameter for the HSV hue.</param>
265         /// <param name="saturation">Output parameter for the HSV saturation.</param>
266         /// <param name="value">Output parameter for the HSV value.</param>
ToHsvGodot.Color267         public void ToHsv(out float hue, out float saturation, out float value)
268         {
269             float max = (float)Mathf.Max(r, Mathf.Max(g, b));
270             float min = (float)Mathf.Min(r, Mathf.Min(g, b));
271 
272             float delta = max - min;
273 
274             if (delta == 0)
275             {
276                 hue = 0;
277             }
278             else
279             {
280                 if (r == max)
281                     hue = (g - b) / delta; // Between yellow & magenta
282                 else if (g == max)
283                     hue = 2 + (b - r) / delta; // Between cyan & yellow
284                 else
285                     hue = 4 + (r - g) / delta; // Between magenta & cyan
286 
287                 hue /= 6.0f;
288 
289                 if (hue < 0)
290                     hue += 1.0f;
291             }
292 
293             saturation = max == 0 ? 0 : 1f - 1f * min / max;
294             value = max;
295         }
296 
297         /// <summary>
298         /// Constructs a color from an HSV profile, with values on the
299         /// range of 0 to 1. This is equivalent to using each of
300         /// the `h`/`s`/`v` properties, but much more efficient.
301         /// </summary>
302         /// <param name="hue">The HSV hue, typically on the range of 0 to 1.</param>
303         /// <param name="saturation">The HSV saturation, typically on the range of 0 to 1.</param>
304         /// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param>
305         /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
306         /// <returns>The constructed color.</returns>
FromHsvGodot.Color307         public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f)
308         {
309             if (saturation == 0)
310             {
311                 // acp_hromatic (grey)
312                 return new Color(value, value, value, alpha);
313             }
314 
315             int i;
316             float f, p, q, t;
317 
318             hue *= 6.0f;
319             hue %= 6f;
320             i = (int)hue;
321 
322             f = hue - i;
323             p = value * (1 - saturation);
324             q = value * (1 - saturation * f);
325             t = value * (1 - saturation * (1 - f));
326 
327             switch (i)
328             {
329                 case 0: // Red is the dominant color
330                     return new Color(value, t, p, alpha);
331                 case 1: // Green is the dominant color
332                     return new Color(q, value, p, alpha);
333                 case 2:
334                     return new Color(p, value, t, alpha);
335                 case 3: // Blue is the dominant color
336                     return new Color(p, q, value, alpha);
337                 case 4:
338                     return new Color(t, p, value, alpha);
339                 default: // (5) Red is the dominant color
340                     return new Color(value, p, q, alpha);
341             }
342         }
343 
344         /// <summary>
345         /// Returns a new color resulting from blending this color over another.
346         /// If the color is opaque, the result is also opaque.
347         /// The second color may have a range of alpha values.
348         /// </summary>
349         /// <param name="over">The color to blend over.</param>
350         /// <returns>This color blended over `over`.</returns>
BlendGodot.Color351         public Color Blend(Color over)
352         {
353             Color res;
354 
355             float sa = 1.0f - over.a;
356             res.a = a * sa + over.a;
357 
358             if (res.a == 0)
359             {
360                 return new Color(0, 0, 0, 0);
361             }
362 
363             res.r = (r * a * sa + over.r * over.a) / res.a;
364             res.g = (g * a * sa + over.g * over.a) / res.a;
365             res.b = (b * a * sa + over.b * over.a) / res.a;
366 
367             return res;
368         }
369 
370         /// <summary>
371         /// Returns the most contrasting color.
372         /// </summary>
373         /// <returns>The most contrasting color</returns>
ContrastedGodot.Color374         public Color Contrasted()
375         {
376             return new Color(
377                 (r + 0.5f) % 1.0f,
378                 (g + 0.5f) % 1.0f,
379                 (b + 0.5f) % 1.0f,
380                 a
381             );
382         }
383 
384         /// <summary>
385         /// Returns a new color resulting from making this color darker
386         /// by the specified ratio (on the range of 0 to 1).
387         /// </summary>
388         /// <param name="amount">The ratio to darken by.</param>
389         /// <returns>The darkened color.</returns>
DarkenedGodot.Color390         public Color Darkened(float amount)
391         {
392             Color res = this;
393             res.r = res.r * (1.0f - amount);
394             res.g = res.g * (1.0f - amount);
395             res.b = res.b * (1.0f - amount);
396             return res;
397         }
398 
399         /// <summary>
400         /// Returns the inverted color: `(1 - r, 1 - g, 1 - b, a)`.
401         /// </summary>
402         /// <returns>The inverted color.</returns>
InvertedGodot.Color403         public Color Inverted()
404         {
405             return new Color(
406                 1.0f - r,
407                 1.0f - g,
408                 1.0f - b,
409                 a
410             );
411         }
412 
413         /// <summary>
414         /// Returns a new color resulting from making this color lighter
415         /// by the specified ratio (on the range of 0 to 1).
416         /// </summary>
417         /// <param name="amount">The ratio to lighten by.</param>
418         /// <returns>The darkened color.</returns>
LightenedGodot.Color419         public Color Lightened(float amount)
420         {
421             Color res = this;
422             res.r = res.r + (1.0f - res.r) * amount;
423             res.g = res.g + (1.0f - res.g) * amount;
424             res.b = res.b + (1.0f - res.b) * amount;
425             return res;
426         }
427 
428         /// <summary>
429         /// Returns the result of the linear interpolation between
430         /// this color and `to` by amount `weight`.
431         /// </summary>
432         /// <param name="to">The destination color for interpolation.</param>
433         /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
434         /// <returns>The resulting color of the interpolation.</returns>
LinearInterpolateGodot.Color435         public Color LinearInterpolate(Color to, float weight)
436         {
437             return new Color
438             (
439                 Mathf.Lerp(r, to.r, weight),
440                 Mathf.Lerp(g, to.g, weight),
441                 Mathf.Lerp(b, to.b, weight),
442                 Mathf.Lerp(a, to.a, weight)
443             );
444         }
445 
446         /// <summary>
447         /// Returns the result of the linear interpolation between
448         /// this color and `to` by color amount `weight`.
449         /// </summary>
450         /// <param name="to">The destination color for interpolation.</param>
451         /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
452         /// <returns>The resulting color of the interpolation.</returns>
LinearInterpolateGodot.Color453         public Color LinearInterpolate(Color to, Color weight)
454         {
455             return new Color
456             (
457                 Mathf.Lerp(r, to.r, weight.r),
458                 Mathf.Lerp(g, to.g, weight.g),
459                 Mathf.Lerp(b, to.b, weight.b),
460                 Mathf.Lerp(a, to.a, weight.a)
461             );
462         }
463 
464         /// <summary>
465         /// Returns the color's 32-bit integer in ABGR format
466         /// (each byte represents a component of the ABGR profile).
467         /// ABGR is the reversed version of the default format.
468         /// </summary>
469         /// <returns>An int representing this color in ABGR32 format.</returns>
ToAbgr32Godot.Color470         public int ToAbgr32()
471         {
472             int c = (byte)Math.Round(a * 255);
473             c <<= 8;
474             c |= (byte)Math.Round(b * 255);
475             c <<= 8;
476             c |= (byte)Math.Round(g * 255);
477             c <<= 8;
478             c |= (byte)Math.Round(r * 255);
479 
480             return c;
481         }
482 
483         /// <summary>
484         /// Returns the color's 64-bit integer in ABGR format
485         /// (each byte represents a component of the ABGR profile).
486         /// ABGR is the reversed version of the default format.
487         /// </summary>
488         /// <returns>An int representing this color in ABGR64 format.</returns>
ToAbgr64Godot.Color489         public long ToAbgr64()
490         {
491             long c = (ushort)Math.Round(a * 65535);
492             c <<= 16;
493             c |= (ushort)Math.Round(b * 65535);
494             c <<= 16;
495             c |= (ushort)Math.Round(g * 65535);
496             c <<= 16;
497             c |= (ushort)Math.Round(r * 65535);
498 
499             return c;
500         }
501 
502         /// <summary>
503         /// Returns the color's 32-bit integer in ARGB format
504         /// (each byte represents a component of the ARGB profile).
505         /// ARGB is more compatible with DirectX, but not used much in Godot.
506         /// </summary>
507         /// <returns>An int representing this color in ARGB32 format.</returns>
ToArgb32Godot.Color508         public int ToArgb32()
509         {
510             int c = (byte)Math.Round(a * 255);
511             c <<= 8;
512             c |= (byte)Math.Round(r * 255);
513             c <<= 8;
514             c |= (byte)Math.Round(g * 255);
515             c <<= 8;
516             c |= (byte)Math.Round(b * 255);
517 
518             return c;
519         }
520 
521         /// <summary>
522         /// Returns the color's 64-bit integer in ARGB format
523         /// (each word represents a component of the ARGB profile).
524         /// ARGB is more compatible with DirectX, but not used much in Godot.
525         /// </summary>
526         /// <returns>A long representing this color in ARGB64 format.</returns>
ToArgb64Godot.Color527         public long ToArgb64()
528         {
529             long c = (ushort)Math.Round(a * 65535);
530             c <<= 16;
531             c |= (ushort)Math.Round(r * 65535);
532             c <<= 16;
533             c |= (ushort)Math.Round(g * 65535);
534             c <<= 16;
535             c |= (ushort)Math.Round(b * 65535);
536 
537             return c;
538         }
539 
540         /// <summary>
541         /// Returns the color's 32-bit integer in RGBA format
542         /// (each byte represents a component of the RGBA profile).
543         /// RGBA is Godot's default and recommended format.
544         /// </summary>
545         /// <returns>An int representing this color in RGBA32 format.</returns>
ToRgba32Godot.Color546         public int ToRgba32()
547         {
548             int c = (byte)Math.Round(r * 255);
549             c <<= 8;
550             c |= (byte)Math.Round(g * 255);
551             c <<= 8;
552             c |= (byte)Math.Round(b * 255);
553             c <<= 8;
554             c |= (byte)Math.Round(a * 255);
555 
556             return c;
557         }
558 
559         /// <summary>
560         /// Returns the color's 64-bit integer in RGBA format
561         /// (each word represents a component of the RGBA profile).
562         /// RGBA is Godot's default and recommended format.
563         /// </summary>
564         /// <returns>A long representing this color in RGBA64 format.</returns>
ToRgba64Godot.Color565         public long ToRgba64()
566         {
567             long c = (ushort)Math.Round(r * 65535);
568             c <<= 16;
569             c |= (ushort)Math.Round(g * 65535);
570             c <<= 16;
571             c |= (ushort)Math.Round(b * 65535);
572             c <<= 16;
573             c |= (ushort)Math.Round(a * 65535);
574 
575             return c;
576         }
577 
578         /// <summary>
579         /// Returns the color's HTML hexadecimal color string in RGBA format.
580         /// </summary>
581         /// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param>
582         /// <returns>A string for the HTML hexadecimal representation of this color.</returns>
ToHtmlGodot.Color583         public string ToHtml(bool includeAlpha = true)
584         {
585             var txt = string.Empty;
586 
587             txt += ToHex32(r);
588             txt += ToHex32(g);
589             txt += ToHex32(b);
590 
591             if (includeAlpha)
592                 txt = ToHex32(a) + txt;
593 
594             return txt;
595         }
596 
597         /// <summary>
598         /// Constructs a color from RGBA values on the range of 0 to 1.
599         /// </summary>
600         /// <param name="r">The color's red component, typically on the range of 0 to 1.</param>
601         /// <param name="g">The color's green component, typically on the range of 0 to 1.</param>
602         /// <param name="b">The color's blue component, typically on the range of 0 to 1.</param>
603         /// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
ColorGodot.Color604         public Color(float r, float g, float b, float a = 1.0f)
605         {
606             this.r = r;
607             this.g = g;
608             this.b = b;
609             this.a = a;
610         }
611 
612         /// <summary>
613         /// Constructs a color from an existing color and an alpha value.
614         /// </summary>
615         /// <param name="c">The color to construct from. Only its RGB values are used.</param>
616         /// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
ColorGodot.Color617         public Color(Color c, float a = 1.0f)
618         {
619             r = c.r;
620             g = c.g;
621             b = c.b;
622             this.a = a;
623         }
624 
625         /// <summary>
626         /// Constructs a color from a 32-bit integer
627         /// (each byte represents a component of the RGBA profile).
628         /// </summary>
629         /// <param name="rgba">The int representing the color.</param>
ColorGodot.Color630         public Color(int rgba)
631         {
632             a = (rgba & 0xFF) / 255.0f;
633             rgba >>= 8;
634             b = (rgba & 0xFF) / 255.0f;
635             rgba >>= 8;
636             g = (rgba & 0xFF) / 255.0f;
637             rgba >>= 8;
638             r = (rgba & 0xFF) / 255.0f;
639         }
640 
641         /// <summary>
642         /// Constructs a color from a 64-bit integer
643         /// (each word represents a component of the RGBA profile).
644         /// </summary>
645         /// <param name="rgba">The long representing the color.</param>
ColorGodot.Color646         public Color(long rgba)
647         {
648             a = (rgba & 0xFFFF) / 65535.0f;
649             rgba >>= 16;
650             b = (rgba & 0xFFFF) / 65535.0f;
651             rgba >>= 16;
652             g = (rgba & 0xFFFF) / 65535.0f;
653             rgba >>= 16;
654             r = (rgba & 0xFFFF) / 65535.0f;
655         }
656 
ParseCol8Godot.Color657         private static int ParseCol8(string str, int ofs)
658         {
659             int ig = 0;
660 
661             for (int i = 0; i < 2; i++)
662             {
663                 int c = str[i + ofs];
664                 int v;
665 
666                 if (c >= '0' && c <= '9')
667                 {
668                     v = c - '0';
669                 }
670                 else if (c >= 'a' && c <= 'f')
671                 {
672                     v = c - 'a';
673                     v += 10;
674                 }
675                 else if (c >= 'A' && c <= 'F')
676                 {
677                     v = c - 'A';
678                     v += 10;
679                 }
680                 else
681                 {
682                     return -1;
683                 }
684 
685                 if (i == 0)
686                 {
687                     ig += v * 16;
688                 }
689                 else
690                 {
691                     ig += v;
692                 }
693             }
694 
695             return ig;
696         }
697 
ToHex32Godot.Color698         private String ToHex32(float val)
699         {
700             int v = Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
701 
702             var ret = string.Empty;
703 
704             for (int i = 0; i < 2; i++)
705             {
706                 char c;
707                 int lv = v & 0xF;
708 
709                 if (lv < 10)
710                 {
711                     c = (char)('0' + lv);
712                 }
713                 else
714                 {
715                     c = (char)('a' + lv - 10);
716                 }
717 
718                 v >>= 4;
719                 ret = c + ret;
720             }
721 
722             return ret;
723         }
724 
HtmlIsValidGodot.Color725         internal static bool HtmlIsValid(string color)
726         {
727             if (color.Length == 0)
728             {
729                 return false;
730             }
731 
732             if (color[0] == '#')
733             {
734                 color = color.Substring(1, color.Length - 1);
735             }
736 
737             bool alpha;
738 
739             switch (color.Length)
740             {
741                 case 8:
742                     alpha = true;
743                     break;
744                 case 6:
745                     alpha = false;
746                     break;
747                 default:
748                     return false;
749             }
750 
751             if (alpha)
752             {
753                 if (ParseCol8(color, 0) < 0)
754                 {
755                     return false;
756                 }
757             }
758 
759             int from = alpha ? 2 : 0;
760 
761             if (ParseCol8(color, from + 0) < 0)
762                 return false;
763             if (ParseCol8(color, from + 2) < 0)
764                 return false;
765             if (ParseCol8(color, from + 4) < 0)
766                 return false;
767 
768             return true;
769         }
770 
771         /// <summary>
772         /// Returns a color constructed from integer red, green, blue, and alpha channels.
773         /// Each channel should have 8 bits of information ranging from 0 to 255.
774         /// </summary>
775         /// <param name="r8">The red component represented on the range of 0 to 255.</param>
776         /// <param name="g8">The green component represented on the range of 0 to 255.</param>
777         /// <param name="b8">The blue component represented on the range of 0 to 255.</param>
778         /// <param name="a8">The alpha (transparency) component represented on the range of 0 to 255.</param>
779         /// <returns>The constructed color.</returns>
Color8Godot.Color780         public static Color Color8(byte r8, byte g8, byte b8, byte a8 = 255)
781         {
782             return new Color(r8 / 255f, g8 / 255f, b8 / 255f, a8 / 255f);
783         }
784 
785         /// <summary>
786         /// Constructs a color from the HTML hexadecimal color string in RGBA format.
787         /// </summary>
788         /// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param>
ColorGodot.Color789         public Color(string rgba)
790         {
791             if (rgba.Length == 0)
792             {
793                 r = 0f;
794                 g = 0f;
795                 b = 0f;
796                 a = 1.0f;
797                 return;
798             }
799 
800             if (rgba[0] == '#')
801                 rgba = rgba.Substring(1);
802 
803             bool alpha;
804 
805             if (rgba.Length == 8)
806             {
807                 alpha = true;
808             }
809             else if (rgba.Length == 6)
810             {
811                 alpha = false;
812             }
813             else
814             {
815                 throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
816             }
817 
818             if (alpha)
819             {
820                 a = ParseCol8(rgba, 0) / 255f;
821 
822                 if (a < 0)
823                     throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
824             }
825             else
826             {
827                 a = 1.0f;
828             }
829 
830             int from = alpha ? 2 : 0;
831 
832             r = ParseCol8(rgba, from + 0) / 255f;
833 
834             if (r < 0)
835                 throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
836 
837             g = ParseCol8(rgba, from + 2) / 255f;
838 
839             if (g < 0)
840                 throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
841 
842             b = ParseCol8(rgba, from + 4) / 255f;
843 
844             if (b < 0)
845                 throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
846         }
847 
operator +Godot.Color848         public static Color operator +(Color left, Color right)
849         {
850             left.r += right.r;
851             left.g += right.g;
852             left.b += right.b;
853             left.a += right.a;
854             return left;
855         }
856 
operator -Godot.Color857         public static Color operator -(Color left, Color right)
858         {
859             left.r -= right.r;
860             left.g -= right.g;
861             left.b -= right.b;
862             left.a -= right.a;
863             return left;
864         }
865 
operator -Godot.Color866         public static Color operator -(Color color)
867         {
868             return Colors.White - color;
869         }
870 
operator *Godot.Color871         public static Color operator *(Color color, float scale)
872         {
873             color.r *= scale;
874             color.g *= scale;
875             color.b *= scale;
876             color.a *= scale;
877             return color;
878         }
879 
operator *Godot.Color880         public static Color operator *(float scale, Color color)
881         {
882             color.r *= scale;
883             color.g *= scale;
884             color.b *= scale;
885             color.a *= scale;
886             return color;
887         }
888 
operator *Godot.Color889         public static Color operator *(Color left, Color right)
890         {
891             left.r *= right.r;
892             left.g *= right.g;
893             left.b *= right.b;
894             left.a *= right.a;
895             return left;
896         }
897 
operator /Godot.Color898         public static Color operator /(Color color, float scale)
899         {
900             color.r /= scale;
901             color.g /= scale;
902             color.b /= scale;
903             color.a /= scale;
904             return color;
905         }
906 
operator /Godot.Color907         public static Color operator /(Color left, Color right)
908         {
909             left.r /= right.r;
910             left.g /= right.g;
911             left.b /= right.b;
912             left.a /= right.a;
913             return left;
914         }
915 
operator ==Godot.Color916         public static bool operator ==(Color left, Color right)
917         {
918             return left.Equals(right);
919         }
920 
operator !=Godot.Color921         public static bool operator !=(Color left, Color right)
922         {
923             return !left.Equals(right);
924         }
925 
operator <Godot.Color926         public static bool operator <(Color left, Color right)
927         {
928             if (Mathf.IsEqualApprox(left.r, right.r))
929             {
930                 if (Mathf.IsEqualApprox(left.g, right.g))
931                 {
932                     if (Mathf.IsEqualApprox(left.b, right.b))
933                     {
934                         return left.a < right.a;
935                     }
936                     return left.b < right.b;
937                 }
938                 return left.g < right.g;
939             }
940             return left.r < right.r;
941         }
942 
operator >Godot.Color943         public static bool operator >(Color left, Color right)
944         {
945             if (Mathf.IsEqualApprox(left.r, right.r))
946             {
947                 if (Mathf.IsEqualApprox(left.g, right.g))
948                 {
949                     if (Mathf.IsEqualApprox(left.b, right.b))
950                     {
951                         return left.a > right.a;
952                     }
953                     return left.b > right.b;
954                 }
955                 return left.g > right.g;
956             }
957             return left.r > right.r;
958         }
959 
EqualsGodot.Color960         public override bool Equals(object obj)
961         {
962             if (obj is Color)
963             {
964                 return Equals((Color)obj);
965             }
966 
967             return false;
968         }
969 
EqualsGodot.Color970         public bool Equals(Color other)
971         {
972             return r == other.r && g == other.g && b == other.b && a == other.a;
973         }
974 
975         /// <summary>
976         /// Returns true if this color and `other` are approximately equal, by running
977         /// <see cref="Godot.Mathf.IsEqualApprox(float, float)"/> on each component.
978         /// </summary>
979         /// <param name="other">The other color to compare.</param>
980         /// <returns>Whether or not the colors are approximately equal.</returns>
IsEqualApproxGodot.Color981         public bool IsEqualApprox(Color other)
982         {
983             return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
984         }
985 
GetHashCodeGodot.Color986         public override int GetHashCode()
987         {
988             return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode();
989         }
990 
ToStringGodot.Color991         public override string ToString()
992         {
993             return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString());
994         }
995 
ToStringGodot.Color996         public string ToString(string format)
997         {
998             return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format));
999         }
1000     }
1001 }
1002