1 module nudsfml.graphics.texture;
2 
3 import std.string;
4 
5 import bindbc.sfml.graphics;
6 import bindbc.sfml.system;
7 
8 import nudsfml.graphics.rect;
9 import nudsfml.graphics.image;
10 import nudsfml.graphics.renderwindow;
11 
12 import nudsfml.window.window;
13 
14 import nudsfml.system.inputstream;
15 import nudsfml.system.vector2;
16 //import nudsfml.system.err;
17 
18 /**
19  * Image living on the graphics card that can be used for drawing.
20  */
21 class Texture
22 {
23     package sfTexture* sfPtr;
24     bool managed = false;
25 
26     /**
27      * Default constructor
28      *
29      * Creates an empty texture.
30      */
31     this() {
32         //sfPtr = sfTexture_construct();
33     }
34 
35     package this(sfTexture * texturePointer)
36     {
37         sfPtr = texturePointer;
38         managed = true;
39     }
40 
41     /// Destructor.
42     ~this() {
43         //import nudsfml.system.config;
44 //        mixin(destructorOutput);
45         if(!managed && sfPtr !is null) {
46             sfTexture_destroy(sfPtr);
47             sfPtr = null;
48         }
49     }
50 
51     /**
52      * Load the texture from a file on disk.
53      *
54      * The area argument can be used to load only a sub-rectangle of the whole
55      * image. If you want the entire image then leave the default value (which
56      * is an empty IntRect). If the area rectangle crosses the bounds of the
57      * image, it is adjusted to fit the image size.
58      *
59      * The maximum size for a texture depends on the graphics driver and can be
60      * retrieved with the getMaximumSize function.
61      *
62      * If this function fails, the texture is left unchanged.
63      *
64      * Params:
65      * 		filename	= Path of the image file to load
66      * 		area		= Area of the image to load
67      *
68      * Returns: true if loading was successful, false otherwise.
69      */
70     bool loadFromFile(const(char)[] filename, IntRect area = IntRect() )
71     {
72         if(sfPtr !is null){
73             sfTexture_destroy( sfPtr);
74         }
75 
76         sfIntRect *sfArea = new sfIntRect;
77         sfArea.left = area.left;
78         sfArea.top = area.top;
79         sfArea.width = area.width;
80         sfArea.height = area.height;
81 
82         sfPtr = sfTexture_createFromFile( filename.toStringz ,sfArea); 
83         return sfPtr !is null;
84     }
85 
86     /**
87      * Load the texture from a file in memory.
88      *
89      * The area argument can be used to load only a sub-rectangle of the whole
90      * image. If you want the entire image then leave the default value (which
91      * is an empty IntRect). If the area rectangle crosses the bounds of the
92      * image, it is adjusted to fit the image size.
93      *
94      * The maximum size for a texture depends on the graphics driver and can be
95      * retrieved with the getMaximumSize function.
96      *
97      * If this function fails, the texture is left unchanged.
98      *
99      * Params:
100      * 		data	= Image in memory
101      * 		area	= Area of the image to load
102      *
103      * Returns: true if loading was successful, false otherwise.
104      */
105     bool loadFromMemory(const(void)[] data, IntRect area = IntRect())
106     {
107         if(sfPtr !is null){
108             sfTexture_destroy( sfPtr);
109         }
110         
111         sfIntRect *sfArea = new sfIntRect;
112         sfArea.left = area.left;
113         sfArea.top = area.top;
114         sfArea.width = area.width;
115         sfArea.height = area.height;
116 
117         sfPtr = sfTexture_createFromMemory(data.ptr, data.length,sfArea); 
118         return sfPtr !is null;
119 
120     }
121     /**
122      * Load the texture from an image.
123      *
124      * The area argument can be used to load only a sub-rectangle of the whole
125      * image. If you want the entire image then leave the default value (which
126      * is an empty IntRect). If the area rectangle crosses the bounds of the
127      * image, it is adjusted to fit the image size.
128      *
129      * The maximum size for a texture depends on the graphics driver and can be
130      * retrieved with the getMaximumSize function.
131      *
132      * If this function fails, the texture is left unchanged.
133      *
134      * Params:
135      * 		image	= Image to load into the texture
136      * 		area	= Area of the image to load
137      *
138      * Returns: true if loading was successful, false otherwise.
139      */
140     bool loadFromImage(Image image, IntRect area = IntRect())
141     {
142 
143         if(sfPtr !is null){
144             sfTexture_destroy( sfPtr);
145         }
146         
147         sfIntRect *sfArea = new sfIntRect;
148         sfArea.left = area.left;
149         sfArea.top = area.top;
150         sfArea.width = area.width;
151         sfArea.height = area.height;
152 
153         sfPtr = sfTexture_createFromImage(image.sfPtr,sfArea); 
154         return sfPtr !is null;
155     }
156 
157     /**
158      * Get the maximum texture size allowed.
159      *
160      * This Maximum size is defined by the graphics driver. You can expect a
161      * value of 512 pixels for low-end graphics card, and up to 8192 pixels or
162      * more for newer hardware.
163      *
164      * Returns: Maximum size allowed for textures, in pixels.
165      */
166     static uint getMaximumSize()
167     {
168         return sfTexture_getMaximumSize();
169     }
170 
171     /**
172      * Return the size of the texture.
173      *
174      * Returns: Size in pixels.
175      */
176     Vector2u getSize() const
177     {
178         sfVector2u temp = sfTexture_getSize( sfPtr);
179         Vector2u retval = Vector2u(temp.x,temp.y);
180         return retval;
181     }
182 
183     /**
184      * Enable or disable the smooth filter.
185      *
186      * When the filter is activated, the texture appears smoother so that pixels
187      * are less noticeable. However if you want the texture to look exactly the
188      * same as its source file, you should leave it disabled. The smooth filter
189      * is disabled by default.
190      *
191      * Params:
192      * 		smooth	= true to enable smoothing, false to disable it
193      */
194     void setSmooth(bool smooth)
195     {
196         sfTexture_setSmooth(sfPtr, smooth);
197     }
198 
199     /**
200      * Enable or disable repeating.
201      *
202      * Repeating is involved when using texture coordinates outside the texture
203      * rectangle [0, 0, width, height]. In this case, if repeat mode is enabled,
204      * the whole texture will be repeated as many times as needed to reach the
205      * coordinate (for example, if the X texture coordinate is 3 * width, the
206      * texture will be repeated 3 times).
207      *
208      * If repeat mode is disabled, the "extra space" will instead be filled with
209      * border pixels. Warning: on very old graphics cards, white pixels may
210      * appear when the texture is repeated. With such cards, repeat mode can be
211      * used reliably only if the texture has power-of-two dimensions
212      * (such as 256x128). Repeating is disabled by default.
213      *
214      * Params:
215      * 		repeated	= true to repeat the texture, false to disable repeating
216      */
217     void setRepeated(bool repeated)
218     {
219         sfTexture_setRepeated(sfPtr, repeated);
220     }
221 
222     /**
223      * Bind a texture for rendering.
224      *
225      * This function is not part of the graphics API, it mustn't be used when
226      * drawing DSFML entities. It must be used only if you mix Texture with
227      * OpenGL code.
228      *
229      * Params:
230      * 		texture	= The texture to bind. Can be null to use no texture
231      */
232     static void bind(Texture texture)
233     {
234         (texture is null)?sfTexture_bind(null):sfTexture_bind(texture.sfPtr);
235     }
236 
237     /**
238      * Create the texture.
239      *
240      * If this function fails, the texture is left unchanged.
241      *
242      * Params:
243      * 		width	= Width of the texture
244      * 		height	= Height of the texture
245      *
246      * Returns: true if creation was successful, false otherwise.
247      */
248     bool create(uint width, uint height)
249     {
250         if(sfPtr !is null){
251             sfTexture_destroy( sfPtr);
252         }
253         sfPtr = sfTexture_create(width,height);
254         return sfPtr !is null;
255     }
256 
257     /**
258      * Copy the texture pixels to an image.
259      *
260      * This function performs a slow operation that downloads the texture's
261      * pixels from the graphics card and copies them to a new image, potentially
262      * applying transformations to pixels if necessary (texture may be padded or
263      * flipped).
264      *
265      * Returns: Image containing the texture's pixels.
266      */
267     Image copyToImage() const
268     {
269         return new Image(sfTexture_copyToImage(sfPtr));
270     }
271 
272     /**
273      * Creates a new texture from the same data (this means copying the entire
274      * set of pixels).
275      */
276     @property Texture dup() const
277     {
278         return new Texture(sfTexture_copy(sfPtr));
279     }
280 
281     /**
282      * Tell whether the texture is repeated or not.
283      *
284      * Returns: true if repeat mode is enabled, false if it is disabled.
285      */
286     bool isRepeated() const
287     {
288         return (sfTexture_isRepeated(sfPtr)) > 0;
289     }
290 
291     /**
292      * Tell whether the smooth filter is enabled or not.
293      *
294      * Returns: true if something is enabled, false if it is disabled.
295      */
296     bool isSmooth() const
297     {
298         return (sfTexture_isSmooth(sfPtr)) > 0;
299     }
300 
301     /**
302      * Update the whole texture from an array of pixels.
303      *
304      * The pixel array is assumed to have the same size as
305      * the area rectangle, and to contain 32-bits RGBA pixels.
306      *
307      * No additional check is performed on the size of the pixel
308      * array, passing invalid arguments will lead to an undefined
309      * behavior.
310      *
311      * This function does nothing if pixels is empty or if the
312      * texture was not previously created.
313      *
314      * Params:
315      * 		pixels	= Array of pixels to copy to the texture.
316      */
317     void update(const(ubyte)[] pixels)
318     {
319         Vector2u size = getSize();
320 
321         sfTexture_updateFromPixels(sfPtr,pixels.ptr,size.x, size.y, 0,0);
322     }
323 
324     /**
325      * Update part of the texture from an array of pixels.
326      *
327      * The size of the pixel array must match the width and height arguments,
328      * and it must contain 32-bits RGBA pixels.
329      *
330      * No additional check is performed on the size of the pixel array or the
331      * bounds of the area to update, passing invalid arguments will lead to an
332      * undefined behaviour.
333      *
334      * This function does nothing if pixels is empty or if the texture was not
335      * previously created.
336      *
337      * Params:
338      * 		pixels	= Array of pixels to copy to the texture.
339      * 		width	= Width of the pixel region contained in pixels
340      * 		height	= Height of the pixel region contained in pixels
341      * 		x		= X offset in the texture where to copy the source pixels
342      * 		y		= Y offset in the texture where to copy the source pixels
343      */
344     void update(const(ubyte)[] pixels, uint width, uint height, uint x, uint y)
345     {
346         sfTexture_updateFromPixels(sfPtr,pixels.ptr,width, height, x,y);
347     }
348 
349     /**
350      * Update the texture from an image.
351      *
352      * Although the source image can be smaller than the texture, this function
353      * is usually used for updating the whole texture. The other overload, which
354      * has (x, y) additional arguments, is more convenient for updating a
355      * sub-area of the texture.
356      *
357      * No additional check is performed on the size of the image, passing an
358      * image bigger than the texture will lead to an undefined behaviour.
359      *
360      * This function does nothing if the texture was not previously created.
361      *
362      * Params:
363      * 		image	= Image to copy to the texture.
364      */
365     void update(const(Image) image)
366     {
367         sfTexture_updateFromImage(sfPtr, image.sfPtr, 0, 0);
368     }
369 
370     /**
371      * Update the texture from an image.
372      *
373      * No additional check is performed on the size of the image, passing an
374      * invalid combination of image size and offset will lead to an undefined
375      * behavior.
376      *
377      * This function does nothing if the texture was not previously created.
378      *
379      * Params:
380      * 		image = Image to copy to the texture.
381      *		y     = Y offset in the texture where to copy the source image.
382      *		x     = X offset in the texture where to copy the source image.
383      */
384     void update(const(Image) image, uint x, uint y)
385     {
386         sfTexture_updateFromImage(sfPtr, image.sfPtr, x, y);
387     }
388 
389     /**
390      * Update the texture from the contents of a window
391      *
392      * Although the source window can be smaller than the texture, this function
393      * is usually used for updating the whole texture. The other overload, which
394      * has (x, y) additional arguments, is more convenient for updating a
395      * sub-area of the texture.
396      *
397      * No additional check is performed on the size of the window, passing a
398      * window bigger than the texture will lead to an undefined behavior.
399      *
400      * This function does nothing if either the texture or the window
401      * was not previously created.
402      *
403      * Params:
404      *		window = Window to copy to the texture
405      */
406     void update(T)(const(T) window)
407         if(is(T == Window) || is(T == RenderWindow))
408     {
409         update(window, 0, 0);
410     }
411 
412     /**
413      * Update a part of the texture from the contents of a window.
414      *
415      * No additional check is performed on the size of the window, passing an
416      * invalid combination of window size and offset will lead to an undefined
417      * behavior.
418      *
419      * This function does nothing if either the texture or the window was not
420      * previously created.
421      *
422      * Params:
423      *		window = Window to copy to the texture
424      *		x      = X offset in the texture where to copy the source window
425      *		y      = Y offset in the texture where to copy the source window
426      *
427      */
428     void update(T)(const(T) window, uint x, uint y)
429         if(is(T == Window) || is(T == RenderWindow))
430     {
431         static if(is(T == RenderWindow))
432         {
433             sfTexture_updateFromRenderWindow(sfPtr, T.sfPtr, x, y);
434         }
435         else
436         {
437             sfTexture_updateFromWindow(sfPtr, RenderWindow.windowPointer(T),
438                                         x, y);
439         }
440     }
441 
442     /**
443      * Update the texture from an image.
444      *
445      * Although the source image can be smaller than the texture, this function
446      * is usually used for updating the whole texture. The other overload, which
447      * has (x, y) additional arguments, is more convenient for updating a
448      * sub-area of the texture.
449      *
450      * No additional check is performed on the size of the image, passing an
451      * image bigger than the texture will lead to an undefined behaviour.
452      *
453      * This function does nothing if the texture was not previously created.
454      *
455      * Params:
456      * 		image	= Image to copy to the texture.
457      *		y     = Y offset in the texture where to copy the source image.
458      *		x     = X offset in the texture where to copy the source image.
459      */
460     //deprecated("Use update function.")
461     void updateFromImage(Image image, uint x, uint y)
462     {
463         sfTexture_updateFromImage(sfPtr, image.sfPtr, x, y);
464     }
465 
466     /**
467      * Update part of the texture from an array of pixels.
468      *
469      * The size of the pixel array must match the width and height arguments,
470      * and it must contain 32-bits RGBA pixels.
471      *
472      * No additional check is performed on the size of the pixel array or the
473      * bounds of the area to update, passing invalid arguments will lead to an
474      * undefined behaviour.
475      *
476      * This function does nothing if pixels is null or if the texture was not
477      * previously created.
478      *
479      * Params:
480      * 		pixels	= Array of pixels to copy to the texture.
481      * 		width	= Width of the pixel region contained in pixels
482      * 		height	= Height of the pixel region contained in pixels
483      * 		x		= X offset in the texture where to copy the source pixels
484      * 		y		= Y offset in the texture where to copy the source pixels
485      */
486     //deprecated("Use update function.")
487     void updateFromPixels(const(ubyte)[] pixels, uint width, uint height, uint x, uint y)
488     {
489         sfTexture_updateFromPixels(sfPtr,pixels.ptr,width, height, x,y);
490     }
491 
492     //TODO: Get this working via inheritance?(so custom window classes can do it too)
493     /**
494      * Update a part of the texture from the contents of a window.
495      *
496      * No additional check is performed on the size of the window, passing an
497      * invalid combination of window size and offset will lead to an undefined
498      * behaviour.
499      *
500      * This function does nothing if either the texture or the window was not
501      * previously created.
502      *
503      * Params:
504      * 		window	= Window to copy to the texture
505      * 		x		= X offset in the texture where to copy the source window
506      * 		y		= Y offset in the texture where to copy the source window
507      */
508     //deprecated("Use update function.")
509     void updateFromWindow(Window window, uint x, uint y)
510     {
511        // sfTexture_updateFromWindow(sfPtr, RenderWindow.windowPointer(window), x, y);
512     }
513 
514     //Is this even safe? RenderWindow inherits from Window, so what happens? Is this bottom used or the top?
515     /**
516      * Update a part of the texture from the contents of a window.
517      *
518      * No additional check is performed on the size of the window, passing an
519      * invalid combination of window size and offset will lead to an undefined
520      * behaviour.
521      *
522      * This function does nothing if either the texture or the window was not
523      * previously created.
524      *
525      * Params:
526      * 		window	= Window to copy to the texture
527      * 		x		= X offset in the texture where to copy the source window
528      * 		y		= Y offset in the texture where to copy the source window
529      */
530     //deprecated("Use update function.")
531     void updateFromWindow(RenderWindow window, uint x, uint y)
532     {
533        // sfTexture_updateFromRenderWindow(sfPtr, window.sfPtr, x, y);
534     }
535 }