1 module skia.SKMatrix; 2 3 import skia.Definitions; 4 import skia.Exceptions; 5 import skia.MathTypes; 6 import skia.SkiaApi; 7 // import skia.SKPoint; 8 9 import std.math; 10 11 struct SKMatrix 12 { 13 enum float DegreesToRadians = cast(float)PI / 180.0f; 14 15 enum SKMatrix Empty = SKMatrix(); 16 17 // float scaleX 18 private float scaleX; 19 float ScaleX() { 20 return scaleX; 21 } 22 23 void ScaleX(float value) { 24 scaleX = value; 25 } 26 27 // float skewX 28 private float skewX; 29 float SkewX() { 30 return skewX; 31 } 32 33 void SkewX(float value) { 34 skewX = value; 35 } 36 37 // float transX 38 private float transX; 39 float TransX() { 40 return transX; 41 } 42 43 void TransX(float value) { 44 transX = value; 45 } 46 47 // float skewY 48 private float skewY; 49 float SkewY() { 50 return skewY; 51 } 52 53 void SkewY(float value) { 54 skewY = value; 55 } 56 57 // float scaleY 58 private float scaleY; 59 float ScaleY() { 60 return scaleY; 61 } 62 63 void ScaleY(float value) { 64 scaleY = value; 65 } 66 67 // float transY 68 private float transY; 69 float TransY() { 70 return transY; 71 } 72 73 void TransY(float value) { 74 transY = value; 75 } 76 77 // float persp0 78 private float persp0; 79 float Persp0() { 80 return persp0; 81 } 82 83 void Persp0(float value) { 84 persp0 = value; 85 } 86 87 // float persp1 88 private float persp1; 89 float Persp1() { 90 return persp1; 91 } 92 93 void Persp1(float value) { 94 persp1 = value; 95 } 96 97 // float persp2 98 private float persp2; 99 float Persp2() { 100 return persp2; 101 } 102 103 void Persp2(float value) { 104 persp2 = value; 105 } 106 107 // const bool Equals (SKMatrix obj) { 108 // return scaleX == obj.scaleX && skewX == obj.skewX && transX == obj.transX && skewY == obj.skewY && scaleY == obj.scaleY && transY == obj.transY && persp0 == obj.persp0 && persp1 == obj.persp1 && persp2 == obj.persp2 109 // } 110 111 // const override bool Equals (object obj) { 112 // return obj is SKMatrix f && Equals (f) 113 // } 114 115 // static bool operator == (SKMatrix left, SKMatrix right) { 116 // return left.Equals (right) 117 // } 118 119 // static bool operator != (SKMatrix left, SKMatrix right) { 120 // return !left.Equals (right) 121 // } 122 123 // const override int GetHashCode () 124 // { 125 // var hash = new HashCode (); 126 // hash.Add (scaleX); 127 // hash.Add (skewX); 128 // hash.Add (transX); 129 // hash.Add (skewY); 130 // hash.Add (scaleY); 131 // hash.Add (transY); 132 // hash.Add (persp0); 133 // hash.Add (persp1); 134 // hash.Add (persp2); 135 // return hash.ToHashCode (); 136 // } 137 138 static SKMatrix Identity() 139 { 140 SKMatrix matrix; 141 matrix.scaleX = 1; 142 matrix.scaleY = 1; 143 matrix.persp2 = 1; 144 return matrix; 145 } 146 147 private static struct Indices 148 { 149 enum ScaleX = 0; 150 enum SkewX = 1; 151 enum TransX = 2; 152 enum SkewY = 3; 153 enum ScaleY = 4; 154 enum TransY = 5; 155 enum Persp0 = 6; 156 enum Persp1 = 7; 157 enum Persp2 = 8; 158 159 enum Count = 9; 160 } 161 162 this (float[] values) 163 { 164 if (values is null) 165 throw new ArgumentNullException (values.stringof); 166 if (values.length != Indices.Count) 167 throw new ArgumentException ("The matrix array must have a length of {Indices.Count}.", values.stringof); 168 169 scaleX = values[Indices.ScaleX]; 170 skewX = values[Indices.SkewX]; 171 transX = values[Indices.TransX]; 172 173 skewY = values[Indices.SkewY]; 174 scaleY = values[Indices.ScaleY]; 175 transY = values[Indices.TransY]; 176 177 persp0 = values[Indices.Persp0]; 178 persp1 = values[Indices.Persp1]; 179 persp2 = values[Indices.Persp2]; 180 } 181 182 this ( 183 float scaleX, float skewX, float transX, 184 float skewY, float scaleY, float transY, 185 float persp0, float persp1, float persp2) 186 { 187 this.scaleX = scaleX; 188 this.skewX = skewX; 189 this.transX = transX; 190 this.skewY = skewY; 191 this.scaleY = scaleY; 192 this.transY = transY; 193 this.persp0 = persp0; 194 this.persp1 = persp1; 195 this.persp2 = persp2; 196 } 197 198 const bool IsIdentity() 199 { 200 return this == (Identity); 201 } 202 203 // Values 204 205 float[] Values() { 206 return 207 [ 208 scaleX, skewX, transX, 209 skewY, scaleY, transY, 210 persp0, persp1, persp2 211 ]; 212 213 } 214 void Values(float[] value) { 215 216 if (value is null) 217 throw new ArgumentNullException (Values.stringof); 218 if (value.length != Indices.Count) 219 throw new ArgumentException ("The matrix array must have a length of {Indices.Count}.", Values.stringof); 220 221 scaleX = value[Indices.ScaleX]; 222 skewX = value[Indices.SkewX]; 223 transX = value[Indices.TransX]; 224 225 skewY = value[Indices.SkewY]; 226 scaleY = value[Indices.ScaleY]; 227 transY = value[Indices.TransY]; 228 229 persp0 = value[Indices.Persp0]; 230 persp1 = value[Indices.Persp1]; 231 persp2 = value[Indices.Persp2]; 232 233 } 234 235 const void GetValues (float[] values) 236 { 237 if (values is null) 238 throw new ArgumentNullException (values.stringof); 239 if (values.length != Indices.Count) 240 throw new ArgumentException ("The matrix array must have a length of {Indices.Count}.", values.stringof); 241 242 values[Indices.ScaleX] = scaleX; 243 values[Indices.SkewX] = skewX; 244 values[Indices.TransX] = transX; 245 246 values[Indices.SkewY] = skewY; 247 values[Indices.ScaleY] = scaleY; 248 values[Indices.TransY] = transY; 249 250 values[Indices.Persp0] = persp0; 251 values[Indices.Persp1] = persp1; 252 values[Indices.Persp2] = persp2; 253 } 254 255 // Create* 256 257 static SKMatrix CreateIdentity () 258 { 259 SKMatrix matrix = SKMatrix(); 260 matrix.scaleX = 1; 261 matrix.scaleY = 1; 262 matrix.persp2 = 1; 263 264 return matrix; 265 } 266 267 static SKMatrix CreateTranslation (float x, float y) 268 { 269 if (x == 0 && y == 0) 270 return Identity; 271 272 SKMatrix matrix = SKMatrix(); 273 matrix.scaleX = 1; 274 matrix.scaleY = 1; 275 matrix.transX = x; 276 matrix.transY = y; 277 matrix.persp2 = 1; 278 return matrix; 279 } 280 281 static SKMatrix CreateScale (float x, float y) 282 { 283 if (x == 1 && y == 1) 284 return Identity; 285 286 SKMatrix matrix = SKMatrix(); 287 matrix.scaleX = x; 288 matrix.scaleY = y; 289 matrix.persp2 = 1; 290 return matrix; 291 } 292 293 static SKMatrix CreateScale (float x, float y, float pivotX, float pivotY) 294 { 295 if (x == 1 && y == 1) 296 return Identity; 297 298 auto tx = pivotX - x * pivotX; 299 auto ty = pivotY - y * pivotY; 300 301 SKMatrix matrix = SKMatrix(); 302 matrix.scaleX = x; 303 matrix.scaleY = y; 304 matrix.transX = tx; 305 matrix.transY = ty; 306 matrix.persp2 = 1; 307 return matrix; 308 } 309 310 static SKMatrix CreateRotation (float radians) 311 { 312 if (radians == 0) 313 return Identity; 314 315 auto sin = cast(float)sin (radians); 316 auto cos = cast(float)cos (radians); 317 318 auto matrix = Identity; 319 SetSinCos ( matrix, sin, cos); 320 return matrix; 321 } 322 323 static SKMatrix CreateRotation (float radians, float pivotX, float pivotY) 324 { 325 if (radians == 0) 326 return Identity; 327 328 auto sin = cast(float)sin (radians); 329 auto cos = cast(float)cos (radians); 330 331 auto matrix = Identity; 332 SetSinCos (matrix, sin, cos, pivotX, pivotY); 333 return matrix; 334 } 335 336 static SKMatrix CreateRotationDegrees (float degrees) 337 { 338 if (degrees == 0) 339 return Identity; 340 341 return CreateRotation (degrees * DegreesToRadians); 342 } 343 344 static SKMatrix CreateRotationDegrees (float degrees, float pivotX, float pivotY) 345 { 346 if (degrees == 0) 347 return Identity; 348 349 return CreateRotation (degrees * DegreesToRadians, pivotX, pivotY); 350 } 351 352 static SKMatrix CreateSkew (float x, float y) 353 { 354 if (x == 0 && y == 0) 355 return Identity; 356 357 SKMatrix matrix = SKMatrix(); 358 359 matrix.scaleX = 1; 360 matrix.skewX = x; 361 matrix.skewY = y; 362 matrix.scaleY = 1; 363 matrix.persp2 = 1; 364 365 return matrix; 366 } 367 368 static SKMatrix CreateScaleTranslation (float sx, float sy, float tx, float ty) 369 { 370 if (sx == 0 && sy == 0 && tx == 0 && ty == 0) 371 return Identity; 372 373 SKMatrix matrix = SKMatrix(); 374 375 matrix.scaleX = sx; 376 matrix.skewX = 0; 377 matrix.transX = tx; 378 379 matrix.skewY = 0; 380 matrix.scaleY = sy; 381 matrix.transY = ty; 382 383 matrix.persp0 = 0; 384 matrix.persp1 = 0; 385 matrix.persp2 = 1; 386 387 return matrix; 388 } 389 390 // Make* 391 392 static SKMatrix MakeIdentity () 393 { 394 return CreateIdentity (); 395 } 396 397 static SKMatrix MakeScale (float sx, float sy) 398 { 399 return CreateScale (sx, sy); 400 } 401 402 static SKMatrix MakeScale (float sx, float sy, float pivotX, float pivotY) 403 { 404 return CreateScale (sx, sy, pivotX, pivotY); 405 } 406 407 static SKMatrix MakeTranslation (float dx, float dy) 408 { 409 return CreateTranslation (dx, dy); 410 } 411 412 static SKMatrix MakeRotation (float radians) 413 { 414 return CreateRotation (radians); 415 } 416 417 static SKMatrix MakeRotation (float radians, float pivotx, float pivoty) 418 { 419 return CreateRotation (radians, pivotx, pivoty); 420 } 421 422 static SKMatrix MakeRotationDegrees (float degrees) 423 { 424 return CreateRotationDegrees (degrees); 425 } 426 427 static SKMatrix MakeRotationDegrees (float degrees, float pivotx, float pivoty) 428 { 429 return CreateRotationDegrees (degrees, pivotx, pivoty); 430 } 431 432 static SKMatrix MakeSkew (float sx, float sy) 433 { 434 return CreateSkew (sx, sy); 435 } 436 437 // Set* 438 439 void SetScaleTranslate (float sx, float sy, float tx, float ty) 440 { 441 scaleX = sx; 442 skewX = 0; 443 transX = tx; 444 445 skewY = 0; 446 scaleY = sy; 447 transY = ty; 448 449 persp0 = 0; 450 persp1 = 0; 451 persp2 = 1; 452 } 453 454 // Rotate 455 456 static void Rotate (ref SKMatrix matrix, float radians, float pivotx, float pivoty) 457 { 458 auto sin = cast(float)sin (radians); 459 auto cos = cast(float)cos (radians); 460 SetSinCos ( matrix, sin, cos, pivotx, pivoty); 461 } 462 463 static void RotateDegrees (ref SKMatrix matrix, float degrees, float pivotx, float pivoty) 464 { 465 auto sin = cast(float)sin (degrees * DegreesToRadians); 466 auto cos = cast(float)cos (degrees * DegreesToRadians); 467 SetSinCos ( matrix, sin, cos, pivotx, pivoty); 468 } 469 470 static void Rotate (ref SKMatrix matrix, float radians) 471 { 472 auto sin = cast(float)sin (radians); 473 auto cos = cast(float)cos (radians); 474 SetSinCos ( matrix, sin, cos); 475 } 476 477 static void RotateDegrees (ref SKMatrix matrix, float degrees) 478 { 479 auto sin = cast(float)sin (degrees * DegreesToRadians); 480 auto cos = cast(float)cos (degrees * DegreesToRadians); 481 SetSinCos ( matrix, sin, cos); 482 } 483 484 // Invert 485 486 const bool IsInvertible() { 487 488 SKMatrix* t = cast(SKMatrix*)&this; 489 return SkiaApi.sk_matrix_try_invert (t, null); 490 } 491 492 const bool TryInvert (out SKMatrix inverse) 493 { 494 SKMatrix* i = &inverse; 495 SKMatrix* t = cast(SKMatrix*)&this; 496 return SkiaApi.sk_matrix_try_invert (t, i); 497 } 498 499 SKMatrix Invert () 500 { 501 SKMatrix matrix; 502 if (TryInvert ( matrix)) 503 return matrix; 504 505 return Empty; 506 } 507 508 // *Concat 509 510 static SKMatrix Concat (SKMatrix first, SKMatrix second) 511 { 512 SKMatrix target; 513 SkiaApi.sk_matrix_concat (&target, &first, &second); 514 return target; 515 } 516 517 SKMatrix PreConcat (SKMatrix matrix) 518 { 519 auto target = this; 520 SkiaApi.sk_matrix_pre_concat (&target, &matrix); 521 return target; 522 } 523 524 SKMatrix PostConcat (SKMatrix matrix) 525 { 526 auto target = this; 527 SkiaApi.sk_matrix_post_concat (&target, &matrix); 528 return target; 529 } 530 531 static void Concat (ref SKMatrix target, SKMatrix first, SKMatrix second) 532 { 533 SKMatrix* t = ⌖ 534 SkiaApi.sk_matrix_concat (t, &first, &second); 535 } 536 537 static void Concat (ref SKMatrix target, ref SKMatrix first, ref SKMatrix second) 538 { 539 SKMatrix* t = ⌖ 540 SKMatrix* f = &first; 541 SKMatrix* s = &second; 542 SkiaApi.sk_matrix_concat (t, f, s); 543 } 544 545 static void PreConcat (ref SKMatrix target, SKMatrix matrix) 546 { 547 SKMatrix* t = ⌖ 548 SkiaApi.sk_matrix_pre_concat (t, &matrix); 549 } 550 551 static void PreConcat (ref SKMatrix target, ref SKMatrix matrix) 552 { 553 SKMatrix* t = ⌖ 554 SKMatrix* m = &matrix; 555 SkiaApi.sk_matrix_pre_concat (t, m); 556 } 557 558 static void PostConcat (ref SKMatrix target, SKMatrix matrix) 559 { 560 SKMatrix* t = ⌖ 561 SkiaApi.sk_matrix_post_concat (t, &matrix); 562 } 563 564 static void PostConcat (ref SKMatrix target, ref SKMatrix matrix) 565 { 566 SKMatrix* t = ⌖ 567 SKMatrix* m = &matrix; 568 SkiaApi.sk_matrix_post_concat (t, m); 569 } 570 571 // MapRect 572 573 const SKRect MapRect (SKRect source) 574 { 575 SKRect dest; 576 SKMatrix* m = cast(SKMatrix*)&this; 577 SkiaApi.sk_matrix_map_rect (m, &dest, &source); 578 return dest; 579 } 580 581 static void MapRect (ref SKMatrix matrix, out SKRect dest, ref SKRect source) 582 { 583 SKMatrix* m = &matrix; 584 SKRect* d = &dest; 585 SKRect* s = &source; 586 SkiaApi.sk_matrix_map_rect (m, d, s); 587 } 588 589 // MapPoints 590 591 const SKPoint MapPoint (SKPoint point) 592 { 593 return MapPoint (point.X, point.Y); 594 } 595 596 597 const SKPoint MapPoint (float x, float y) 598 { 599 SKPoint result; 600 SKMatrix* t = cast(SKMatrix*)&this; 601 SkiaApi.sk_matrix_map_xy (t, x, y, &result); 602 return result; 603 } 604 605 const void MapPoints (SKPoint[] result, SKPoint[] points) 606 { 607 if (result is null) 608 throw new ArgumentNullException (result.stringof); 609 if (points is null) 610 throw new ArgumentNullException (points.stringof); 611 if (result.length != points.length) 612 throw new ArgumentException ("Buffers must be the same size."); 613 614 SKMatrix* t = cast(SKMatrix*)&this; 615 SKPoint* rp = result.ptr; 616 SKPoint* pp = points.ptr; 617 SkiaApi.sk_matrix_map_points (t, rp, pp, cast(int)result.length); 618 } 619 620 const SKPoint[] MapPoints (SKPoint[] points) 621 { 622 if (points is null) 623 throw new ArgumentNullException (points.stringof); 624 625 auto res = new SKPoint[points.length]; 626 MapPoints (res, points); 627 return res; 628 } 629 630 // MapVectors 631 632 const SKPoint MapVector (SKPoint vector) 633 { 634 return MapVector (vector.X, vector.Y); 635 } 636 637 638 const SKPoint MapVector (float x, float y) 639 { 640 SKPoint result; 641 SKMatrix* t = cast(SKMatrix*)&this; 642 SkiaApi.sk_matrix_map_vector (t, x, y, &result); 643 return result; 644 } 645 646 const void MapVectors (SKPoint[] result, SKPoint[] vectors) 647 { 648 if (result is null) 649 throw new ArgumentNullException (result.stringof); 650 if (vectors is null) 651 throw new ArgumentNullException (vectors.stringof); 652 if (result.length != vectors.length) 653 throw new ArgumentException ("Buffers must be the same size."); 654 655 SKMatrix* t = cast(SKMatrix*)&this; 656 SKPoint* rp = result.ptr; 657 SKPoint* pp = vectors.ptr; 658 SkiaApi.sk_matrix_map_vectors (t, rp, pp, cast(int)result.length); 659 } 660 661 const SKPoint[] MapVectors (SKPoint[] vectors) 662 { 663 if (vectors is null) 664 throw new ArgumentNullException (vectors.stringof); 665 666 auto res = new SKPoint[vectors.length]; 667 MapVectors (res, vectors); 668 return res; 669 } 670 671 // MapRadius 672 673 const float MapRadius (float radius) 674 { 675 SKMatrix* t = cast(SKMatrix*)&this; 676 return SkiaApi.sk_matrix_map_radius (t, radius); 677 } 678 679 // private 680 681 private static void SetSinCos (ref SKMatrix matrix, float sin, float cos) 682 { 683 matrix.scaleX = cos; 684 matrix.skewX = -sin; 685 matrix.transX = 0; 686 matrix.skewY = sin; 687 matrix.scaleY = cos; 688 matrix.transY = 0; 689 matrix.persp0 = 0; 690 matrix.persp1 = 0; 691 matrix.persp2 = 1; 692 } 693 694 private static void SetSinCos (ref SKMatrix matrix, float sin, float cos, float pivotx, float pivoty) 695 { 696 float oneMinusCos = 1 - cos; 697 698 matrix.scaleX = cos; 699 matrix.skewX = -sin; 700 matrix.transX = Dot (sin, pivoty, oneMinusCos, pivotx); 701 matrix.skewY = sin; 702 matrix.scaleY = cos; 703 matrix.transY = Dot (-sin, pivotx, oneMinusCos, pivoty); 704 matrix.persp0 = 0; 705 matrix.persp1 = 0; 706 matrix.persp2 = 1; 707 } 708 709 private static float Dot (float a, float b, float c, float d) 710 { 711 return a * b + c * d; 712 } 713 714 715 private static float Cross (float a, float b, float c, float d) 716 { 717 return a * b - c * d; 718 } 719 720 }