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 }