diff --git a/doc/method-chaining.dox b/doc/method-chaining.dox new file mode 100644 index 000000000..9ed291b49 --- /dev/null +++ b/doc/method-chaining.dox @@ -0,0 +1,66 @@ +namespace Magnum { +/** @page method-chaining Method chaining + +@brief Little feature helping to reduce typing and encourage best practices. + +Method chaining ([Wikipedia](http://en.wikipedia.org/wiki/Method_chaining)) is a +feature which allows you to chain method calls one after another without +repeatedly specifying variable the method is called on. Its primary goal is to +reduce unnecessary repeated names, improving code readability. + +%Magnum uses this feature for configuring OpenGL objects (such as various mesh +and framebuffer options, shader uniforms etc.). Because OpenGL was designed with +"bind-to-modify" approach, most configuration calls need to bind the object +first and only after that change the parameters (unless @extension{EXT,direct_state_access} +extension is available to avoid this). To reduce unneeded bind calls, %Magnum +binds the object only if it is not already bound somewhere. Method chaining +encourages you to configure whole object in one run, effectively reducing the +number of needed bindings. Consider the following example: +@code +Texture2D *carDiffuseTexture, *carSpecularTexture, *carBumpTexture; + +carDiffuseTexture->setStorage(5, Texture2D::InternalFormat::SRGB8); +carSpecularTexture->setStorage(3, Texture2D::InternalFormat::R8); +carBumpTexture->setStorage(5, Texture2D::InternalFormat::RGB8); +carDiffuseTexture->setSubImage(0, {}, diffuse); +carSpecularTexture->setSubImage(0, {}, specular; +carBumpTexture->setSubImage(0, {}, bump); +carDiffuseTexture->generateMipmap(); +carSpecularTexture->generateMipmap(); +carBumpTexture->generateMipmap(); +@endcode + +This code is written that similar configuration steps are grouped together, +which might be good when somebody needs to change something for all three +textures at once, but on the other hand the code is cluttered with repeated +names and after each configuration step the texture must be rebound to another. +With method chaining used the code looks much lighter and each object is +configured in one run, reducing count of bind calls from 9 to 3. +@code +carDiffuseTexture->setStorage(5, Texture2D::InternalFormat::SRGB8) + ->setSubImage(0, {}, diffuse) + ->generateMipmap(); +carSpecularTexture->setStorage(3, Texture2D::InternalFormat::R8) + ->setSubImage(0, {}, diffuse) + ->generateMipmap(); +carBumpTexture->setStorage(5, Texture2D::InternalFormat::RGB8) + ->setSubImage(0, {}, bump) + ->generateMipmap(); +@endcode + +Method chaining is not used on non-configuring functions, such as Framebuffer::clear() +or Mesh::draw(), as these won't be commonly used in conjunction with other +functions anyway. + +Method chaining is also used in SceneGraph and other libraries and in some cases +it allows you to just "configure and forget" without even saving the created +object to some variable, for example when adding static object to an scene: +@code +Scene3D scene; + +(new MyObject(&scene)) + ->rotateX(90.0_degf) + ->translate({-1.5f, 0.5f, 7.0f}); +@endcode +*/ +} diff --git a/doc/tips.dox b/doc/tips.dox index 85e0d6ad4..88800e65d 100644 --- a/doc/tips.dox +++ b/doc/tips.dox @@ -2,8 +2,9 @@ namespace Magnum { /** @page tips Tips and tricks @brief Hints for better productivity and performance. -- @subpage portability - @copybrief portability -- @subpage best-practices - @copybrief best-practices -- @subpage compilation-speedup - @copybrief compilation-speedup +- @subpage method-chaining -- @copybrief method-chaining +- @subpage portability -- @copybrief portability +- @subpage best-practices -- @copybrief best-practices +- @subpage compilation-speedup -- @copybrief compilation-speedup */ }