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 }