1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 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 use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 module dsfml.graphics.rendertexture; 21 22 import dsfml.graphics.rendertarget; 23 import dsfml.graphics.view; 24 import dsfml.graphics.rect; 25 import dsfml.graphics.drawable; 26 import dsfml.graphics.texture; 27 import dsfml.graphics.renderstates; 28 import dsfml.graphics.vertex; 29 import dsfml.graphics.primitivetype; 30 31 import dsfml.graphics.text; 32 import dsfml.graphics.shader; 33 34 import dsfml.graphics.color; 35 36 import dsfml.system.vector2; 37 38 39 import dsfml.system.err; 40 41 /++ 42 + Target for off-screen 2D rendering into a texture. 43 + 44 + RenderTexture is the little brother of RenderWindow. 45 + 46 + It implements the same 2D drawing and OpenGL-related functions (see their base class RenderTarget for more details), the difference is that the result is stored in an off-screen texture rather than being show in a window. 47 + 48 + Rendering to a texture can be useful in a variety of situations: 49 + - precomputing a complex static texture (like a level's background from multiple tiles) 50 + - applying post-effects to the whole scene with shaders 51 + - creating a sprite from a 3D object rendered with OpenGL 52 + - etc. 53 + 54 + Authors: Laurent Gomila, Jeremy DeHaan 55 + See_Also: http://www.sfml-dev.org/documentation/2.0/classsf_1_1RenderTexture.php#details 56 +/ 57 class RenderTexture : RenderTarget 58 { 59 package sfRenderTexture* sfPtr; 60 private Texture m_texture; 61 private View m_currentView, m_defaultView; 62 63 this() 64 { 65 sfPtr = sfRenderTexture_construct(); 66 m_texture = new Texture(sfRenderTexture_getTexture(sfPtr)); 67 m_currentView = new View(); 68 m_defaultView = new View(); 69 } 70 71 ~this() 72 { 73 import dsfml.system.config; 74 mixin(destructorOutput); 75 sfRenderTexture_destroy(sfPtr); 76 } 77 78 /** 79 * Create the render-texture. 80 * 81 * Before calling this function, the render-texture is in an invalid state, thus it is mandatory to call it before doing anything with the render-texture. 82 * 83 * The last parameter, depthBuffer, is useful if you want to use the render-texture for 3D OpenGL rendering that requires a depth-buffer. Otherwise it is unnecessary, and you should leave this parameter to false (which is its default value). 84 * 85 * Params: 86 * width = Width of the render-texture 87 * height = Height of the render-texture 88 * depthBuffer = Do you want this render-texture to have a depth buffer? 89 * 90 */ 91 void create(uint width, uint height, bool depthBuffer = false) 92 { 93 import dsfml.system..string; 94 95 sfRenderTexture_create(sfPtr, width, height, depthBuffer); 96 err.write(dsfml.system..string.toString(sfErr_getOutput())); 97 98 //get view 99 m_currentView = new View(sfRenderTexture_getView(sfPtr)); 100 101 //get default view 102 m_defaultView = new View(sfRenderTexture_getDefaultView(sfPtr)); 103 104 } 105 106 /** 107 * Enable or disable texture smoothing. 108 */ 109 @property 110 { 111 bool smooth(bool newSmooth) 112 { 113 sfRenderTexture_setSmooth(sfPtr, newSmooth); 114 return newSmooth; 115 } 116 bool smooth() 117 { 118 return (sfRenderTexture_isSmooth(sfPtr));//== sfTrue)? true:false; 119 } 120 } 121 122 /** 123 * Change the current active view. 124 * 125 * The view is like a 2D camera, it controls which part of the 2D scene is visible, and how it is viewed in the render-target. The new view will affect everything that is drawn, until another view is set. 126 * 127 * The render target keeps its own copy of the view object, so it is not necessary to keep the original one alive after calling this function. To restore the original view of the target, you can pass the result of getDefaultView() to this function. 128 */ 129 @property 130 { 131 override const(View) view(const(View) newView) 132 { 133 sfRenderTexture_setView(sfPtr, newView.sfPtr); 134 m_currentView = new View(sfRenderTexture_getView(sfPtr)); 135 return m_currentView; 136 } 137 override const(View) view() const 138 { 139 return m_currentView; 140 } 141 } 142 143 /** 144 * Get the default view of the render target. 145 * 146 * The default view has the initial size of the render target, and never changes after the target has been created. 147 * 148 * Returns: The default view of the render target. 149 */ 150 const(View) getDefaultView() const // note: if refactored, change documentation of view property above 151 { 152 return m_defaultView; 153 } 154 155 /** 156 * Return the size of the rendering region of the target. 157 * 158 * Returns: Size in pixels 159 */ 160 Vector2u getSize() const 161 { 162 Vector2u temp; 163 sfRenderTexture_getSize(sfPtr, &temp.x, &temp.y); 164 return temp; 165 } 166 167 /** 168 * Get the viewport of a view, applied to this render target. 169 * 170 * The viewport is defined in the view as a ratio, this function simply applies this ratio to the current dimensions of the render target to calculate the pixels rectangle that the viewport actually covers in the target. 171 * 172 * Params: 173 * view = The view for which we want to compute the viewport 174 * 175 * Returns: Viewport rectangle, expressed in pixels 176 */ 177 IntRect getViewport(const(View) view) const 178 { 179 IntRect temp; 180 sfRenderTexture_getViewport(sfPtr, view.sfPtr, &temp.left, &temp.top, &temp.width, &temp.height); 181 return temp; 182 } 183 184 /** 185 * Get a read-only reference to the target texture. 186 * 187 * After drawing to the render-texture and calling Display, you can retrieve the updated texture using this function, and draw it using a sprite (for example). 188 * 189 * The internal Texture of a render-texture is always the same instance, so that it is possible to call this function once and keep a reference to the texture even after it is modified. 190 * 191 * Returns: Const reference to the texture. 192 */ 193 const(Texture) getTexture() 194 { 195 return m_texture; 196 } 197 198 /** 199 * Activate or deactivate the render-texture for rendering. 200 * 201 * This function makes the render-texture's context current for future OpenGL rendering operations (so you shouldn't care about it if you're not doing direct OpenGL stuff). 202 * 203 * Only one context can be current in a thread, so if you want to draw OpenGL geometry to another render target (like a RenderWindow) don't forget to activate it again. 204 * 205 * Params: 206 * active = True to activate, false to deactivate 207 */ 208 void setActive(bool active = true) 209 { 210 sfRenderTexture_setActive(sfPtr, active); 211 } 212 213 /** 214 * Clear the entire target with a single color. 215 * 216 * This function is usually called once every frame, to clear the previous contents of the target. 217 * 218 * Params: 219 * color = Fill color to use to clear the render target 220 */ 221 void clear(Color color = Color.Black) 222 { 223 sfRenderTexture_clear(sfPtr, color.r,color.g, color.b, color.a); 224 } 225 226 /** 227 * Update the contents of the target texture. 228 * 229 * This function updates the target texture with what has been drawn so far. Like for windows, calling this function is mandatory at the end of rendering. Not calling it may leave the texture in an undefined state. 230 */ 231 void display() 232 { 233 sfRenderTexture_display(sfPtr); 234 } 235 236 /** 237 * Draw a drawable object to the render target. 238 * 239 * Params: 240 * drawable = Object to draw 241 * states = Render states to use for drawing 242 */ 243 override void draw(Drawable drawable, RenderStates states = RenderStates.Default) 244 { 245 //Confirms that even a blank render states struct won't break anything during drawing 246 if(states.texture is null) 247 { 248 states.texture = RenderStates.emptyTexture; 249 } 250 if(states.shader is null) 251 { 252 states.shader = RenderStates.emptyShader; 253 } 254 255 drawable.draw(this, states); 256 } 257 258 /** 259 * Draw primitives defined by an array of vertices. 260 * 261 * Params: 262 * vertices = Array of vertices to draw 263 * type = Type of primitives to draw 264 * states = Render states to use for drawing 265 */ 266 override void draw(const(Vertex)[] vertices, PrimitiveType type, RenderStates states = RenderStates.Default) 267 { 268 import std.algorithm; 269 270 //Confirms that even a blank render states struct won't break anything during drawing 271 if(states.texture is null) 272 { 273 states.texture = RenderStates.emptyTexture; 274 } 275 if(states.shader is null) 276 { 277 states.shader = RenderStates.emptyShader; 278 } 279 280 sfRenderTexture_drawPrimitives(sfPtr, vertices.ptr, cast(uint)min(uint.max, vertices.length),type,states.blendMode, states.transform.m_matrix.ptr, states.texture.sfPtr, states.shader.sfPtr); 281 } 282 283 /** 284 * Convert a point fom target coordinates to world coordinates, using the current view. 285 * 286 * This function is an overload of the mapPixelToCoords function that implicitely uses the current view. 287 * 288 * Params: 289 * point = Pixel to convert 290 * 291 * Returns: The converted point, in "world" coordinates. 292 */ 293 Vector2f mapPixelToCoords(Vector2i point) const 294 { 295 Vector2f temp; 296 sfRenderTexture_mapPixelToCoords(sfPtr,point.x, point.y, &temp.x, &temp.y, null); 297 return temp; 298 } 299 300 /** 301 * Convert a point from target coordinates to world coordinates. 302 * 303 * This function finds the 2D position that matches the given pixel of the render-target. In other words, it does the inverse of what the graphics card does, to find the initial position of a rendered pixel. 304 * 305 * Initially, both coordinate systems (world units and target pixels) match perfectly. But if you define a custom view or resize your render-target, this assertion is not true anymore, ie. a point located at (10, 50) in your render-target may map to the point (150, 75) in your 2D world – if the view is translated by (140, 25). 306 * 307 * For render-windows, this function is typically used to find which point (or object) is located below the mouse cursor. 308 * 309 * This version uses a custom view for calculations, see the other overload of the function if you want to use the current view of the render-target. 310 * 311 * Params: 312 * point = Pixel to convert 313 * view = The view to use for converting the point 314 * 315 * Returns: The converted point, in "world" coordinates. 316 */ 317 Vector2f mapPixelToCoords(Vector2i point, const(View) view) const 318 { 319 Vector2f temp; 320 sfRenderTexture_mapPixelToCoords(sfPtr,point.x, point.y, &temp.x, &temp.y, view.sfPtr); 321 return temp; 322 } 323 324 /** 325 * Convert a point from target coordinates to world coordinates, using the current view. 326 * 327 * This function is an overload of the mapPixelToCoords function that implicitely uses the current view. 328 * 329 * Params: 330 * point = Point to convert 331 * 332 * The converted point, in "world" coordinates 333 */ 334 Vector2i mapCoordsToPixel(Vector2f point) const 335 { 336 Vector2i temp; 337 sfRenderTexture_mapCoordsToPixel(sfPtr,point.x, point.y, &temp.x, &temp.y,null); 338 return temp; 339 } 340 341 /** 342 * Convert a point from world coordinates to target coordinates. 343 * 344 * This function finds the pixel of the render-target that matches the given 2D point. In other words, it goes through the same process as the graphics card, to compute the final position of a rendered point. 345 * 346 * Initially, both coordinate systems (world units and target pixels) match perfectly. But if you define a custom view or resize your render-target, this assertion is not true anymore, ie. a point located at (150, 75) in your 2D world may map to the pixel (10, 50) of your render-target – if the view is translated by (140, 25). 347 * 348 * This version uses a custom view for calculations, see the other overload of the function if you want to use the current view of the render-target. 349 * 350 * Params: 351 * point = Point to convert 352 * view = The view to use for converting the point 353 * 354 * Returns: The converted point, in target coordinates (pixels) 355 */ 356 Vector2i mapCoordsToPixel(Vector2f point, const(View) view) const 357 { 358 Vector2i temp; 359 sfRenderTexture_mapCoordsToPixel(sfPtr,point.x, point.y, &temp.x, &temp.y,view.sfPtr); 360 return temp; 361 } 362 363 /** 364 * Restore the previously saved OpenGL render states and matrices. 365 * 366 * See the description of pushGLStates to get a detailed description of these functions. 367 */ 368 void popGLStates() 369 { 370 sfRenderTexture_popGLStates(sfPtr); 371 } 372 373 /** 374 * Save the current OpenGL render states and matrices. 375 * 376 * This function can be used when you mix SFML drawing and direct OpenGL rendering. Combined with PopGLStates, it ensures that: 377 * - SFML's internal states are not messed up by your OpenGL code 378 * - your OpenGL states are not modified by a call to an SFML function 379 * 380 * More specifically, it must be used around the code that calls Draw functions. 381 * 382 * Note that this function is quite expensive: it saves all the possible OpenGL states and matrices, even the ones you don't care about. Therefore it should be used wisely. It is provided for convenience, but the best results will be achieved if you handle OpenGL states yourself (because you know which states have really changed, and need to be saved and restored). Take a look at the ResetGLStates function if you do so. 383 */ 384 void pushGLStates() 385 { 386 import dsfml.system..string; 387 sfRenderTexture_pushGLStates(sfPtr); 388 err.write(dsfml.system..string.toString(sfErr_getOutput())); 389 } 390 391 /** 392 * Reset the internal OpenGL states so that the target is ready for drawing. 393 * 394 * This function can be used when you mix SFML drawing and direct OpenGL rendering, if you choose not to use pushGLStates/popGLStates. It makes sure that all OpenGL states needed by SFML are set, so that subsequent draw() calls will work as expected. 395 */ 396 void resetGLStates() 397 { 398 sfRenderTexture_resetGLStates(sfPtr); 399 } 400 } 401 402 unittest 403 { 404 version(DSFML_Unittest_Graphics) 405 { 406 import std.stdio; 407 import dsfml.graphics.sprite; 408 409 writeln("Unit tests for RenderTexture"); 410 411 auto renderTexture = new RenderTexture(); 412 413 renderTexture.create(100,100); 414 415 Sprite testSprite = new Sprite();//doesn't need a texture for this unit test 416 417 //clear before doing anything 418 renderTexture.clear(); 419 420 renderTexture.draw(testSprite); 421 422 //prepare the RenderTexture for usage after drawing 423 renderTexture.display(); 424 425 //grab that texture for usage 426 auto texture = renderTexture.getTexture(); 427 428 writeln(); 429 430 } 431 } 432 433 package extern(C) struct sfRenderTexture; 434 435 private extern(C): 436 437 //Construct a new render texture 438 sfRenderTexture* sfRenderTexture_construct(); 439 440 //Construct a new render texture 441 void sfRenderTexture_create(sfRenderTexture* renderTexture, uint width, uint height, bool depthBuffer); 442 443 //Destroy an existing render texture 444 void sfRenderTexture_destroy(sfRenderTexture* renderTexture); 445 446 //Get the size of the rendering region of a render texture 447 void sfRenderTexture_getSize(const sfRenderTexture* renderTexture, uint* x, uint* y); 448 449 //Activate or deactivate a render texture as the current target for rendering 450 bool sfRenderTexture_setActive(sfRenderTexture* renderTexture, bool active); 451 452 //Update the contents of the target texture 453 void sfRenderTexture_display(sfRenderTexture* renderTexture); 454 455 //Clear the rendertexture with the given color 456 void sfRenderTexture_clear(sfRenderTexture* renderTexture, ubyte r, ubyte g, ubyte b, ubyte a); 457 458 //Change the current active view of a render texture 459 void sfRenderTexture_setView(sfRenderTexture* renderTexture, const sfView* view); 460 461 //Get the current active view of a render texture 462 sfView* sfRenderTexture_getView(const sfRenderTexture* renderTexture); 463 464 //Get the default view of a render texture 465 sfView* sfRenderTexture_getDefaultView(const sfRenderTexture* renderTexture); 466 467 //Get the viewport of a view applied to this target 468 void sfRenderTexture_getViewport(const sfRenderTexture* renderTexture, const sfView* view, int* rectLeft, int* rectTop, int* rectWidth, int* rectHeight); 469 470 //Convert a point from texture coordinates to world coordinates 471 void sfRenderTexture_mapPixelToCoords(const sfRenderTexture* renderTexture, int xIn, int yIn, float* xOut, float* yOut, const sfView* targetView); 472 473 //Convert a point from world coordinates to texture coordinates 474 void sfRenderTexture_mapCoordsToPixel(const sfRenderTexture* renderTexture, float xIn, float yIn, int* xOut, int* yOut, const sfView* targetView); 475 476 //Draw a drawable object to the render-target 477 //void sfRenderTexture_drawText(sfRenderTexture* renderTexture, const sfText* object, int blendMode,const float* transform, const sfTexture* texture, const sfShader* shader); 478 479 480 //Draw primitives defined by an array of vertices to a render texture 481 void sfRenderTexture_drawPrimitives(sfRenderTexture* renderTexture, const void* vertices, uint vertexCount, int type, int blendMode,const float* transform, const sfTexture* texture, const sfShader* shader); 482 483 //Save the current OpenGL render states and matrices 484 void sfRenderTexture_pushGLStates(sfRenderTexture* renderTexture); 485 486 //Restore the previously saved OpenGL render states and matrices 487 void sfRenderTexture_popGLStates(sfRenderTexture* renderTexture); 488 489 //Reset the internal OpenGL states so that the target is ready for drawing 490 void sfRenderTexture_resetGLStates(sfRenderTexture* renderTexture); 491 492 //Get the target texture of a render texture 493 sfTexture* sfRenderTexture_getTexture(const sfRenderTexture* renderTexture); 494 495 //Enable or disable the smooth filter on a render texture 496 void sfRenderTexture_setSmooth(sfRenderTexture* renderTexture, bool smooth); 497 498 //Tell whether the smooth filter is enabled or not for a render texture 499 bool sfRenderTexture_isSmooth(const sfRenderTexture* renderTexture); 500 501 502 const(char)* sfErr_getOutput();