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