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();