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  * There are four global states that can be applied to the drawn objects:
30  * $(UL
31  * $(LI the blend mode: how pixels of the object are blended with the
32  * background)
33  * $(LI the transform: how the object is positioned/rotated/scaled)
34  * $(LI the texture: what image is mapped to the object)
35  * $(LI the shader: what custom effect is applied to the object))
36  *
37  * High-level objects such as sprites or text force some of these states when
38  * they are drawn. For example, a sprite will set its own texture, so that you
39  * don't have to care about it when drawing the sprite.
40  *
41  * The transform is a special case: sprites, texts and shapes (and it's a good
42  * idea to do it with your own drawable classes too) combine their transform
43  * with the one that is passed in the RenderStates structure. So that you can
44  * use a "global" transform on top of each object's transform.
45  *
46  * Most objects, especially high-level drawables, can be drawn directly without
47  * defining render states explicitely – the default set of states is ok in most
48  * cases.
49  * ---
50  * RenderWindow window;
51  * Sprite sprite;
52  *
53  * ...
54  *
55  * window.draw(sprite);
56  * ---
57  *
58  * $(PARA If you want to use a single specific render state, for example a
59  * shader, you can construct a $(U RenderStates) object from it:)
60  * ---
61  * auto states = RenderStates(shader)
62  * window.draw(sprite, states);
63  *
64  * //or
65  * window.draw(sprite, RenderStates(shader));
66  * ---
67  *
68  * $(PARA When you're inside the `draw` function of a drawable object (inherited
69  * from $(DRAWABLE_LINK)), you can either pass the render states unmodified, or
70  * change some of them. For example, a transformable object will combine the
71  * current transform with its own transform. A sprite will set its texture.
72  * Etc.)
73  *
74  * See_Also:
75  * $(RENDERTARGET_LINK), $(DRAWABLE_LINK)
76  */
77 module dsfml.graphics.renderstates;
78 
79 import dsfml.graphics.blendmode;
80 import dsfml.graphics.transform;
81 import dsfml.graphics.texture;
82 import dsfml.graphics.shader;
83 import std.typecons:Rebindable;
84 
85 /**
86  * Define the states used for drawing to a RenderTarget.
87  */
88 struct RenderStates
89 {
90     /// The blending mode.
91     BlendMode blendMode;
92     /// The transform.
93     Transform transform;
94     private
95     {
96         Rebindable!(const(Texture)) m_texture;
97         Rebindable!(const(Shader)) m_shader;
98     }
99 
100     /**
101      * Construct a default set of render states with a custom blend mode.
102      *
103      * Params:
104      *	theBlendMode = Blend mode to use
105      */
106     this(BlendMode theBlendMode)
107     {
108         blendMode = theBlendMode;
109         transform = Transform();
110 
111         m_texture = null;
112         m_shader = null;
113     }
114 
115     /**
116      * Construct a default set of render states with a custom transform.
117      *
118      * Params:
119      *	theTransform = Transform to use
120      */
121     this(Transform theTransform)
122     {
123         transform = theTransform;
124 
125         blendMode = BlendMode.Alpha;
126 
127         m_texture = null;
128         m_shader = null;
129     }
130 
131     /**
132      * Construct a default set of render states with a custom texture
133      *
134      * Params:
135      *	theTexture = Texture to use
136      */
137     this(const(Texture) theTexture)
138     {
139         m_texture = theTexture;
140 
141         blendMode = BlendMode.Alpha;
142 
143         transform = Transform();
144         m_shader = null;
145     }
146 
147     /**
148      * Construct a default set of render states with a custom shader
149      *
150      * Params:
151      * theShader = Shader to use
152      */
153     this(const(Shader) theShader)
154     {
155         m_shader = theShader;
156     }
157 
158     /**
159      * Construct a set of render states with all its attributes
160      *
161      * Params:
162      *	theBlendMode = Blend mode to use
163      *	theTransform = Transform to use
164      *	theTexture   = Texture to use
165      *	theShader    = Shader to use
166      */
167     this(BlendMode theBlendMode, Transform theTransform, const(Texture) theTexture, const(Shader) theShader)
168     {
169         blendMode = theBlendMode;
170         transform = theTransform;
171         m_texture = theTexture;
172         m_shader = theShader;
173     }
174 
175     @property
176     {
177         /// The shader to apply while rendering.
178         const(Shader) shader(const(Shader) theShader)
179         {
180             m_shader = theShader;
181             return theShader;
182         }
183 
184         /// ditto
185         const(Shader) shader() const
186         {
187             return m_shader;
188         }
189     }
190 
191     @property
192     {
193         /// The texture to apply while rendering.
194         const(Texture) texture(const(Texture) theTexture)
195         {
196             m_texture = theTexture;
197             return theTexture;
198         }
199 
200         /// ditto
201         const(Texture) texture() const
202         {
203             return m_texture;
204         }
205     }
206 }