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