1 /++ 2 + Authors: Avaxar <avaxar@nekkl.org> 3 + Copyright: Copyright © 2023, Avaxar 4 + License: $(LINK2 https://mit-license.org, MIT License) 5 +/ 6 7 module dsdl2.pixels; 8 @safe: 9 10 import bindbc.sdl; 11 import dsdl2.sdl; 12 13 import core.memory : GC; 14 import std.conv : to; 15 import std.format : format; 16 17 /++ 18 + D struct that wraps `SDL_Color` containing 4 bytes for storing color values of 3 color channels and 1 alpha 19 + channel. 20 + 21 + `dsdl2.Color` stores unsigned `byte`-sized (0-255) `r`ed, `g`reen, `b`lue color, and `a`lpha channel values. 22 + In total there are 16,777,216 possible color values. Combined with the `a`lpha (transparency) channel, there 23 + are 4,294,967,296 combinations. 24 + 25 + Examples 26 + --- 27 + auto red = dsdl2.Color(255, 0, 0); 28 + auto translucentRed = dsdl2.Color(255, 0, 0, 128); 29 + --- 30 +/ 31 struct Color { 32 SDL_Color sdlColor; /// Internal `SDL_Color` struct 33 34 this() @disable; 35 36 /++ 37 + Constructs a `dsdl2.Color` from a vanilla `SDL_Color` from bindbc-sdl 38 + 39 + Params: 40 + sdlColor = the `SDL_Color` struct 41 +/ 42 this(SDL_Color sdlColor) { 43 this.sdlColor = sdlColor; 44 } 45 46 /++ 47 + Constructs a `dsdl2.Color` by feeding in `r`ed, `g`reen, `b`lue, and optionally `a`lpha values 48 + 49 + Params: 50 + r = red color channel value (0-255) 51 + g = green color channel value (0-255) 52 + b = blue color channel value (0-255) 53 + a = alpha transparency channel value (0-255 / transparent-opaque) 54 +/ 55 this(ubyte r, ubyte g, ubyte b, ubyte a = 255) { 56 this.sdlColor.r = r; 57 this.sdlColor.g = g; 58 this.sdlColor.b = b; 59 this.sdlColor.a = a; 60 } 61 62 /++ 63 + Constructs a `dsdl2.Color` by feeding in an array of `r`ed, `g`reen, and `b`lue, with `a`lpha being `255` 64 + 65 + Params: 66 + rgb = array of `r`ed, `g`reen, `b`lue values 67 +/ 68 this(ubyte[3] rgb) { 69 this.sdlColor.r = rgb[0]; 70 this.sdlColor.g = rgb[1]; 71 this.sdlColor.b = rgb[2]; 72 this.sdlColor.a = 255; 73 } 74 75 /++ 76 + Constructs a `dsdl2.Color` by feeding in an array of `r`ed, `g`reen, `b`lue, and `a`lpha 77 + 78 + Params: 79 + rgba = array of `r`ed, `g`reen, `b`lue, `a`lpha values 80 +/ 81 this(ubyte[4] rgba) { 82 this.sdlColor.r = rgba[0]; 83 this.sdlColor.g = rgba[1]; 84 this.sdlColor.b = rgba[2]; 85 this.sdlColor.a = rgba[3]; 86 } 87 88 /++ 89 + Formats the `dsdl2.Color` into its construction representation: `"dsdl2.Color(<r>, <g>, <b>, <a>)"` 90 + 91 + Returns: the formatted `string` 92 +/ 93 string toString() const { 94 return "dsdl2.Color(%d, %d, %d, %d)".format(this.r, this.g, this.b, this.a); 95 } 96 97 /++ 98 + Proxy to the red color value of the `dsdl2.Color` 99 + 100 + Returns: red color value of the `dsdl2.Color` 101 +/ 102 ref inout(ubyte) r() return inout @property { 103 return this.sdlColor.r; 104 } 105 106 /++ 107 + Proxy to the green color value of the `dsdl2.Color` 108 + 109 + Returns: green color value of the `dsdl2.Color` 110 +/ 111 ref inout(ubyte) g() return inout @property { 112 return this.sdlColor.g; 113 } 114 115 /++ 116 + Proxy to the blue color value of the `dsdl2.Color` 117 + 118 + Returns: blue color value of the `dsdl2.Color` 119 +/ 120 ref inout(ubyte) b() return inout @property { 121 return this.sdlColor.b; 122 } 123 124 /++ 125 + Proxy to the alpha transparency value of the `dsdl2.Color` 126 + 127 + Returns: alpha transparency value of the `dsdl2.Color` 128 +/ 129 ref inout(ubyte) a() return inout @property { 130 return this.sdlColor.a; 131 } 132 133 /++ 134 + Static array proxy of the `dsdl2.Color` 135 + 136 + Returns: array of `r`, `g`, `b`, `a` 137 +/ 138 ref inout(ubyte[4]) array() return inout @property @trusted { 139 return *cast(inout(ubyte[4]*))&this.sdlColor; 140 } 141 } 142 143 /++ 144 + D class that wraps `SDL_Palette` storing multiple `dsdl2.Color` as a palette to use along with indexed 145 + `dsdl2.PixelFormat` instances 146 +/ 147 final class Palette { 148 private bool isOwner = true; 149 private void* userRef = null; 150 151 @system SDL_Palette* sdlPalette = null; /// Internal `SDL_Palette` pointer 152 153 /++ 154 + Constructs a `dsdl2.Palette` from a vanilla `SDL_Palette*` from bindbc-sdl 155 + 156 + Params: 157 + sdlPalette = the `SDL_Palette` pointer to manage 158 + isOwner = whether the instance owns the given `SDL_Palette*` and should destroy it on its own 159 + userRef = optional pointer to maintain reference link, avoiding GC cleanup 160 +/ 161 this(SDL_Palette* sdlPalette, bool isOwner = true, void* userRef = null) @system 162 in { 163 assert(sdlPalette !is null); 164 } 165 do { 166 this.sdlPalette = sdlPalette; 167 this.isOwner = isOwner; 168 this.userRef = userRef; 169 } 170 171 /++ 172 + Constructs a `dsdl2.Palette` and allocate memory for a set amount of `dsdl2.Color`s 173 + 174 + Params: 175 + ncolors = amount of `dsdl2.Color`s to allocate in the `dsdl2.Palette` 176 + Throws: `dsdl2.SDLException` if allocation failed 177 +/ 178 this(uint ncolors) @trusted { 179 this.sdlPalette = SDL_AllocPalette(ncolors.to!int); 180 if (this.sdlPalette is null) { 181 throw new SDLException; 182 } 183 } 184 185 /++ 186 + Constructs a `dsdl2.Palette` from an array of `dsdl2.Color`s 187 + 188 + Params: 189 + colors = an array/slice of `dsdl2.Color`s to put in the `dsdl2.Palette` 190 + Throws: `dsdl2.SDLException` if allocation failed 191 +/ 192 this(const Color[] colors) @trusted { 193 this.sdlPalette = SDL_AllocPalette(colors.length.to!int); 194 if (this.sdlPalette is null) { 195 throw new SDLException; 196 } 197 198 foreach (i, const ref color; colors) { 199 this.sdlPalette.colors[i] = color.sdlColor; 200 } 201 } 202 203 ~this() @trusted { 204 if (this.isOwner) { 205 SDL_FreePalette(this.sdlPalette); 206 } 207 } 208 209 @trusted invariant { // @suppress(dscanner.trust_too_much) 210 // Instance might be in an invalid state due to holding a non-owned externally-freed object when 211 // destructed in an unpredictable order. 212 if (!this.isOwner && GC.inFinalizer) { 213 return; 214 } 215 216 assert(this.sdlPalette !is null); 217 } 218 219 /++ 220 + Equality operator overload 221 +/ 222 bool opEquals(const Palette rhs) const @trusted { 223 if (rhs is null) { 224 return false; 225 } 226 227 if (this.sdlPalette is rhs.sdlPalette) { 228 return true; 229 } 230 231 if (this.length != rhs.length) { 232 return false; 233 } 234 235 foreach (i; 0 .. this.length) { 236 if (this[i] != rhs[i]) { 237 return false; 238 } 239 } 240 241 return true; 242 } 243 244 /++ 245 + Gets the hash of the `dsdl2.Palette` 246 + 247 + Returns: unique hash for the `dsdl2.Palette` 248 +/ 249 override hash_t toHash() const @trusted { 250 try { 251 return this.colors.hashOf; 252 } 253 catch (Exception) { 254 assert(false); 255 } 256 } 257 258 /++ 259 + Indexing operation overload 260 +/ 261 ref inout(Color) opIndex(size_t i) return inout @trusted 262 in { 263 assert(0 <= i && i < this.length); 264 } 265 do { 266 return *cast(inout(Color*))&this.sdlPalette.colors[i]; 267 } 268 269 /++ 270 + Dollar sign overload 271 +/ 272 size_t opDollar(size_t dim)() const if (dim == 0) { 273 return this.length; 274 } 275 276 /++ 277 + Formats the `dsdl2.Palette` into its construction representation: `"dsdl2.Palette([<list of dsdl2.Color>])"` 278 + 279 + Returns: the formatted `string` 280 +/ 281 override string toString() const { 282 string str = "dsdl2.Palette(["; 283 284 foreach (i; 0 .. this.length) { 285 str ~= this[i].toString(); 286 287 if (i + 1 < this.length) { 288 str ~= ", "; 289 } 290 } 291 292 return str ~= "])"; 293 } 294 295 /++ 296 + Gets the length of `dsdl2.Color`s allocated in the `dsdl2.Palette` 297 + 298 + Returns: number of `dsdl2.Color`s 299 +/ 300 size_t length() const @property @trusted { 301 return this.sdlPalette.ncolors; 302 } 303 304 /++ 305 + Proxy to the `dsdl2.Color` array of the `dsdl2.Palette` 306 + 307 + This function is marked as `@system` due to the potential of referencing invalid memory. 308 + 309 + Returns: `dsdl2.Color` array of the `dsdl2.Palette` 310 +/ 311 inout(Color[]) colors() inout @property @system { 312 return (cast(inout(Color*))&this.sdlPalette.colors)[0 .. this.length]; 313 } 314 } 315 /// 316 unittest { 317 auto myPalette = new dsdl2.Palette([dsdl2.Color(1, 2, 3), dsdl2.Color(3, 2, 1)]); 318 assert(myPalette.length == 2); 319 assert(myPalette[0] == dsdl2.Color(1, 2, 3)); 320 } 321 322 /++ 323 + D class that wraps `SDL_PixelFormat` defining the color and alpha channel bit layout in the internal 324 + representation of a pixel 325 +/ 326 final class PixelFormat { 327 static PixelFormat _multiton(SDL_PixelFormatEnum sdlPixelFormatEnum, ubyte minMinorVer = 0, 328 ubyte minPatchVer = 0)() 329 in { 330 assert(getVersion() >= Version(2, minMinorVer, minPatchVer)); 331 } 332 do { 333 static PixelFormat pixelFormat = null; 334 if (pixelFormat is null) { 335 pixelFormat = new PixelFormat(sdlPixelFormatEnum); 336 } 337 338 return pixelFormat; 339 } 340 341 static PixelFormat _instantiateIndexed(SDL_PixelFormatEnum sdlPixelFormatEnum, ubyte minMinorVer = 0, 342 ubyte minPatchVer = 0)(Palette palette) 343 in { 344 assert(getVersion() >= Version(2, minMinorVer, minPatchVer)); 345 assert(palette !is null); 346 } 347 do { 348 return new PixelFormat(sdlPixelFormatEnum, palette); 349 } 350 351 /++ 352 + Instantiates indexed `dsdl2.PixelFormat` for use with `dsdl2.Palette`s from `SDL_PIXELFORMAT_*` enumeration 353 + constants 354 +/ 355 static alias index1lsb = _instantiateIndexed!SDL_PIXELFORMAT_INDEX1LSB; 356 static alias index1msb = _instantiateIndexed!SDL_PIXELFORMAT_INDEX1MSB; /// ditto 357 static alias index4lsb = _instantiateIndexed!SDL_PIXELFORMAT_INDEX4LSB; /// ditto 358 static alias index4msb = _instantiateIndexed!SDL_PIXELFORMAT_INDEX4MSB; /// ditto 359 static alias index8 = _instantiateIndexed!SDL_PIXELFORMAT_INDEX8; /// ditto 360 static alias yv12 = _instantiateIndexed!SDL_PIXELFORMAT_YV12; /// ditto 361 static alias yuy2 = _instantiateIndexed!SDL_PIXELFORMAT_YUY2; /// ditto 362 363 /++ 364 + Retrieves one of the `dsdl2.PixelFormat` multiton presets from `SDL_PIXELFORMAT_*` enumeration constants 365 +/ 366 static alias rgb332 = _multiton!SDL_PIXELFORMAT_RGB332; 367 static alias rgb444 = _multiton!SDL_PIXELFORMAT_RGB444; /// ditto 368 static alias rgb555 = _multiton!SDL_PIXELFORMAT_RGB555; /// ditto 369 static alias bgr555 = _multiton!SDL_PIXELFORMAT_BGR555; /// ditto 370 static alias argb4444 = _multiton!SDL_PIXELFORMAT_ARGB4444; /// ditto 371 static alias rgba444 = _multiton!SDL_PIXELFORMAT_RGBA4444; /// ditto 372 static alias abgr4444 = _multiton!SDL_PIXELFORMAT_ABGR4444; /// ditto 373 static alias bgra4444 = _multiton!SDL_PIXELFORMAT_BGRA4444; /// ditto 374 static alias argb1555 = _multiton!SDL_PIXELFORMAT_ARGB1555; /// ditto 375 static alias rgba5551 = _multiton!SDL_PIXELFORMAT_RGBA5551; /// ditto 376 static alias abgr1555 = _multiton!SDL_PIXELFORMAT_ABGR1555; /// ditto 377 static alias bgra5551 = _multiton!SDL_PIXELFORMAT_BGRA5551; /// ditto 378 static alias rgb565 = _multiton!SDL_PIXELFORMAT_RGB565; /// ditto 379 static alias bgr565 = _multiton!SDL_PIXELFORMAT_BGR565; /// ditto 380 static alias rgb24 = _multiton!SDL_PIXELFORMAT_RGB24; /// ditto 381 static alias bgr24 = _multiton!SDL_PIXELFORMAT_BGR24; /// ditto 382 static alias rgb888 = _multiton!SDL_PIXELFORMAT_RGB888; /// ditto 383 static alias rgbx8888 = _multiton!SDL_PIXELFORMAT_RGBX8888; /// ditto 384 static alias bgr888 = _multiton!SDL_PIXELFORMAT_BGR888; /// ditto 385 static alias bgrx8888 = _multiton!SDL_PIXELFORMAT_BGRX8888; /// ditto 386 static alias argb8888 = _multiton!SDL_PIXELFORMAT_ARGB8888; /// ditto 387 static alias rgba8888 = _multiton!SDL_PIXELFORMAT_RGBA8888; /// ditto 388 static alias abgr8888 = _multiton!SDL_PIXELFORMAT_ABGR8888; /// ditto 389 static alias bgra8888 = _multiton!SDL_PIXELFORMAT_BGRA8888; /// ditto 390 static alias argb2101010 = _multiton!SDL_PIXELFORMAT_ARGB2101010; /// ditto 391 392 static alias iyuv = _multiton!SDL_PIXELFORMAT_IYUV; /// ditto 393 static alias uyvy = _multiton!SDL_PIXELFORMAT_UYVY; /// ditto 394 static alias yvyu = _multiton!SDL_PIXELFORMAT_YVYU; /// ditto 395 396 static if (sdlSupport >= SDLSupport.v2_0_4) { 397 /++ 398 + Instantiates indexed `dsdl2.PixelFormat` for use with `dsdl2.Palette`s from `SDL_PIXELFORMAT_*` 399 + enumeration constants (from SDL 2.0.4) 400 +/ 401 static alias nv12 = _instantiateIndexed!(SDL_PIXELFORMAT_NV12, 0, 4); 402 static alias nv21 = _instantiateIndexed!(SDL_PIXELFORMAT_NV21, 0, 4); /// ditto 403 } 404 405 static if (sdlSupport >= SDLSupport.v2_0_5) { 406 /++ 407 + Retrieves one of the `dsdl2.PixelFormat` multiton presets from `SDL_PIXELFORMAT_*` enumeration constants 408 + (from SDL 2.0.5) 409 +/ 410 static alias rgba32 = _multiton!(SDL_PIXELFORMAT_RGBA32, 0, 5); 411 static alias argb32 = _multiton!(SDL_PIXELFORMAT_ARGB32, 0, 5); /// ditto 412 static alias bgra32 = _multiton!(SDL_PIXELFORMAT_BGRA32, 0, 5); /// ditto 413 static alias abgr32 = _multiton!(SDL_PIXELFORMAT_ABGR32, 0, 5); /// ditto 414 } 415 416 private Palette paletteRef = null; 417 private bool isOwner = true; 418 private void* userRef = null; 419 420 @system SDL_PixelFormat* sdlPixelFormat = null; /// Internal `SDL_PixelFormat` pointer 421 422 /++ 423 + Constructs a `dsdl2.PixelFormat` from a vanilla `SDL_PixelFormat*` from bindbc-sdl 424 + 425 + Params: 426 + sdlPixelFormat = the `SDL_PixelFormat` pointer to manage 427 + isOwner = whether the instance owns the given `SDL_PixelFormat*` and should destroy it on its own 428 + userRef = optional pointer to maintain reference link, avoiding GC cleanup 429 +/ 430 this(SDL_PixelFormat* sdlPixelFormat, bool isOwner = true, void* userRef = null) @system 431 in { 432 assert(sdlPixelFormat !is null); 433 } 434 do { 435 this.sdlPixelFormat = sdlPixelFormat; 436 this.isOwner = isOwner; 437 this.userRef = userRef; 438 439 if (this.sdlPixelFormat.palette !is null) { 440 this.paletteRef = new Palette(this.sdlPixelFormat.palette, false, cast(void*) this); 441 } 442 } 443 444 /++ 445 + Constructs a `dsdl2.PixelFormat` using an `SDL_PixelFormatEnum` from bindbc-sdl 446 + 447 + Params: 448 + sdlPixelFormatEnum = the `SDL_PixelFormatEnum` enumeration (non-indexed) 449 + Throws: `dsdl2.SDLException` if allocation failed 450 +/ 451 this(SDL_PixelFormatEnum sdlPixelFormatEnum) @trusted 452 in { 453 assert(sdlPixelFormatEnum != SDL_PIXELFORMAT_UNKNOWN); 454 assert(!SDL_ISPIXELFORMAT_INDEXED(sdlPixelFormatEnum)); 455 } 456 do { 457 this.sdlPixelFormat = SDL_AllocFormat(sdlPixelFormatEnum); 458 if (this.sdlPixelFormat is null) { 459 throw new SDLException; 460 } 461 } 462 463 /++ 464 + Constructs a `dsdl2.PixelFormat` using an indexed `SDL_PixelFormatEnum` from bindbc-sdl, allowing use with 465 + `dsdl2.Palette`s 466 + 467 + Params: 468 + sdlPixelFormatEnum = the `SDL_PixelFormatEnum` enumeration (indexed) 469 + palette = the `dsdl2.Palette` class instance to bind as the color palette 470 + Throws: `dsdl2.SDLException` if allocation or palette-setting failed 471 +/ 472 this(SDL_PixelFormatEnum sdlPixelFormatEnum, Palette palette) @trusted 473 in { 474 assert(SDL_ISPIXELFORMAT_INDEXED(sdlPixelFormatEnum)); 475 assert(palette !is null); 476 } 477 do { 478 this.sdlPixelFormat = SDL_AllocFormat(sdlPixelFormatEnum); 479 if (this.sdlPixelFormat is null) { 480 throw new SDLException; 481 } 482 483 if (SDL_SetPixelFormatPalette(this.sdlPixelFormat, palette.sdlPalette) != 0) { 484 throw new SDLException; 485 } 486 487 this.paletteRef = palette; 488 } 489 490 /++ 491 + Constructs a `dsdl2.PixelFormat` from user-provided bit masks for RGB color and alpha channels by internally 492 + using `SDL_MasksToPixelFormatEnum` to retrieve the `SDL_PixelFormatEnum` 493 + 494 + Params: 495 + bitsPerPixel = size of one pixel in bits 496 + rgbaMasks = bit masks for the red, green, blue, and alpha channels 497 + Throws: `dsdl2.SDLException` if pixel format conversion not possible 498 +/ 499 this(ubyte bitsPerPixel, uint[4] rgbaMasks) @trusted 500 in { 501 assert(bitsPerPixel > 0); 502 } 503 do { 504 uint sdlPixelFormatEnum = SDL_MasksToPixelFormatEnum(bitsPerPixel, rgbaMasks[0], rgbaMasks[1], rgbaMasks[2], 505 rgbaMasks[3]); 506 if (sdlPixelFormatEnum == SDL_PIXELFORMAT_UNKNOWN) { 507 throw new SDLException("Pixel format conversion is not possible", __FILE__, __LINE__); 508 } 509 510 this(sdlPixelFormatEnum); 511 } 512 513 ~this() @trusted { 514 if (this.isOwner) { 515 SDL_FreeFormat(this.sdlPixelFormat); 516 } 517 } 518 519 @trusted invariant { // @suppress(dscanner.trust_too_much) 520 // Instance might be in an invalid state due to holding a non-owned externally-freed object when 521 // destructed in an unpredictable order. 522 if (!this.isOwner && GC.inFinalizer) { 523 return; 524 } 525 526 assert(this.sdlPixelFormat !is null); 527 if (this.isOwner) { 528 assert(this.sdlPixelFormat.format != SDL_PIXELFORMAT_UNKNOWN); 529 } 530 531 if (SDL_ISPIXELFORMAT_INDEXED(this.sdlPixelFormat.format)) { 532 assert(this.paletteRef !is null); 533 if (this.isOwner) { 534 assert(this.sdlPixelFormat.palette !is null); 535 } 536 } 537 } 538 539 /++ 540 + Equality operator overload 541 +/ 542 bool opEquals(const PixelFormat rhs) const @trusted { 543 if (rhs is null) { 544 return false; 545 } 546 547 if (this.sdlPixelFormat.format == rhs.sdlPixelFormat.format) { 548 return true; 549 } 550 551 if (this.sdlPixelFormatEnum != rhs.sdlPixelFormatEnum) { 552 return false; 553 } 554 555 if (SDL_ISPIXELFORMAT_INDEXED(this.sdlPixelFormatEnum)) { 556 return this.paletteRef == rhs.paletteRef; 557 } 558 else { 559 return true; 560 } 561 } 562 563 /++ 564 + Gets the hash of the `dsdl2.PixelFormat` 565 + 566 + Returns: unique hash for the `dsdl2.PixelFormat` 567 +/ 568 override hash_t toHash() const @trusted { 569 try { 570 return this.sdlPixelFormatEnum.hashOf(this.paletteRef.hashOf); 571 } 572 catch (Exception) { 573 assert(false); 574 } 575 } 576 577 /++ 578 + Formats the `dsdl2.PixelFormat` into its construction representation: 579 + `"dsdl2.PixelFormat(<sdlPixelFormatEnum>)"` or `"dsdl2.PixelFormat(<sdlPixelFormatEnum>, <palette>)"` 580 + 581 + Returns: the formatted `string` 582 +/ 583 override string toString() const @trusted { 584 if (SDL_ISPIXELFORMAT_INDEXED(this.sdlPixelFormatEnum)) { 585 return "dsdl2.PixelFormat(0x%x, %s)".format(this.sdlPixelFormatEnum, this.paletteRef); 586 } 587 else { 588 return "dsdl2.PixelFormat(0x%s)".format(this.sdlPixelFormatEnum); 589 } 590 } 591 592 /++ 593 + Gets the `SDL_PixelFormatEnum` of the underlying `SDL_PixelFormat` 594 + 595 + Returns: `SDL_PixelFormatEnum` enumeration from bindbc-sdl 596 +/ 597 SDL_PixelFormatEnum sdlPixelFormatEnum() const @property @trusted { 598 return this.sdlPixelFormat.format; 599 } 600 601 /++ 602 + Wraps `SDL_GetRGB` which converts a pixel `uint` value to a comprehensible `dsdl2.Color` struct without 603 + accounting the alpha value (automatically set to opaque [255]), based on the pixel format defined by the 604 + `dsdl2.PixelFormat` 605 + 606 + Params: 607 + pixel = the pixel `uint` value to convert 608 + Returns: the `dsdl2.Color` struct of the given `pixel` value 609 +/ 610 Color getRGB(uint pixel) const @trusted { 611 Color color = Color(0, 0, 0, 255); 612 SDL_GetRGB(pixel, this.sdlPixelFormat, &color.sdlColor.r, &color.sdlColor.g, 613 &color.sdlColor.b); 614 return color; 615 } 616 617 /++ 618 + Wraps `SDL_GetRGBA` which converts a pixel `uint` value to a comprehensible `dsdl2.Color` struct, based on 619 + the pixel format defined by the `dsdl2.PixelFormat` 620 + 621 + Params: 622 + pixel = the pixel `uint` value to convert 623 + Returns: the `dsdl2.Color` struct of the given `pixel` value 624 +/ 625 Color getRGBA(uint pixel) const @trusted { 626 Color color = void; 627 SDL_GetRGBA(pixel, this.sdlPixelFormat, &color.sdlColor.r, &color.sdlColor.g, &color.sdlColor.b, 628 &color.sdlColor.a); 629 return color; 630 } 631 632 /++ 633 + Wraps `SDL_MapRGB` which converts a `dsdl2.Color` to its pixel `uint` value according to the pixel format 634 + defined by the `dsdl2.PixelFormat` without accounting the alpha value, assuming that it's opaque 635 + 636 + Params: 637 + color = the `dsdl2.Color` struct to convert 638 + Returns: the converted pixel value 639 +/ 640 uint mapRGB(Color color) const @trusted { 641 return SDL_MapRGB(this.sdlPixelFormat, color.sdlColor.r, color.sdlColor.g, 642 color.sdlColor.b); 643 } 644 645 /++ 646 + Wraps `SDL_MapRGBA` which converts a `dsdl2.Color` to its pixel `uint` value according to the pixel format 647 + defined by the `dsdl2.PixelFormat` 648 + 649 + Params: 650 + color = the `dsdl2.Color` struct to convert 651 + Returns: the converted pixel value 652 +/ 653 uint mapRGBA(Color color) const @trusted { 654 return SDL_MapRGBA(this.sdlPixelFormat, color.sdlColor.r, color.sdlColor.g, color.sdlColor.b, 655 color.sdlColor.a); 656 } 657 658 /++ 659 + Gets the `dsdl2.Palette` bounds to the indexed `dsdl2.PixelFormat` 660 + 661 + Returns: the bound `dsdl2.Palette` 662 +/ 663 inout(Palette) palette() return inout @property @trusted 664 in { 665 assert(this.indexed); 666 } 667 do { 668 return this.paletteRef; 669 } 670 671 /++ 672 + Wraps `SDL_SetPixelFormatPalette` which sets the `dsdl2.Palette` for indexed `dsdl2.PixelFormat`s` 673 + 674 + Params: 675 + newPalette = the `dsdl2.Palette` class instance to bind as the color palette 676 +/ 677 void palette(Palette newPalette) @property @trusted 678 in { 679 assert(this.indexed); 680 assert(newPalette !is null); 681 } 682 do { 683 if (SDL_SetPixelFormatPalette(this.sdlPixelFormat, newPalette.sdlPalette) != 0) { 684 throw new SDLException; 685 } 686 687 this.paletteRef = newPalette; 688 } 689 690 /++ 691 + Gets the bit depth (size of a pixel in bits) of the `dsdl2.PixelFormat` 692 + 693 + Returns: the bit depth of the `dsdl2.PixelFormat` 694 +/ 695 ubyte bitsPerPixel() const @property @trusted { 696 return this.sdlPixelFormat.BitsPerPixel; 697 } 698 699 /++ 700 + Gets the how many bytes needed to represent a pixel in the `dsdl2.PixelFormat` 701 + 702 + Returns: the bytes per pixel value of the `dsdl2.PixelFormat` 703 +/ 704 size_t bytesPerPixel() const @property @trusted { 705 return this.sdlPixelFormat.BytesPerPixel; 706 } 707 708 /++ 709 + Wraps `SDL_PixelFormatEnumToMasks` which gets the bit mask for all four channels of the `dsdl2.PixelFormat` 710 + 711 + Returns: an array of 4 bit masks for each channel (red, green, blue, and alpha) 712 +/ 713 uint[4] toMasks() const @trusted { 714 uint[4] rgbaMasks = void; 715 int bitsPerPixel = void; 716 717 if (SDL_PixelFormatEnumToMasks(this.sdlPixelFormatEnum, &bitsPerPixel, &rgbaMasks[0], &rgbaMasks[1], 718 &rgbaMasks[2], &rgbaMasks[3]) == SDL_FALSE) { 719 throw new SDLException; 720 } 721 722 return rgbaMasks; 723 } 724 725 /++ 726 + Wraps `SDL_ISPIXELFORMAT_INDEXED` which checks whether the `dsdl2.PixelFormat` is indexed 727 + 728 + Returns: `true` if it is indexed, otherwise `false` 729 +/ 730 bool indexed() const @property @trusted { 731 return SDL_ISPIXELFORMAT_INDEXED(this.sdlPixelFormatEnum); 732 } 733 734 /++ 735 + Wraps `SDL_ISPIXELFORMAT_ALPHA` which checks whether the `dsdl2.PixelFormat` is capable of storing alpha value 736 + 737 + Returns: `true` if it can have an alpha channel, otherwise `false` 738 +/ 739 bool hasAlpha() const @property @trusted { 740 return SDL_ISPIXELFORMAT_ALPHA(this.sdlPixelFormatEnum); 741 } 742 743 /++ 744 + Wraps `SDL_ISPIXELFORMAT_FOURCC` which checks whether the `dsdl2.PixelFormat` represents a unique format 745 + 746 + Returns: `true` if it is unique, otherwise `false` 747 +/ 748 bool fourCC() const @property @trusted { 749 return SDL_ISPIXELFORMAT_FOURCC(this.sdlPixelFormatEnum) != 0; 750 } 751 } 752 /// 753 unittest { 754 static if (sdlSupport >= SDLSupport.v2_0_5) { 755 const auto rgba32 = dsdl2.PixelFormat.rgba32; 756 assert(rgba32.mapRGBA(dsdl2.Color(0x12, 0x34, 0x56, 0x78)) == 0x12345678); 757 assert(rgba32.getRGBA(0x12345678) == dsdl2.Color(0x12, 0x34, 0x56, 0x78)); 758 } 759 760 const auto rgba8888 = dsdl2.PixelFormat.rgba8888; 761 version (LittleEndian) { 762 assert(rgba8888.mapRGBA(dsdl2.Color(0x12, 0x34, 0x56, 0x78)) == 0x12345678); 763 assert(rgba8888.getRGBA(0x12345678) == dsdl2.Color(0x12, 0x34, 0x56, 0x78)); 764 } 765 version (BigEndian) { 766 assert(rgba8888.mapRGBA(dsdl2.Color(0x12, 0x34, 0x56, 0x78)) == 0x78563412); 767 assert(rgba8888.get(0x78563412) == dsdl2.Color(0x12, 0x34, 0x56, 0x78)); 768 } 769 }