+ const uint32_t clippingDepth = node->GetClippingDepth();
+
+ // Pre-calculate a mask which has all bits set up to and including the current clipping depth.
+ // EG. If depth is 3, the mask would be "111" in binary.
+ const uint32_t currentDepthMask = ( 1u << clippingDepth ) - 1u;
+
+ // Are we are writing to the stencil buffer?
+ if( item.mNode->GetClippingMode() == Dali::ClippingMode::CLIP_CHILDREN )
+ {
+ // We are writing to the stencil buffer.
+ // If clipping Id is 1, this is the first clipping renderer within this render-list.
+ if( clippingId == 1u )
+ {
+ // We are enabling the stencil-buffer for the first time within this render list.
+ // Clear the buffer at this point.
+ context.StencilMask( 0xff );
+ context.Clear( GL_STENCIL_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+ }
+ else if( ( clippingDepth < lastClippingDepth ) ||
+ ( ( clippingDepth == lastClippingDepth ) && ( clippingId > lastClippingId ) ) )
+ {
+ // The above if() statement tests if we need to clear some (not all) stencil bit-planes.
+ // We need to do this if either of the following are true:
+ // 1) We traverse up the scene-graph to a previous stencil depth
+ // 2) We are at the same stencil depth but the clipping Id has increased.
+ //
+ // This calculation takes the new depth to move to, and creates an inverse-mask of that number of consecutive bits.
+ // This has the effect of clearing everything except the bit-planes up to (and including) our current depth.
+ const uint32_t stencilClearMask = ( currentDepthMask >> 1u ) ^ 0xff;
+
+ context.StencilMask( stencilClearMask );
+ context.Clear( GL_STENCIL_BUFFER_BIT, Context::CHECK_CACHED_VALUES );
+ }
+
+ // We keep track of the last clipping Id and depth so we can determine when we are
+ // moving back up the scene graph and require some of the stencil bit-planes to be deleted.
+ lastClippingDepth = clippingDepth;
+ lastClippingId = clippingId;
+
+ // We only ever write to bit-planes up to the current depth as we may need
+ // to erase individual bit-planes and revert to a previous clipping area.
+ // Our reference value for testing (in StencilFunc) is written to to the buffer, but we actually
+ // want to test a different value. IE. All the bit-planes up to but not including the current depth.
+ // So we use the Mask parameter of StencilFunc to mask off the top bit-plane when testing.
+ // Here we create our test mask to innore the top bit of the reference test value.
+ // As the mask is made up of contiguous "1" values, we can do this quickly with a bit-shift.
+ const uint32_t testMask = currentDepthMask >> 1u;
+
+ context.StencilFunc( GL_EQUAL, currentDepthMask, testMask ); // Test against existing stencil bit-planes. All must match up to (but not including) this depth.
+ context.StencilMask( currentDepthMask ); // Write to the new stencil bit-plane (the other previous bit-planes are also written to).
+ context.StencilOp( GL_KEEP, GL_REPLACE, GL_REPLACE );