[4.0] Render to Frame Buffer Object.
[platform/core/uifw/dali-core.git] / dali / internal / render / common / render-algorithms.cpp
index 612092c..84df509 100644 (file)
@@ -223,60 +223,13 @@ inline void SetupDepthBuffer( const RenderItem& item, Context& context, bool dep
 } // 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).
@@ -302,6 +255,10 @@ inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Cont
     // 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 )
@@ -312,7 +269,8 @@ inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Cont
       // 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() );
 
@@ -339,11 +297,15 @@ inline void RenderAlgorithms::SetupScissorClipping( const RenderItem& item, Cont
 
 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:
@@ -404,12 +366,11 @@ inline void RenderAlgorithms::SetupClipping( const RenderItem& item, Context& co
   }
 }
 
-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 );
 
@@ -441,25 +402,26 @@ inline void RenderAlgorithms::ProcessRenderList(
     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 );
     }