*/
// EXTERNAL INCLUDES
+#include <dali/devel-api/actors/actor-devel.h>
+
#include <dali/public-api/dali-core.h>
#include <dali/devel-api/images/texture-set-image.h>
#include <cstdio>
END_TEST;
}
+int UtcDaliRendererRenderOrder2DLayerDepthIndex(void)
+{
+ TestApplication application;
+ tet_infoline("Test the rendering order in a 2D layer is correct using multiple renderers per actor");
+
+ /*
+ * Creates the following hierarchy:
+ *
+ * Layer
+ * / \
+ * / \
+ * / \
+ * / \
+ * / \
+ * actor0 (SIBLING_ORDER:1) actor1 (SIBLING_ORDER:0)
+ * / | \ / | \
+ * / | \ / | \
+ * / | \ / | \
+ * renderer0 renderer1 actor2 renderer2 renderer3 renderer4
+ * |
+ * |
+ * renderer5
+ *
+ * actor0 has sibling order 1
+ * actor1 has sibling order 0
+ * actor2 has sibling order 0
+ *
+ * renderer0 has depth index 2
+ * renderer1 has depth index 0
+ *
+ * renderer2 has depth index 0
+ * renderer3 has depth index 1
+ * renderer4 has depth index 2
+ *
+ * renderer5 has depth index -1
+ *
+ * Expected rendering order: renderer2 - renderer3 - renderer4 - renderer1 - renderer0 - renderer5
+ */
+
+ Shader shader = Shader::New("VertexSource", "FragmentSource");
+ Geometry geometry = CreateQuadGeometry();
+
+ Actor actor0 = Actor::New();
+ actor0.SetAnchorPoint(AnchorPoint::CENTER);
+ actor0.SetParentOrigin(AnchorPoint::CENTER);
+ actor0.SetPosition(0.0f,0.0f);
+ actor0.SetSize(1, 1);
+ actor0.SetProperty( Dali::DevelActor::Property::SIBLING_ORDER, 1 );
+ DALI_TEST_EQUALS( actor0.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 1, TEST_LOCATION );
+ Stage::GetCurrent().Add(actor0);
+
+ Actor actor1 = Actor::New();
+ actor1.SetAnchorPoint(AnchorPoint::CENTER);
+ actor1.SetParentOrigin(AnchorPoint::CENTER);
+ actor1.SetPosition(0.0f,0.0f);
+ actor1.SetSize(1, 1);
+ DALI_TEST_EQUALS( actor1.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 0, TEST_LOCATION );
+ Stage::GetCurrent().Add(actor1);
+
+ Actor actor2 = Actor::New();
+ actor2.SetAnchorPoint(AnchorPoint::CENTER);
+ actor2.SetParentOrigin(AnchorPoint::CENTER);
+ actor2.SetPosition(0.0f,0.0f);
+ actor2.SetSize(1, 1);
+ DALI_TEST_EQUALS( actor1.GetProperty<int>( Dali::DevelActor::Property::SIBLING_ORDER), 0, TEST_LOCATION );
+ actor0.Add(actor2);
+
+ //Renderer0
+ Image image0 = BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet0 = CreateTextureSet( image0 );
+ Renderer renderer0 = Renderer::New( geometry, shader );
+ renderer0.SetTextures( textureSet0 );
+ renderer0.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
+ actor0.AddRenderer(renderer0);
+ application.SendNotification();
+ application.Render(0);
+
+ //Renderer1
+ Image image1= BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet1 = CreateTextureSet( image1 );
+ Renderer renderer1 = Renderer::New( geometry, shader );
+ renderer1.SetTextures( textureSet1 );
+ renderer1.SetProperty( Renderer::Property::DEPTH_INDEX, 0 );
+ actor0.AddRenderer(renderer1);
+ application.SendNotification();
+ application.Render(0);
+
+ //Renderer2
+ Image image2= BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet2 = CreateTextureSet( image2 );
+ Renderer renderer2 = Renderer::New( geometry, shader );
+ renderer2.SetTextures( textureSet2 );
+ renderer2.SetProperty( Renderer::Property::DEPTH_INDEX, 0 );
+ actor1.AddRenderer(renderer2);
+ application.SendNotification();
+ application.Render(0);
+
+ //Renderer3
+ Image image3 = BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet3 = CreateTextureSet( image3 );
+ Renderer renderer3 = Renderer::New( geometry, shader );
+ renderer3.SetTextures( textureSet3 );
+ renderer3.SetProperty( Renderer::Property::DEPTH_INDEX, 1 );
+ actor1.AddRenderer(renderer3);
+ application.SendNotification();
+ application.Render(0);
+
+ //Renderer4
+ Image image4= BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet4 = CreateTextureSet( image4 );
+ Renderer renderer4 = Renderer::New( geometry, shader );
+ renderer4.SetTextures( textureSet4 );
+ renderer4.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
+ actor1.AddRenderer(renderer4);
+ application.SendNotification();
+ application.Render(0);
+
+ //Renderer5
+ Image image5= BufferImage::New( 64, 64, Pixel::RGB888 );
+ TextureSet textureSet5 = CreateTextureSet( image5 );
+ Renderer renderer5 = Renderer::New( geometry, shader );
+ renderer5.SetTextures( textureSet5 );
+ renderer5.SetProperty( Renderer::Property::DEPTH_INDEX, -1 );
+ actor2.AddRenderer(renderer5);
+ application.SendNotification();
+ application.Render(0);
+
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+ gl.EnableTextureCallTrace(true);
+ application.SendNotification();
+ application.Render(0);
+
+ int textureBindIndex[6];
+ for( unsigned int i(0); i<6; ++i )
+ {
+ std::stringstream params;
+ params << GL_TEXTURE_2D<<", "<<i+1;
+ textureBindIndex[i] = gl.GetTextureTrace().FindIndexFromMethodAndParams("BindTexture", params.str() );
+ }
+
+ DALI_TEST_EQUALS( textureBindIndex[2], 0, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureBindIndex[3], 1, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureBindIndex[4], 2, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureBindIndex[1], 3, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureBindIndex[0], 4, TEST_LOCATION );
+ DALI_TEST_EQUALS( textureBindIndex[5], 5, TEST_LOCATION );
+
+ END_TEST;
+}
+
int UtcDaliRendererRenderOrder2DLayerOverlay(void)
{
TestApplication application;
* @note The default value is 'false'
*/
BATCH_PARENT = CLIPPING_MODE + 1,
+ SIBLING_ORDER = CLIPPING_MODE + 2,
};
} // namespace Property
--- /dev/null
+#ifndef DALI_LAYER_DEVEL_H
+#define DALI_LAYER_DEVEL_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+
+namespace Dali
+{
+
+namespace DevelLayer
+{
+
+ /**
+ * @brief TREE_DEPTH_MULTIPLIER is used by the rendering sorting algorithm to decide which actors to render first.
+ * @SINCE_1_0.0
+ */
+ enum TreeDepthMultiplier
+ {
+ TREE_DEPTH_MULTIPLIER = 1000000,
+ };
+
+ /**
+ * @brief SIBLING_ORDER_MULTIPLIER is used by the rendering sorting algorithm to decide which actors to render first.
+ * @SINCE_1_2.16
+ */
+ enum SiblingOrderMultiplier
+ {
+ SIBLING_ORDER_MULTIPLIER = 1000,
+ };
+
+}
+
+}
+
+#endif //DALI_LAYER_DEVEL_H
# Add devel header files here DALi internal developer files used by Adaptor & Toolkit
devel_api_core_actors_header_files = \
- $(devel_api_src_dir)/actors/actor-devel.h
+ $(devel_api_src_dir)/actors/actor-devel.h \
+ $(devel_api_src_dir)/actors/layer-devel.h
devel_api_core_animation_header_files = \
$(devel_api_src_dir)/animation/animation-data.h \
#include <cfloat>
// INTERNAL INCLUDES
+#include <dali/devel-api/actors/layer-devel.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/constants.h>
#include <dali/public-api/events/touch-data.h>
return GetDimensionValue( values.GetVectorXY(), dimension );
}
+unsigned int GetDepthIndex( uint16_t depth, uint16_t siblingOrder )
+{
+ return depth * Dali::DevelLayer::TREE_DEPTH_MULTIPLIER + siblingOrder * Dali::DevelLayer::SIBLING_ORDER_MULTIPLIER;
+}
} // unnamed namespace
mName(),
mId( ++mActorCounter ), // actor ID is initialised to start from 1, and 0 is reserved
mDepth( 0u ),
+ mSiblingOrder(0u),
mIsRoot( ROOT_LAYER == derivedType ),
mIsLayer( LAYER == derivedType || ROOT_LAYER == derivedType ),
mIsOnStage( false ),
mIsOnStage = true;
mDepth = depth;
+ SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
ConnectToSceneGraph();
break;
}
+ case Dali::DevelActor::Property::SIBLING_ORDER:
+ {
+ int value;
+
+ if( property.Get( value ) )
+ {
+ if( static_cast<unsigned int>(value) != mSiblingOrder )
+ {
+ mSiblingOrder = value;
+ if( mIsOnStage )
+ {
+ SetDepthIndexMessage( GetEventThreadServices(), *mNode, GetDepthIndex( mDepth, mSiblingOrder ) );
+ }
+ }
+ }
+ break;
+ }
+
case Dali::Actor::Property::CLIPPING_MODE:
{
ClippingMode::Type convertedValue = mClippingMode;
break;
}
+ case Dali::DevelActor::Property::SIBLING_ORDER:
+ {
+ value = static_cast<int>(mSiblingOrder);
+ break;
+ }
+
case Dali::Actor::Property::CLIPPING_MODE:
{
value = mClippingMode;
std::string mName; ///< Name of the actor
unsigned int mId; ///< A unique ID to identify the actor starting from 1, and 0 is reserved
- unsigned short mDepth :12; ///< Cached: The depth in the hierarchy of the actor. Only 4096 levels of depth are supported
+ uint16_t mDepth; ///< The depth in the hierarchy of the actor. Only 4096 levels of depth are supported
+ uint16_t mSiblingOrder; ///< The sibling order of the actor
+
const bool mIsRoot : 1; ///< Flag to identify the root actor
const bool mIsLayer : 1; ///< Flag to identify that this is a layer
bool mIsOnStage : 1; ///< Flag to identify whether the actor is on-stage
if( !isLayer3d )
{
- item.mDepthIndex += static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER;
+ item.mDepthIndex += renderable.mNode->GetDepthIndex();
}
// Save ModelView matrix onto the item.
* @param[in] currentLayer The current layer containing lists of opaque/transparent renderables.
* @param[in] renderTask The current render-task.
* @param[in] inheritedDrawMode The draw mode of the parent
+ * @param[in] parentDepthIndex The inherited parent node depth index
* @param[in] currentClippingId The current Clipping Id
* Note: ClippingId is passed by reference, so it is permanently modified when traversing back up the tree for uniqueness.
* @param[in] clippingDepth The current clipping depth
mExclusiveRenderTask( NULL ),
mChildren(),
mClippingDepth( 0u ),
+ mDepthIndex( 0u ),
mRegenerateUniformMap( 0 ),
- mDepth( 0u ),
mDirtyFlags( AllFlags ),
mDrawMode( DrawMode::NORMAL ),
mColorMode( DEFAULT_COLOR_MODE ),
DALI_ASSERT_ALWAYS(mParent == NULL);
mParent = &parentNode;
- mDepth = mParent->GetDepth() + 1u;
if( mTransformId != INVALID_TRANSFORM_ID )
{
// Remove back-pointer to parent
mParent = NULL;
- mDepth = 0u;
// Remove all child pointers
mChildren.Clear();
return ( this == rhs );
}
- unsigned short GetDepth() const
- {
- return mDepth;
- }
-
/**
* @brief Turns on or off being a batch parent for the node
* @param[in] enabled If true the node becomes a parent for batch of its children
void SetIsBatchParent( bool enabled );
/**
+ * @brief Sets the sibling order of the node
+ * @param[in] order The new order
+ */
+ void SetDepthIndex( unsigned int depthIndex ){ mDepthIndex = depthIndex; }
+
+ /**
+ * @brief Get the depth index of the node
+ * @return Current depth index
+ */
+ unsigned int GetDepthIndex(){ return mDepthIndex; }
+
+ /**
* @brief Tells if the node is a batch parent
* @return True if node is a batch parent, false otherwise.
*/
CollectedUniformMap mCollectedUniformMap[2]; ///< Uniform maps of the node
unsigned int mUniformMapChanged[2]; ///< Records if the uniform map has been altered this frame
uint32_t mClippingDepth; ///< The number of clipping nodes deep this node is
- unsigned int mRegenerateUniformMap:2; ///< Indicate if the uniform map has to be regenerated this frame
+
+ uint32_t mDepthIndex; ///< Depth index of the node
// flags, compressed to bitfield
- unsigned short mDepth:12; ///< Depth in the hierarchy
+ unsigned int mRegenerateUniformMap:2; ///< Indicate if the uniform map has to be regenerated this frame
int mDirtyFlags:8; ///< A composite set of flags for each of the Node properties
DrawMode::Type mDrawMode:2; ///< How the Node and its children should be drawn
ColorMode mColorMode:2; ///< Determines whether mWorldColor is inherited, 2 bits is enough
new (slot) LocalType( &node, &Node::SetIsBatchParent, isBatchParent );
}
+inline void SetDepthIndexMessage( EventThreadServices& eventThreadServices, const Node& node, unsigned int depthIndex )
+{
+ typedef MessageValue1< Node, unsigned int > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( &node, &Node::SetDepthIndex, depthIndex );
+}
+
inline void SetClippingModeMessage( EventThreadServices& eventThreadServices, const Node& node, ClippingMode::Type clippingMode )
{
typedef MessageValue1< Node, ClippingMode::Type > LocalType;