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 }