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 RenderTexture) is the little brother of $(RENDERWINDOW_LINK). It 30 * implements the same 2D drawing and OpenGL-related functions (see their base 31 * class $(RENDERTARGET_LINK) for more details), the difference is that the 32 * result is stored in an off-screen texture rather than being show in a window. 33 * 34 * Rendering to a texture can be useful in a variety of situations: 35 * $(UL 36 * $(LI precomputing a complex static texture (like a level's background from 37 * multiple tiles)) 38 * $(LI applying post-effects to the whole scene with shaders) 39 * $(LI creating a sprite from a 3D object rendered with OpenGL) 40 * $(LI etc.)) 41 * 42 * Example: 43 * --- 44 * // Create a new render-window 45 * auto window = new RenderWindow(VideoMode(800, 600), "DSFML window"); 46 * 47 * // Create a new render-texture 48 * auto texture = new RenderTexture(); 49 * if (!texture.create(500, 500)) 50 * return -1; 51 * 52 * // The main loop 53 * while (window.isOpen()) 54 * { 55 * // Event processing 56 * // ... 57 * 58 * // Clear the whole texture with red color 59 * texture.clear(Color.Red); 60 * 61 * // Draw stuff to the texture 62 * texture.draw(sprite); 63 * texture.draw(shape); 64 * texture.draw(text); 65 * 66 * // We're done drawing to the texture 67 * texture.display(); 68 * 69 * // Now we start rendering to the window, clear it first 70 * window.clear(); 71 * 72 * // Draw the texture 73 * auto sprite = new Sprite(texture.getTexture()); 74 * window.draw(sprite); 75 * 76 * // End the current frame and display its contents on screen 77 * window.display(); 78 * } 79 * --- 80 * 81 * $(PARA Like $(RENDERWINDOW_LINK), $(U RenderTexture) is still able to render 82 * direct OpenGL stuff. It is even possible to mix together OpenGL calls and 83 * regular DSFML drawing commands. If you need a depth buffer for 3D rendering, 84 * don't forget to request it when calling `RenderTexture.create`.) 85 * 86 * See_Also: 87 * $(RENDERTARGET_LINK), $(RENDERWINDOW_LINK), $(VIEW_LINK), $(TEXTURE_LINK) 88 */ 89 module dsfml.graphics.rendertexture; 90 91 import dsfml.graphics.color; 92 import dsfml.graphics.drawable; 93 import dsfml.graphics.primitivetype; 94 import dsfml.graphics.rect; 95 import dsfml.graphics.renderstates; 96 import dsfml.graphics.rendertarget; 97 import dsfml.graphics.shader; 98 import dsfml.graphics.text; 99 import dsfml.graphics.texture; 100 import dsfml.graphics.vertex; 101 import dsfml.graphics.view; 102 103 import dsfml.system.err; 104 import dsfml.system.vector2; 105 106 /** 107 * Target for off-screen 2D rendering into a texture. 108 */ 109 class RenderTexture : RenderTarget 110 { 111 package sfRenderTexture* sfPtr; 112 private Texture m_texture; 113 private View m_currentView, m_defaultView; 114 115 /// Default constructor. 116 this() 117 { 118 sfPtr = sfRenderTexture_construct(); 119 m_texture = new Texture(sfRenderTexture_getTexture(sfPtr)); 120 } 121 122 /// Desructor. 123 ~this() 124 { 125 import dsfml.system.config; 126 mixin(destructorOutput); 127 sfRenderTexture_destroy(sfPtr); 128 } 129 130 /** 131 * Create the render-texture. 132 * 133 * Before calling this function, the render-texture is in an invalid state, 134 * thus it is mandatory to call it before doing anything with the 135 * render-texture. 136 * 137 * The last parameter, depthBuffer, is useful if you want to use the 138 * render-texture for 3D OpenGL rendering that requires a depth-buffer. 139 * Otherwise it is unnecessary, and you should leave this parameter to false 140 * (which is its default value). 141 * 142 * Params: 143 * width = Width of the render-texture 144 * height = Height of the render-texture 145 * depthBuffer = Do you want this render-texture to have a depth buffer? 146 * 147 * Returns: True if creation has been successful. 148 */ 149 bool create(uint width, uint height, bool depthBuffer = false) 150 { 151 return sfRenderTexture_create(sfPtr, width, height, depthBuffer); 152 } 153 154 @property 155 { 156 /** 157 * Enable or disable texture smoothing. 158 */ 159 bool smooth(bool newSmooth) 160 { 161 sfRenderTexture_setSmooth(sfPtr, newSmooth); 162 return newSmooth; 163 } 164 165 /// ditto 166 bool smooth() const 167 { 168 return (sfRenderTexture_isSmooth(sfPtr)); 169 } 170 } 171 172 @property 173 { 174 /** 175 * Change the current active view. 176 * 177 * The view is like a 2D camera, it controls which part of the 2D scene 178 * is visible, and how it is viewed in the render-target. The new view 179 * will affect everything that is drawn, until another view is set. 180 * 181 * The render target keeps its own copy of the view object, so it is not 182 * necessary to keep the original one alive after calling this function. 183 * To restore the original view of the target, you can pass the result 184 * of `getDefaultView()` to this function. 185 */ 186 override View view(View newView) 187 { 188 sfRenderTexture_setView(sfPtr, newView.center.x, newView.center.y, newView.size.x, newView.size.y, newView.rotation, 189 newView.viewport.left, newView.viewport.top, newView.viewport.width, newView.viewport.height); 190 return newView; 191 } 192 193 /// ditto 194 override View view() const 195 { 196 View currentView; 197 198 Vector2f currentCenter, currentSize; 199 float currentRotation; 200 FloatRect currentViewport; 201 202 sfRenderTexture_getView(sfPtr, ¤tCenter.x, ¤tCenter.y, ¤tSize.x, ¤tSize.y, ¤tRotation, 203 ¤tViewport.left, ¤tViewport.top, ¤tViewport.width, ¤tViewport.height); 204 205 currentView.center = currentCenter; 206 currentView.size = currentSize; 207 currentView.rotation = currentRotation; 208 currentView.viewport = currentViewport; 209 210 return currentView; 211 } 212 } 213 214 /** 215 * Get the default view of the render target. 216 * 217 * The default view has the initial size of the render target, and never 218 * changes after the target has been created. 219 * 220 * Returns: The default view of the render target. 221 */ 222 View getDefaultView() const 223 { 224 View currentView; 225 226 Vector2f currentCenter, currentSize; 227 float currentRotation; 228 FloatRect currentViewport; 229 230 sfRenderTexture_getDefaultView(sfPtr, ¤tCenter.x, ¤tCenter.y, ¤tSize.x, ¤tSize.y, ¤tRotation, 231 ¤tViewport.left, ¤tViewport.top, ¤tViewport.width, ¤tViewport.height); 232 233 currentView.center = currentCenter; 234 currentView.size = currentSize; 235 currentView.rotation = currentRotation; 236 currentView.viewport = currentViewport; 237 238 return currentView; 239 } 240 241 /** 242 * Return the size of the rendering region of the target. 243 * 244 * Returns: Size in pixels. 245 */ 246 Vector2u getSize() const 247 { 248 Vector2u temp; 249 sfRenderTexture_getSize(sfPtr, &temp.x, &temp.y); 250 return temp; 251 } 252 253 /** 254 * Get a read-only reference to the target texture. 255 * 256 * After drawing to the render-texture and calling Display, you can retrieve 257 * the updated texture using this function, and draw it using a sprite 258 * (for example). 259 * 260 * The internal Texture of a render-texture is always the same instance, so 261 * that it is possible to call this function once and keep a reference to 262 * the texture even after it is modified. 263 * 264 * Returns: Const reference to the texture. 265 */ 266 const(Texture) getTexture() const 267 { 268 return m_texture; 269 } 270 271 /** 272 * Activate or deactivate the render-texture for rendering. 273 * 274 * This function makes the render-texture's context current for future 275 * OpenGL rendering operations (so you shouldn't care about it if you're not 276 * doing direct OpenGL stuff). 277 * 278 * Only one context can be current in a thread, so if you want to draw 279 * OpenGL geometry to another render target (like a $(RENDERWINDOW_LINK)) 280 * don't forget to activate it again. 281 * 282 * Params: 283 * active = true to activate, false to deactivate 284 */ 285 void setActive(bool active = true) 286 { 287 sfRenderTexture_setActive(sfPtr, active); 288 } 289 290 /** 291 * Clear the entire target with a single color. 292 * 293 * This function is usually called once every frame, to clear the previous 294 * contents of the target. 295 * 296 * Params: 297 * color = Fill color to use to clear the render target 298 */ 299 void clear(Color color = Color.Black) 300 { 301 sfRenderTexture_clear(sfPtr, color.r,color.g, color.b, color.a); 302 } 303 304 /** 305 * Update the contents of the target texture. 306 * 307 * This function updates the target texture with what has been drawn so far. 308 * Like for windows, calling this function is mandatory at the end of 309 * rendering. Not calling it may leave the texture in an undefined state. 310 */ 311 void display() 312 { 313 sfRenderTexture_display(sfPtr); 314 } 315 316 /** 317 * Draw a drawable object to the render target. 318 * 319 * Params: 320 * drawable = Object to draw 321 * states = Render states to use for drawing 322 */ 323 override void draw(Drawable drawable, RenderStates states = RenderStates.init) 324 { 325 drawable.draw(this, states); 326 } 327 328 /** 329 * Draw primitives defined by an array of vertices. 330 * 331 * Params: 332 * vertices = Array of vertices to draw 333 * type = Type of primitives to draw 334 * states = Render states to use for drawing 335 */ 336 override void draw(const(Vertex)[] vertices, PrimitiveType type, RenderStates states = RenderStates.init) 337 { 338 import std.algorithm; 339 340 sfRenderTexture_drawPrimitives(sfPtr, vertices.ptr, cast(uint)min(uint.max, vertices.length),type,states.blendMode.colorSrcFactor, states.blendMode.alphaDstFactor, 341 states.blendMode.colorEquation, states.blendMode.alphaSrcFactor, states.blendMode.alphaDstFactor, states.blendMode.alphaEquation, 342 states.transform.m_matrix.ptr, states.texture?states.texture.sfPtr:null, states.shader?states.shader.sfPtr:null); 343 } 344 345 /** 346 * Restore the previously saved OpenGL render states and matrices. 347 * 348 * See the description of pushGLStates to get a detailed description of 349 * these functions. 350 */ 351 void popGLStates() 352 { 353 sfRenderTexture_popGLStates(sfPtr); 354 } 355 356 /** 357 * Save the current OpenGL render states and matrices. 358 * 359 * This function can be used when you mix SFML drawing and direct OpenGL 360 * rendering. Combined with PopGLStates, it ensures that: 361 * $(UL 362 * $(LI DSFML's internal states are not messed up by your OpenGL code) 363 * $(LI your OpenGL states are not modified by a call to an SFML function)) 364 * 365 * $(PARA More specifically, it must be used around the code that calls 366 * `draw` functions. 367 * 368 * Note that this function is quite expensive: it saves all the possible 369 * OpenGL states and matrices, even the ones you don't care about.Therefore 370 * it should be used wisely. It is provided for convenience, but the best 371 * results will be achieved if you handle OpenGL states yourself (because 372 * you know which states have really changed, and need to be saved and 373 * restored). Take a look at the `resetGLStates` function if you do so.) 374 */ 375 void pushGLStates() 376 { 377 sfRenderTexture_pushGLStates(sfPtr); 378 } 379 380 /** 381 * Reset the internal OpenGL states so that the target is ready for drawing. 382 * 383 * This function can be used when you mix DSFML drawing and direct OpenGL 384 * rendering, if you choose not to use pushGLStates/popGLStates. It makes 385 * sure that all OpenGL states needed by DSFML are set, so that subsequent 386 * `draw()` calls will work as expected. 387 */ 388 void resetGLStates() 389 { 390 sfRenderTexture_resetGLStates(sfPtr); 391 } 392 } 393 394 unittest 395 { 396 version(DSFML_Unittest_Graphics) 397 { 398 import std.stdio; 399 import dsfml.graphics.sprite; 400 401 writeln("Unit tests for RenderTexture"); 402 403 auto renderTexture = new RenderTexture(); 404 405 renderTexture.create(100,100); 406 407 //doesn't need a texture for this unit test 408 Sprite testSprite = new Sprite(); 409 410 //clear before doing anything 411 renderTexture.clear(); 412 413 renderTexture.draw(testSprite); 414 415 //prepare the RenderTexture for usage after drawing 416 renderTexture.display(); 417 418 //grab that texture for usage 419 auto texture = renderTexture.getTexture(); 420 421 writeln(); 422 } 423 } 424 425 package extern(C) struct sfRenderTexture; 426 427 private extern(C): 428 429 //Construct a new render texture 430 sfRenderTexture* sfRenderTexture_construct(); 431 432 //Construct a new render texture 433 bool sfRenderTexture_create(sfRenderTexture* renderTexture, uint width, uint height, bool depthBuffer); 434 435 //Destroy an existing render texture 436 void sfRenderTexture_destroy(sfRenderTexture* renderTexture); 437 438 //Get the size of the rendering region of a render texture 439 void sfRenderTexture_getSize(const sfRenderTexture* renderTexture, uint* x, uint* y); 440 441 //Activate or deactivate a render texture as the current target for rendering 442 bool sfRenderTexture_setActive(sfRenderTexture* renderTexture, bool active); 443 444 //Update the contents of the target texture 445 void sfRenderTexture_display(sfRenderTexture* renderTexture); 446 447 //Clear the rendertexture with the given color 448 void sfRenderTexture_clear(sfRenderTexture* renderTexture, ubyte r, ubyte g, ubyte b, ubyte a); 449 450 //Change the current active view of a render texture 451 void sfRenderTexture_setView(sfRenderTexture* renderTexture, float centerX, float centerY, float sizeX, 452 float sizeY, float rotation, float viewportLeft, float viewportTop, float viewportWidth, 453 float viewportHeight); 454 455 //Get the current active view of a render texture 456 void sfRenderTexture_getView(const sfRenderTexture* renderTexture, float* centerX, float* centerY, float* sizeX, 457 float* sizeY, float* rotation, float* viewportLeft, float* viewportTop, float* viewportWidth, 458 float* viewportHeight); 459 460 //Get the default view of a render texture 461 void sfRenderTexture_getDefaultView(const sfRenderTexture* renderTexture, float* centerX, float* centerY, float* sizeX, 462 float* sizeY, float* rotation, float* viewportLeft, float* viewportTop, float* viewportWidth, 463 float* viewportHeight); 464 465 //Draw primitives defined by an array of vertices to a render texture 466 void sfRenderTexture_drawPrimitives(sfRenderTexture* renderTexture, const void* vertices, uint vertexCount, int type, int colorSrcFactor, int colorDstFactor, int colorEquation, 467 int alphaSrcFactor, int alphaDstFactor, int alphaEquation, const float* transform, const sfTexture* texture, const sfShader* shader); 468 469 //Save the current OpenGL render states and matrices 470 void sfRenderTexture_pushGLStates(sfRenderTexture* renderTexture); 471 472 //Restore the previously saved OpenGL render states and matrices 473 void sfRenderTexture_popGLStates(sfRenderTexture* renderTexture); 474 475 //Reset the internal OpenGL states so that the target is ready for drawing 476 void sfRenderTexture_resetGLStates(sfRenderTexture* renderTexture); 477 478 //Get the target texture of a render texture 479 sfTexture* sfRenderTexture_getTexture(const sfRenderTexture* renderTexture); 480 481 //Enable or disable the smooth filter on a render texture 482 void sfRenderTexture_setSmooth(sfRenderTexture* renderTexture, bool smooth); 483 484 //Tell whether the smooth filter is enabled or not for a render texture 485 bool sfRenderTexture_isSmooth(const sfRenderTexture* renderTexture);