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 RenderTarget) defines the common behaviour of all the 2D render targets
30  * usable in the graphics module. It makes it possible to draw 2D entities like
31  * sprites, shapes, text without using any OpenGL command directly.
32  *
33  * A $(U RenderTarget) is also able to use views which are a kind of 2D cameras.
34  * With views you can globally scroll, rotate or zoom everything that is drawn,
35  * without having to transform every single entity.
36  *
37  * On top of that, render targets are still able to render direct OpenGL stuff.
38  * It is even possible to mix together OpenGL calls and regular DSFML drawing
39  * commands. When doing so, make sure that OpenGL states are not messed up by
40  * calling the `pushGLStates`/`popGLStates` functions.
41  *
42  * See_Also:
43  * $(RENDERWINDOW_LINK), $(RENDERTEXTURE_LINK), $(VIEW_LINK)
44  */
45 module nudsfml.graphics.rendertarget;
46 
47 import bindbc.sfml.graphics;
48 
49 import nudsfml.graphics.renderwindow;
50 import nudsfml.graphics.rendertexture;
51 import nudsfml.graphics.drawable;
52 import nudsfml.graphics.renderstates;
53 
54 import nudsfml.graphics.primitivetype;
55 import nudsfml.graphics.vertex;
56 import nudsfml.graphics.view;
57 import nudsfml.graphics.color;
58 import nudsfml.graphics.rect;
59 
60 import nudsfml.system.vector2;
61 
62 /**
63  * Base interface for all render targets (window, texture, ...).
64  */
65 interface RenderTarget
66 {
67 	@property
68 	{
69 		/**
70 	 	 * The current active view.
71 	 	 *
72 	 	 * The view is like a 2D camera, it controls which part of the 2D scene
73 		 * is visible, and how it is viewed in the render-target. The new view
74 		 * will affect everything that is drawn, until another view is set.
75 	 	 *
76 	 	 * The render target keeps its own copy of the view object, so it is not
77 	 	 * necessary to keep the original one alive after calling this function.
78 		 * To restore the original view of the target, you can pass the result
79 		 * of `getDefaultView()` to this function.
80 	 	 */
81 		View view(View newView);
82 
83 		/// ditto
84 		View view() const;
85 	}
86 
87 	/**
88 	 * Get the default view of the render target.
89 	 *
90 	 * The default view has the initial size of the render target, and never
91 	 * changes after the target has been created.
92 	 *
93 	 * Returns: The default view of the render target.
94 	 */
95 	View getDefaultView() const;
96 
97 	/**
98 	 * Return the size of the rendering region of the target.
99 	 *
100 	 * Returns: Size in pixels.
101 	 */
102 	Vector2u getSize() const;
103 
104 	/**
105 	 * Get the viewport of a view, applied to this render target.
106 	 *
107 	 * The viewport is defined in the view as a ratio, this function simply
108 	 * applies this ratio to the current dimensions of the render target to
109 	 * calculate the pixels rectangle that the viewport actually covers in the
110 	 * target.
111 	 *
112 	 * Params:
113 	 * 		view	= The view for which we want to compute the viewport
114 	 *
115 	 * Returns: Viewport rectangle, expressed in pixels.
116 	 */
117 	final IntRect getViewport(View view) const
118 	{
119 		float width = getSize().x;
120 		float height = getSize().y;
121 
122 		return IntRect(cast(int)(0.5 + width * view.viewport.left),
123 						cast(int)(0.5 + height * view.viewport.top),
124 						cast(int)(0.5 + width * view.viewport.width),
125 						cast(int)(0.5 + height * view.viewport.height));
126 	}
127 
128 	/**
129 	 * Clear the entire target with a single color.
130 	 *
131 	 * This function is usually called once every frame, to clear the previous
132 	 * contents of the target.
133 	 *
134 	 * Params:
135 	 * 		color	= Fill color to use to clear the render target
136 	 */
137 	void clear(Color color = Color.Black);
138 
139 	/**
140 	 * Draw a drawable object to the render target.
141 	 *
142 	 * Params:
143 	 * 		drawable	= Object to draw
144 	 * 		states		= Render states to use for drawing
145 	 */
146 	void draw(Drawable drawable, RenderStates states = RenderStates.init);
147 
148 	/**
149 	 * Draw primitives defined by an array of vertices.
150 	 *
151 	 * Params:
152 	 * 		vertices	= Array of vertices to draw
153 	 * 		type		= Type of primitives to draw
154 	 * 		states		= Render states to use for drawing
155 	 */
156 	void draw(const(Vertex)[] vertices, PrimitiveType type, RenderStates states = RenderStates.init);
157 
158 	/**
159 	 * Convert a point fom target coordinates to world coordinates, using the
160 	 * current view.
161 	 *
162 	 * This function is an overload of the mapPixelToCoords function that
163 	 * implicitely uses the current view.
164 	 *
165 	 * Params:
166 	 * 		point	= Pixel to convert
167 	 *
168 	 * Returns: The converted point, in "world" coordinates.
169 	 */
170 	final Vector2f mapPixelToCoords(Vector2i point) inout
171 	{
172 		return mapPixelToCoords(point, view);
173 	}
174 
175 	/**
176 	 * Convert a point from target coordinates to world coordinates.
177 	 *
178 	 * This function finds the 2D position that matches the given pixel of the
179 	 * render-target. In other words, it does the inverse of what the graphics
180 	 * card does, to find the initial position of a rendered pixel.
181 	 *
182 	 * Initially, both coordinate systems (world units and target pixels) match
183 	 * perfectly. But if you define a custom view or resize your render-target,
184 	 * this assertion is not true anymore, ie. a point located at (10, 50) in
185 	 * your render-target may map to the point (150, 75) in your 2D world – if
186 	 * the view is translated by (140, 25).
187 	 *
188 	 * For render-windows, this function is typically used to find which point
189 	 * (or object) is located below the mouse cursor.
190 	 *
191 	 * This version uses a custom view for calculations, see the other overload
192 	 * of the function if you want to use the current view of the render-target.
193 	 *
194 	 * Params:
195 	 * 		point	= Pixel to convert
196 	 * 		theView	= The view to use for converting the point
197 	 *
198 	 * Returns: The converted point, in "world" coordinates.
199 	 */
200 	final Vector2f mapPixelToCoords(Vector2i point, View theView) inout
201 	{
202 	    // First, convert from viewport coordinates to homogeneous coordinates
203 		Vector2f normalized;
204 
205 		normalized.x = -1.0 + 2.0 * (cast(float)point.x - theView.viewport.left) / theView.viewport.width;
206 		normalized.y = -1.0 + 2.0 * (cast(float)point.y - theView.viewport.top) / theView.viewport.height;
207 
208 	    // Then transform by the inverse of the view matrix
209 		return view.getInverseTransform().transformPoint(normalized);
210 	}
211 
212 	/**
213 	 * Convert a point from target coordinates to world coordinates, using the
214 	 * curtheView.view.
215 	 *
216 	 * This function is an overload of the mapPixelToCoords function that
217 	 * implicitely uses the current view.
218 	 *
219 	 * Params:
220 	 * 		point	= Point to convert
221 	 *
222 	 * Returns: The converted point, in "world" coordinates.
223 	 */
224 	final Vector2i mapCoordsToPixel(Vector2f point) inout
225 	{
226 		return mapCoordsToPixel(point, view);
227 	}
228 
229 	/**
230 	 * Convert a point from world coordinates to target coordinates.
231 	 *
232 	 * This function finds the pixel of the render-target that matches the given
233 	 * 2D point. In other words, it goes through the same process as the
234 	 * graphics card, to compute the final position of a rendered point.
235 	 *
236 	 * Initially, both coordinate systems (world units and target pixels) match
237 	 * perfectly. But if you define a custom view or resize your render-target,
238 	 * this assertion is not true anymore, ie. a point located at (150, 75) in
239 	 * your 2D world may map to the pixel (10, 50) of your render-target – if
240 	 * the view is translated by (140, 25).
241 	 *
242 	 * This version uses a custom view for calculations, see the other overload
243 	 * of the function if you want to use the current view of the render-target.
244 	 *
245 	 * Params:
246 	 * 		point	= Point to convert
247 	 * 		theView	= The view to use for converting the point
248 	 *
249 	 * Returns: The converted point, in target coordinates (pixels).
250 	 */
251 	final Vector2i mapCoordsToPixel(Vector2f point, View theView) inout
252 	{
253 		// First, transform the point by the view matrix
254 		Vector2f normalized = theView.getTransform().transformPoint(point);
255 
256 		// Then convert to viewport coordinates
257 		Vector2i pixel;
258 		pixel.x = cast(int)(( normalized.x + 1.0) / 2.0 * theView.viewport.width  + theView.viewport.left);
259 		pixel.y = cast(int)((-normalized.y + 1.0) / 2.0 * theView.viewport.height + theView.viewport.top);
260 
261 		return pixel;
262 	}
263 
264 	/**
265 	 * Restore the previously saved OpenGL render states and matrices.
266 	 *
267 	 * See the description of `pushGLStates` to get a detailed description of
268 	 * these functions.
269 	 */
270 	void popGLStates();
271 
272 	/**
273      * Save the current OpenGL render states and matrices.
274      *
275      * This function can be used when you mix SFML drawing and direct OpenGL
276      * rendering. Combined with PopGLStates, it ensures that:
277      * $(UL
278      * $(LI DSFML's internal states are not messed up by your OpenGL code)
279      * $(LI your OpenGL states are not modified by a call to an SFML function))
280      *
281      * $(PARA More specifically, it must be used around the code that calls
282      * `draw` functions.
283      *
284      * Note that this function is quite expensive: it saves all the possible
285 	 * OpenGL states and matrices, even the ones you don't care about.Therefore
286 	 * it should be used wisely. It is provided for convenience, but the best
287 	 * results will be achieved if you handle OpenGL states yourself (because
288 	 * you know which states have really changed, and need to be saved and
289 	 * restored). Take a look at the `resetGLStates` function if you do so.)
290      */
291 	void pushGLStates();
292 
293 	/**
294 	 * Reset the internal OpenGL states so that the target is ready for drawing.
295 	 *
296 	 * This function can be used when you mix SFML drawing and direct OpenGL
297 	 * rendering, if you choose not to use `pushGLStates`/`popGLStates`. It
298 	 * makes sure that all OpenGL states needed by SFML are set, so that
299 	 * subsequent `draw()` calls will work as expected.
300 	 */
301 	void resetGLStates();
302 }