1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 * 24 * 25 * DSFML is based on SFML (Copyright Laurent Gomila) 26 */ 27 28 /** 29 * $(U Texture) stores pixels that can be drawn, with a sprite for example. A 30 * texture lives in the graphics card memory, therefore it is very fast to draw 31 * a texture to a render target, or copy a render target to a texture (the 32 * graphics card can access both directly). 33 * 34 * Being stored in the graphics card memory has some drawbacks. A texture cannot 35 * be manipulated as freely as a $(IMAGE_LINK), you need to prepare the pixels 36 * first and then upload them to the texture in a single operation (see 37 * `Texture.update`). 38 * 39 * $(U Texture) makes it easy to convert from/to Image, but keep in mind that 40 * these calls require transfers between the graphics card and the central 41 * memory, therefore they are slow operations. 42 * 43 * A texture can be loaded from an image, but also directly from a 44 * file/memory/stream. The necessary shortcuts are defined so that you don't 45 * need an image first for the most common cases. However, if you want to 46 * perform some modifications on the pixels before creating the final texture, 47 * you can load your file to a $(IMAGE_LINK), do whatever you need with the 48 * pixels, and then call `Texture.loadFromImage`. 49 * 50 * Since they live in the graphics card memory, the pixels of a texture cannot 51 * be accessed without a slow copy first. And they cannot be accessed 52 * individually. Therefore, if you need to read the texture's pixels (like for 53 * pixel-perfect collisions), it is recommended to store the collision 54 * information separately, for example in an array of booleans. 55 * 56 * Like $(IMAGE_LINK), $(U Texture) can handle a unique internal representation 57 * of pixels, which is RGBA 32 bits. This means that a pixel must be composed of 58 * 8 bits red, green, blue and alpha channels – just like a $(COLOR_LINK). 59 * 60 * Example: 61 * --- 62 * // This example shows the most common use of Texture: 63 * // drawing a sprite 64 * 65 * // Load a texture from a file 66 * auto texture = new Texture(); 67 * if (!texture.loadFromFile("texture.png")) 68 * return -1; 69 * 70 * // Assign it to a sprite 71 * auto sprite = new Sprite(); 72 * sprite.setTexture(texture); 73 * 74 * // Draw the textured sprite 75 * window.draw(sprite); 76 * --- 77 * 78 * --- 79 * // This example shows another common use of Texture: 80 * // streaming real-time data, like video frames 81 * 82 * // Create an empty texture 83 * auto texture = new Texture(); 84 * if (!texture.create(640, 480)) 85 * return -1; 86 * 87 * // Create a sprite that will display the texture 88 * auto sprite = new Sprite(texture); 89 * 90 * while (...) // the main loop 91 * { 92 * ... 93 * 94 * // update the texture 95 * 96 * // get a fresh chunk of pixels (the next frame of a movie, for example) 97 * ubyte[] pixels = ...; 98 * texture.update(pixels); 99 * 100 * // draw it 101 * window.draw(sprite); 102 * 103 * ... 104 * } 105 * 106 * --- 107 * 108 * $(PARA Like $(SHADER_LINK) that can be used as a raw OpenGL shader, 109 * $(U Texture) can also be used directly as a raw texture for custom OpenGL 110 * geometry.) 111 * --- 112 * Texture.bind(texture); 113 * ... render OpenGL geometry ... 114 * Texture.bind(null); 115 * --- 116 * 117 * See_Also: 118 * $(SPRITE_LINK), $(IMAGE_LINK), $(RENDERTEXTURE_LINK) 119 */ 120 module dsfml.graphics.texture; 121 122 import dsfml.graphics.rect; 123 import dsfml.graphics.image; 124 import dsfml.graphics.renderwindow; 125 126 import dsfml.window.window; 127 128 import dsfml.system.inputstream; 129 import dsfml.system.vector2; 130 import dsfml.system.err; 131 132 /** 133 * Image living on the graphics card that can be used for drawing. 134 */ 135 class Texture 136 { 137 package sfTexture* sfPtr; 138 139 /** 140 * Default constructor 141 * 142 * Creates an empty texture. 143 */ 144 this() 145 { 146 sfPtr = sfTexture_construct(); 147 } 148 149 package this(sfTexture* texturePointer) 150 { 151 sfPtr = texturePointer; 152 } 153 154 /// Destructor. 155 ~this() 156 { 157 import dsfml.system.config; 158 mixin(destructorOutput); 159 sfTexture_destroy( sfPtr); 160 } 161 162 /** 163 * Load the texture from a file on disk. 164 * 165 * The area argument can be used to load only a sub-rectangle of the whole 166 * image. If you want the entire image then leave the default value (which 167 * is an empty IntRect). If the area rectangle crosses the bounds of the 168 * image, it is adjusted to fit the image size. 169 * 170 * The maximum size for a texture depends on the graphics driver and can be 171 * retrieved with the getMaximumSize function. 172 * 173 * If this function fails, the texture is left unchanged. 174 * 175 * Params: 176 * filename = Path of the image file to load 177 * area = Area of the image to load 178 * 179 * Returns: true if loading was successful, false otherwise. 180 */ 181 bool loadFromFile(const(char)[] filename, IntRect area = IntRect() ) 182 { 183 return sfTexture_loadFromFile(sfPtr, filename.ptr, filename.length,area.left, area.top,area.width, area.height); 184 } 185 186 /** 187 * Load the texture from a file in memory. 188 * 189 * The area argument can be used to load only a sub-rectangle of the whole 190 * image. If you want the entire image then leave the default value (which 191 * is an empty IntRect). If the area rectangle crosses the bounds of the 192 * image, it is adjusted to fit the image size. 193 * 194 * The maximum size for a texture depends on the graphics driver and can be 195 * retrieved with the getMaximumSize function. 196 * 197 * If this function fails, the texture is left unchanged. 198 * 199 * Params: 200 * data = Image in memory 201 * area = Area of the image to load 202 * 203 * Returns: true if loading was successful, false otherwise. 204 */ 205 bool loadFromMemory(const(void)[] data, IntRect area = IntRect()) 206 { 207 return sfTexture_loadFromMemory(sfPtr, data.ptr, data.length,area.left, area.top,area.width, area.height); 208 } 209 210 /** 211 * Load the texture from a custom stream. 212 * 213 * The area argument can be used to load only a sub-rectangle of the whole 214 * image. If you want the entire image then leave the default value (which 215 * is an empty IntRect). If the area rectangle crosses the bounds of the 216 * image, it is adjusted to fit the image size. 217 * 218 * The maximum size for a texture depends on the graphics driver and can be 219 * retrieved with the getMaximumSize function. 220 * 221 * If this function fails, the texture is left unchanged. 222 * 223 * Params: 224 * stream = Source stream to read from 225 * area = Area of the image to load 226 * 227 * Returns: true if loading was successful, false otherwise. 228 */ 229 bool loadFromStream(InputStream stream, IntRect area = IntRect()) 230 { 231 return sfTexture_loadFromStream(sfPtr, new textureStream(stream), area.left, area.top,area.width, area.height); 232 } 233 234 /** 235 * Load the texture from an image. 236 * 237 * The area argument can be used to load only a sub-rectangle of the whole 238 * image. If you want the entire image then leave the default value (which 239 * is an empty IntRect). If the area rectangle crosses the bounds of the 240 * image, it is adjusted to fit the image size. 241 * 242 * The maximum size for a texture depends on the graphics driver and can be 243 * retrieved with the getMaximumSize function. 244 * 245 * If this function fails, the texture is left unchanged. 246 * 247 * Params: 248 * image = Image to load into the texture 249 * area = Area of the image to load 250 * 251 * Returns: true if loading was successful, false otherwise. 252 */ 253 bool loadFromImage(Image image, IntRect area = IntRect()) 254 { 255 return sfTexture_loadFromImage(sfPtr, image.sfPtr, area.left, area.top,area.width, area.height); 256 } 257 258 /** 259 * Get the maximum texture size allowed. 260 * 261 * This Maximum size is defined by the graphics driver. You can expect a 262 * value of 512 pixels for low-end graphics card, and up to 8192 pixels or 263 * more for newer hardware. 264 * 265 * Returns: Maximum size allowed for textures, in pixels. 266 */ 267 static uint getMaximumSize() 268 { 269 return sfTexture_getMaximumSize(); 270 } 271 272 /** 273 * Return the size of the texture. 274 * 275 * Returns: Size in pixels. 276 */ 277 Vector2u getSize() const 278 { 279 Vector2u temp; 280 sfTexture_getSize(sfPtr, &temp.x, &temp.y); 281 return temp; 282 } 283 284 /** 285 * Enable or disable the smooth filter. 286 * 287 * When the filter is activated, the texture appears smoother so that pixels 288 * are less noticeable. However if you want the texture to look exactly the 289 * same as its source file, you should leave it disabled. The smooth filter 290 * is disabled by default. 291 * 292 * Params: 293 * smooth = true to enable smoothing, false to disable it 294 */ 295 void setSmooth(bool smooth) 296 { 297 sfTexture_setSmooth(sfPtr, smooth); 298 } 299 300 /** 301 * Enable or disable repeating. 302 * 303 * Repeating is involved when using texture coordinates outside the texture 304 * rectangle [0, 0, width, height]. In this case, if repeat mode is enabled, 305 * the whole texture will be repeated as many times as needed to reach the 306 * coordinate (for example, if the X texture coordinate is 3 * width, the 307 * texture will be repeated 3 times). 308 * 309 * If repeat mode is disabled, the "extra space" will instead be filled with 310 * border pixels. Warning: on very old graphics cards, white pixels may 311 * appear when the texture is repeated. With such cards, repeat mode can be 312 * used reliably only if the texture has power-of-two dimensions 313 * (such as 256x128). Repeating is disabled by default. 314 * 315 * Params: 316 * repeated = true to repeat the texture, false to disable repeating 317 */ 318 void setRepeated(bool repeated) 319 { 320 sfTexture_setRepeated(sfPtr, repeated); 321 } 322 323 /** 324 * Bind a texture for rendering. 325 * 326 * This function is not part of the graphics API, it mustn't be used when 327 * drawing DSFML entities. It must be used only if you mix Texture with 328 * OpenGL code. 329 * 330 * Params: 331 * texture = The texture to bind. Can be null to use no texture 332 */ 333 static void bind(Texture texture) 334 { 335 (texture is null)?sfTexture_bind(null):sfTexture_bind(texture.sfPtr); 336 } 337 338 /** 339 * Create the texture. 340 * 341 * If this function fails, the texture is left unchanged. 342 * 343 * Params: 344 * width = Width of the texture 345 * height = Height of the texture 346 * 347 * Returns: true if creation was successful, false otherwise. 348 */ 349 bool create(uint width, uint height) 350 { 351 return sfTexture_create(sfPtr, width, height); 352 } 353 354 /** 355 * Copy the texture pixels to an image. 356 * 357 * This function performs a slow operation that downloads the texture's 358 * pixels from the graphics card and copies them to a new image, potentially 359 * applying transformations to pixels if necessary (texture may be padded or 360 * flipped). 361 * 362 * Returns: Image containing the texture's pixels. 363 */ 364 Image copyToImage() const 365 { 366 return new Image(sfTexture_copyToImage(sfPtr)); 367 } 368 369 /** 370 * Creates a new texture from the same data (this means copying the entire 371 * set of pixels). 372 */ 373 @property Texture dup() const 374 { 375 return new Texture(sfTexture_copy(sfPtr)); 376 } 377 378 /** 379 * Tell whether the texture is repeated or not. 380 * 381 * Returns: true if repeat mode is enabled, false if it is disabled. 382 */ 383 bool isRepeated() const 384 { 385 return (sfTexture_isRepeated(sfPtr)); 386 } 387 388 /** 389 * Tell whether the smooth filter is enabled or not. 390 * 391 * Returns: true if something is enabled, false if it is disabled. 392 */ 393 bool isSmooth() const 394 { 395 return (sfTexture_isSmooth(sfPtr)); 396 } 397 398 /** 399 * Update the whole texture from an array of pixels. 400 * 401 * The pixel array is assumed to have the same size as 402 * the area rectangle, and to contain 32-bits RGBA pixels. 403 * 404 * No additional check is performed on the size of the pixel 405 * array, passing invalid arguments will lead to an undefined 406 * behavior. 407 * 408 * This function does nothing if pixels is empty or if the 409 * texture was not previously created. 410 * 411 * Params: 412 * pixels = Array of pixels to copy to the texture. 413 */ 414 void update(const(ubyte)[] pixels) 415 { 416 Vector2u size = getSize(); 417 418 sfTexture_updateFromPixels(sfPtr,pixels.ptr,size.x, size.y, 0,0); 419 } 420 421 /** 422 * Update part of the texture from an array of pixels. 423 * 424 * The size of the pixel array must match the width and height arguments, 425 * and it must contain 32-bits RGBA pixels. 426 * 427 * No additional check is performed on the size of the pixel array or the 428 * bounds of the area to update, passing invalid arguments will lead to an 429 * undefined behaviour. 430 * 431 * This function does nothing if pixels is empty or if the texture was not 432 * previously created. 433 * 434 * Params: 435 * pixels = Array of pixels to copy to the texture. 436 * width = Width of the pixel region contained in pixels 437 * height = Height of the pixel region contained in pixels 438 * x = X offset in the texture where to copy the source pixels 439 * y = Y offset in the texture where to copy the source pixels 440 */ 441 void update(const(ubyte)[] pixels, uint width, uint height, uint x, uint y) 442 { 443 sfTexture_updateFromPixels(sfPtr,pixels.ptr,width, height, x,y); 444 } 445 446 /** 447 * Update the texture from an image. 448 * 449 * Although the source image can be smaller than the texture, this function 450 * is usually used for updating the whole texture. The other overload, which 451 * has (x, y) additional arguments, is more convenient for updating a 452 * sub-area of the texture. 453 * 454 * No additional check is performed on the size of the image, passing an 455 * image bigger than the texture will lead to an undefined behaviour. 456 * 457 * This function does nothing if the texture was not previously created. 458 * 459 * Params: 460 * image = Image to copy to the texture. 461 */ 462 void update(const(Image) image) 463 { 464 sfTexture_updateFromImage(sfPtr, image.sfPtr, 0, 0); 465 } 466 467 /** 468 * Update the texture from an image. 469 * 470 * No additional check is performed on the size of the image, passing an 471 * invalid combination of image size and offset will lead to an undefined 472 * behavior. 473 * 474 * This function does nothing if the texture was not previously created. 475 * 476 * Params: 477 * image = Image to copy to the texture. 478 * y = Y offset in the texture where to copy the source image. 479 * x = X offset in the texture where to copy the source image. 480 */ 481 void update(const(Image) image, uint x, uint y) 482 { 483 sfTexture_updateFromImage(sfPtr, image.sfPtr, x, y); 484 } 485 486 /** 487 * Update the texture from the contents of a window 488 * 489 * Although the source window can be smaller than the texture, this function 490 * is usually used for updating the whole texture. The other overload, which 491 * has (x, y) additional arguments, is more convenient for updating a 492 * sub-area of the texture. 493 * 494 * No additional check is performed on the size of the window, passing a 495 * window bigger than the texture will lead to an undefined behavior. 496 * 497 * This function does nothing if either the texture or the window 498 * was not previously created. 499 * 500 * Params: 501 * window = Window to copy to the texture 502 */ 503 void update(T)(const(T) window) 504 if(is(T == Window) || is(T == RenderWindow)) 505 { 506 update(window, 0, 0); 507 } 508 509 /** 510 * Update a part of the texture from the contents of a window. 511 * 512 * No additional check is performed on the size of the window, passing an 513 * invalid combination of window size and offset will lead to an undefined 514 * behavior. 515 * 516 * This function does nothing if either the texture or the window was not 517 * previously created. 518 * 519 * Params: 520 * window = Window to copy to the texture 521 * x = X offset in the texture where to copy the source window 522 * y = Y offset in the texture where to copy the source window 523 * 524 */ 525 void update(T)(const(T) window, uint x, uint y) 526 if(is(T == Window) || is(T == RenderWindow)) 527 { 528 static if(is(T == RenderWindow)) 529 { 530 sfTexture_updateFromRenderWindow(sfPtr, T.sfPtr, x, y); 531 } 532 else 533 { 534 sfTexture_updateFromWindow(sfPtr, RenderWindow.windowPointer(T), 535 x, y); 536 } 537 } 538 539 /** 540 * Update the texture from an image. 541 * 542 * Although the source image can be smaller than the texture, this function 543 * is usually used for updating the whole texture. The other overload, which 544 * has (x, y) additional arguments, is more convenient for updating a 545 * sub-area of the texture. 546 * 547 * No additional check is performed on the size of the image, passing an 548 * image bigger than the texture will lead to an undefined behaviour. 549 * 550 * This function does nothing if the texture was not previously created. 551 * 552 * Params: 553 * image = Image to copy to the texture. 554 * y = Y offset in the texture where to copy the source image. 555 * x = X offset in the texture where to copy the source image. 556 */ 557 deprecated("Use update function.") 558 void updateFromImage(Image image, uint x, uint y) 559 { 560 sfTexture_updateFromImage(sfPtr, image.sfPtr, x, y); 561 } 562 563 /** 564 * Update part of the texture from an array of pixels. 565 * 566 * The size of the pixel array must match the width and height arguments, 567 * and it must contain 32-bits RGBA pixels. 568 * 569 * No additional check is performed on the size of the pixel array or the 570 * bounds of the area to update, passing invalid arguments will lead to an 571 * undefined behaviour. 572 * 573 * This function does nothing if pixels is null or if the texture was not 574 * previously created. 575 * 576 * Params: 577 * pixels = Array of pixels to copy to the texture. 578 * width = Width of the pixel region contained in pixels 579 * height = Height of the pixel region contained in pixels 580 * x = X offset in the texture where to copy the source pixels 581 * y = Y offset in the texture where to copy the source pixels 582 */ 583 deprecated("Use update function.") 584 void updateFromPixels(const(ubyte)[] pixels, uint width, uint height, uint x, uint y) 585 { 586 sfTexture_updateFromPixels(sfPtr,pixels.ptr,width, height, x,y); 587 } 588 589 //TODO: Get this working via inheritance?(so custom window classes can do it too) 590 /** 591 * Update a part of the texture from the contents of a window. 592 * 593 * No additional check is performed on the size of the window, passing an 594 * invalid combination of window size and offset will lead to an undefined 595 * behaviour. 596 * 597 * This function does nothing if either the texture or the window was not 598 * previously created. 599 * 600 * Params: 601 * window = Window to copy to the texture 602 * x = X offset in the texture where to copy the source window 603 * y = Y offset in the texture where to copy the source window 604 */ 605 deprecated("Use update function.") 606 void updateFromWindow(Window window, uint x, uint y) 607 { 608 sfTexture_updateFromWindow(sfPtr, RenderWindow.windowPointer(window), x, y); 609 } 610 611 //Is this even safe? RenderWindow inherits from Window, so what happens? Is this bottom used or the top? 612 /** 613 * Update a part of the texture from the contents of a window. 614 * 615 * No additional check is performed on the size of the window, passing an 616 * invalid combination of window size and offset will lead to an undefined 617 * behaviour. 618 * 619 * This function does nothing if either the texture or the window was not 620 * previously created. 621 * 622 * Params: 623 * window = Window to copy to the texture 624 * x = X offset in the texture where to copy the source window 625 * y = Y offset in the texture where to copy the source window 626 */ 627 deprecated("Use update function.") 628 void updateFromWindow(RenderWindow window, uint x, uint y) 629 { 630 sfTexture_updateFromRenderWindow(sfPtr, window.sfPtr, x, y); 631 } 632 } 633 634 unittest 635 { 636 version(DSFML_Unittest_Graphics) 637 { 638 import std.stdio; 639 640 writeln("Unit test for Texture"); 641 642 auto texture = new Texture(); 643 644 assert(texture.loadFromFile("res/TestImage.png")); 645 646 //do things with the texture 647 648 writeln(); 649 } 650 } 651 652 private extern(C++) interface textureInputStream 653 { 654 long read(void* data, long size); 655 656 long seek(long position); 657 658 long tell(); 659 660 long getSize(); 661 } 662 663 private class textureStream:textureInputStream 664 { 665 private InputStream myStream; 666 667 this(InputStream stream) 668 { 669 myStream = stream; 670 } 671 672 extern(C++)long read(void* data, long size) 673 { 674 return myStream.read(data[0..cast(size_t)size]); 675 } 676 677 extern(C++)long seek(long position) 678 { 679 return myStream.seek(position); 680 } 681 682 extern(C++)long tell() 683 { 684 return myStream.tell(); 685 } 686 687 extern(C++)long getSize() 688 { 689 return myStream.getSize(); 690 } 691 } 692 693 package extern(C) struct sfTexture; 694 695 private extern(C): 696 697 //Construct a new texture 698 sfTexture* sfTexture_construct(); 699 700 //Create a new texture 701 bool sfTexture_create(sfTexture* texture, uint width, uint height); 702 703 //Create a new texture from a file 704 bool sfTexture_loadFromFile(sfTexture* texture, const(char)* filename, size_t length, int left, int top, int width, int height); 705 706 //Create a new texture from a file in memory 707 bool sfTexture_loadFromMemory(sfTexture* texture, const(void)* data, size_t sizeInBytes, int left, int top, int width, int height); 708 709 //Create a new texture from a custom stream 710 bool sfTexture_loadFromStream(sfTexture* texture, textureInputStream stream, int left, int top, int width, int height); 711 712 //Create a new texture from an image 713 bool sfTexture_loadFromImage(sfTexture* texture, const(sfImage)* image, int left, int top, int width, int height); 714 715 //Copy an existing texture 716 sfTexture* sfTexture_copy(const(sfTexture)* texture); 717 718 //Destroy an existing texture 719 void sfTexture_destroy(sfTexture* texture); 720 721 //Return the size of the texture 722 void sfTexture_getSize(const(sfTexture)* texture, uint* x, uint* y); 723 724 //Copy a texture's pixels to an image 725 sfImage* sfTexture_copyToImage(const sfTexture* texture); 726 727 //Update a texture from an array of pixels 728 void sfTexture_updateFromPixels(sfTexture* texture, const ubyte* pixels, uint width, uint height, uint x, uint y); 729 730 //Update a texture from an image 731 void sfTexture_updateFromImage(sfTexture* texture, const sfImage* image, uint x, uint y); 732 733 //Update a texture from the contents of a window 734 void sfTexture_updateFromWindow(sfTexture* texture, const(void)* window, uint x, uint y); 735 736 //Update a texture from the contents of a render-window 737 void sfTexture_updateFromRenderWindow(sfTexture* texture, const sfRenderWindow* renderWindow, uint x, uint y); 738 739 //Enable or disable the smooth filter on a texture 740 void sfTexture_setSmooth(sfTexture* texture, bool smooth); 741 742 //Tell whether the smooth filter is enabled or not for a texture 743 bool sfTexture_isSmooth(const sfTexture* texture); 744 745 //Enable or disable repeating for a texture 746 void sfTexture_setRepeated(sfTexture* texture, bool repeated); 747 748 //Tell whether a texture is repeated or not 749 bool sfTexture_isRepeated(const sfTexture* texture); 750 751 //Bind a texture for rendering 752 void sfTexture_bind(const sfTexture* texture); 753 754 //Get the maximum texture size allowed 755 uint sfTexture_getMaximumSize(); 756 757 //Flush the OpenGL command buffer. 758 //void sfTexture_flush();