Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I like the idea of using RAII to control OpenGL state, but I'd actually take it one step further: have your <code>WithFoo</code> class constructor take a function pointer as a parameter, which contains the code you want to execute in that context. Then <em>don't</em> create named variables, and just work with temporaries, passing in the action you want to execute in that context as a lambda. (needs C++0x, of course - can work with regular function pointers too but it's not nearly as pretty.)<br> Something like this: <em>(edited to restore exception-safety)</em></p> <pre><code>class WithPushedMatrix { public: WithPushedMatrix() { glPushMatrix(); } ~WithPushedMatrix() { glPopMatrix(); } template &lt;typename Func&gt; void Execute(Func action) { action(); } }; </code></pre> <p>And use it like so:</p> <pre><code>WithPushedMatrix().Execute([] { glBegin(GL_LINES); //etc. etc. }); </code></pre> <p>The temporary object will set up your state, execute the action and then tear it down automatically; you don't have "loose" state variables floating around, and the actions executing under the context become strongly associated with it. You can even nest multiple contextual actions without worrying about destructor order. </p> <p>You can even take this further and make a generic <code>WithContext</code> class that takes additional setup and teardown function parameters. </p> <p><em>edit</em>: Had to move the <code>action()</code> call into a separate <code>Execute</code> function to restore exception-safety - if it's called in the constructor and throws, the destructor won't get called.</p> <h3>edit2: Generic technique -</h3> <p>So I fiddled around with this idea some more, and came up with something better:<br> I'll define a <code>With</code> class, that creates the context variable and stuffs it into a <code>std::auto_ptr</code> in it's initializer, then calls the <code>action</code>:</p> <pre><code>template &lt;typename T&gt; class With { public: template &lt;typename Func&gt; With(Func action) : context(new T()) { action(); } template &lt;typename Func, typename Arg&gt; With(Arg arg, Func action) : context(new T(arg)) { action(); } private: const std::auto_ptr&lt;T&gt; context; }; </code></pre> <p>Now you can combine it with context type that you defined originally:</p> <pre><code>struct PushedMatrix { PushedMatrix() { glPushMatrix(); } ~PushedMatrix() { glPopMatrix(); } }; </code></pre> <p>And use it like this:</p> <pre><code>With&lt;PushedMatrix&gt;([] { glBegin(GL_LINES); //etc. etc. }); </code></pre> <p>or</p> <pre><code>With&lt;EnabledFlag&gt;(GL_BLEND, [] { //... }); </code></pre> <p>Benefits:</p> <ol> <li>Exception-safety is handled by the <code>auto_ptr</code> now, so if <code>action</code> throws, the context will still get destroyed properly. </li> <li>No more need for an <code>Execute</code> method, so it looks clean again! :) </li> <li>Your "context" classes are dead-simple; all of the logic is handled by the <code>With</code> class so you just need to define a simple ctor/dtor for each new type of context. </li> </ol> <p>One niggle: As I've written it above, you need to declare manual overloads for the ctor for as many parameters as you need; although even just one should cover most OpenGL use cases, this isn't really nice. This should be neatly fixed with variadic templates - just replace <code>typename Arg</code> in the ctor with <code>typename ...Args</code> - but it'll depend on compiler support for that (MSVC2010 doesn't have them yet). </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload