} // Unnamed namespace
-inline ClippingBox RenderAlgorithms::CalculateScreenSpaceAABB( const SceneGraph::RenderItem& item )
-{
- // Calculate extent vector of the AABB:
- const Vector3& actorSize = item.mSize;
- const float halfActorX = actorSize.x * 0.5f;
- const float halfActorY = actorSize.y * 0.5f;
-
- // Transform to absolute oriented bounding box.
- const Matrix& worldMatrix = item.mModelViewMatrix;
-
- // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
- // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
- // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
- // This causes the construction of the vector arrays contents in-place for optimization.
- // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
- // Note: The below * operators trigger a fast (2D) matrix multiply (only 4 multiplications are done).
- Vector2 corners[4]{ worldMatrix * Vector2( -halfActorX, -halfActorY ),
- worldMatrix * Vector2( halfActorX, -halfActorY ),
- worldMatrix * Vector2( halfActorX, halfActorY ) };
-
- // As we are dealing with a rectangle, we can do a fast calculation to get the 4th corner from knowing the other 3 (even if rotated).
- corners[3] = Vector2( corners[0] + ( corners[2] - corners[1] ) );
-
- // Calculate the AABB:
- // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
- // The standard equivalent min/max code of the below would be:
- // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
- // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
- // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
- // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
- unsigned int smallestX = 0u;
- // Loop 3 times to find the index of the smallest X value.
- // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
- for( unsigned int i = 1u; i < 4u; ++i )
- {
- if( corners[i].x < corners[smallestX].x )
- {
- smallestX = i;
- }
- }
-
- // As we are dealing with a rectangle, we can assume opposite corners are the largest.
- // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
- Vector4 aabb( corners[smallestX].x, corners[( smallestX + 3u ) % 4].y, corners[( smallestX + 2u ) % 4].x, corners[( smallestX + 1u ) % 4].y );
-
- // Convert maximums to extents.
- aabb.z -= aabb.x;
- aabb.w -= aabb.y;
-
- // Return the AABB in screen-space pixels (x, y, width, height).
- // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis.
- return ClippingBox( ( mViewportRectangle.width / 2 ) - aabb.z - aabb.x, ( mViewportRectangle.height / 2 ) - aabb.w - aabb.y, aabb.z, aabb.w );
-}
-
+/**
+ * @brief This method is responsible for making decisions on when to apply and unapply scissor clipping, and what rectangular dimensions should be used.
+ * A stack of scissor clips at each depth of clipping is maintained, so it can be applied and unapplied.
+ * As the clips are hierarchical, this RenderItems AABB is clipped against the current "active" scissor bounds via an intersection operation.
+ * @param[in] item The current RenderItem about to be rendered
+ * @param[in] context The context
+ */
inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Context& context )
{
// Get the number of child scissors in the stack (do not include layer or root box).
// We traversed up the tree, we need to apply a new scissor rectangle (unless we are at the root).
traversedUpTree = true;
}
+ else if( clippingNode && childStackDepth > 0u && childStackDepth == scissorDepth ) // case of sibling clip area
+ {
+ mScissorStack.pop_back();
+ }
// If we are on a clipping node, or we have traveled up the tree and gone back past a clipping node, may need to apply a new scissor clip.
if( clippingNode || traversedUpTree )
// This is a clipping node. We generate the AABB for this node and intersect it with the previous intersection further up the tree.
// Get the AABB bounding box for the current render item.
- const ClippingBox scissorBox( CalculateScreenSpaceAABB( item ) );
+ const ClippingBox scissorBox( item.CalculateViewportSpaceAABB( mViewportRectangle.width, mViewportRectangle.height ) );
+
// Get the AABB for the parent item that we must intersect with.
const ClippingBox& parentBox( mScissorStack.back() );
inline void RenderAlgorithms::SetupClipping( const RenderItem& item, Context& context, bool& usedStencilBuffer, uint32_t& lastClippingDepth, uint32_t& lastClippingId )
{
+ RenderMode::Type renderMode = RenderMode::AUTO;
const Renderer *renderer = item.mRenderer;
+ if( renderer )
+ {
+ renderMode = renderer->GetRenderMode();
+ }
// Setup the stencil using either the automatic clipping feature, or, the manual per-renderer stencil API.
// Note: This switch is in order of most likely value first.
- RenderMode::Type renderMode = renderer->GetRenderMode();
switch( renderMode )
{
case RenderMode::AUTO:
}
}
-inline void RenderAlgorithms::ProcessRenderList(
- const RenderList& renderList,
- Context& context,
- BufferIndex bufferIndex,
- const Matrix& viewMatrix,
- const Matrix& projectionMatrix )
+inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
+ Context& context,
+ BufferIndex bufferIndex,
+ const Matrix& viewMatrix,
+ const Matrix& projectionMatrix )
{
DALI_PRINT_RENDER_LIST( renderList );
mScissorStack.push_back( mViewportRectangle );
}
+ // Loop through all RenderList in the RenderList, set up any prerequisites to render them, then perform the render.
for( size_t index( 0u ); index < count; ++index )
{
const RenderItem& item = renderList.GetItem( index );
DALI_PRINT_RENDER_ITEM( item );
- // Set up the depth buffer based on per-renderer flags.
- // If the per renderer flags are set to "ON" or "OFF", they will always override any Layer depth mode or
- // draw-mode state, such as Overlays.
- // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will always
- // disable depth testing and writing. Color Renderers will enable them if the Layer does.
- SetupDepthBuffer( item, context, autoDepthTestMode, firstDepthBufferUse );
-
// Set up clipping based on both the Renderer and Actor APIs.
// The Renderer API will be used if specified. If AUTO, the Actors automatic clipping feature will be used.
SetupClipping( item, context, usedStencilBuffer, lastClippingDepth, lastClippingId );
- // Render the item (we skip rendering for bounding box clips).
- if( item.mNode->GetClippingMode() != ClippingMode::CLIP_TO_BOUNDING_BOX )
+ if( DALI_LIKELY( item.mRenderer ) )
{
+ // Set up the depth buffer based on per-renderer flags.
+ // If the per renderer flags are set to "ON" or "OFF", they will always override any Layer depth mode or
+ // draw-mode state, such as Overlays.
+ // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will always
+ // disable depth testing and writing. Color Renderers will enable them if the Layer does.
+ SetupDepthBuffer( item, context, autoDepthTestMode, firstDepthBufferUse );
+
+ // Render the item.
item.mRenderer->Render( context, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix,
viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque );
}