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