Skip to main content

3D Scenes and Nodes

Chapters


Example Solutions

    NodeManipulationSolution_3D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes SceneGraphDynamicsSolution_3D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes ShaderParameterSetterSolution in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes VertexGeometryBuilderSolution in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes
    3D Scenes and Nodes
    Scenes and Nodes

    Candera::Node is an abstract base class for all scene graph nodes.

    drawing-4-1676880912.png

    Each node defines a local coordinate system relative to the coordinate system of the parent node. The functionality to define the local coordinate system is derived from Candera::Transformable and consists of following components:

    • position,
    • rotation,
    • scale,
    • and a generic matrix called transform matrix.

    If the node is transformed from the local coordinate system to the world's coordinate system, then the node's local transformation is multiplied with all its parent's transformations. A node can also store a set of nodes as its children but a node can only have one parent at a time. Cycles are prohibited. The nodes alpha value is multiplied with the alpha value of its descendent nodes.

    Candera::Scene is the top level scene node which cannot be part of any other node.

    Back to the Chapter menu


    3D Node Transformations
    3D Node Manipulation Example

    To illustrate basic node transformation operations, the NodeManipulationWidget_3D and the DisplayPositionWidget3D part of the Tutorial Widgets can be used. An usage example for NodeManipulationWidget_3D widget is presented in NodeManipulationSolution_3D solution provided in the content folder of cgi_studio_player.

    Please consider:

      The widget property Node is derived from a base class and provides the node associated to the widget (e.g. the root node for content managed by the widget). Only if the widget is enabled (this property is also derived from a base class), the setter methods of the widget properties will take effect. If a widget property setter changes a node property of the associated node, the visual effect can be seen, but note that the static node properties maintained by SceneComposer are not changed accordingly! Widget dynamics are never reflected to static scene structure. It is recommended to use SceneComposer only for property configuration and dynamics only in the Player.
      Translations

      Once the NodeManipulationWidget_3D is linked to a node from the static scene tree and enabled, the position coordinates can be set in the Player for this property to change the position.

              // Set node position
              node->SetPosition(m_position);
              // end Set node position
      

      Use TranslateX property to move the node on the x axis with a delta value only. Candera::Transformable::Translate adds the given Vector to the actual position .

             // Translate node on x axis
              node->Translate(Vector3(m_translateX, 0.0F, 0.0F));
              // end Translate node on x axis
      
      Rotations

      Similar to translation, rotation can also be applied via Candera::Transformable::SetRotation() or Candera::Transformable::Rotate().

              // Set node rotation
              node->SetRotation(m_rotation);
              // end Set node rotation
      
      Scaling

      Again there is also a Candera::Transformable::SetScale and Candera::Transformable::Scale method.

              // set node scale
              node->SetScale(m_scale);
              // end node scale
      
      Pivot Point

      It is possible to change your pivot point with the Candera::Transformable::TranslatePivotPoint (or Candera::Transformable::SetPivotPoint) method. The pivot point can be used to define e.g. the rotation point that the node should rotate around. It affects the scaling too.

      How to get the screen space coordinates of a node

      With the DisplayPositionWidget3D you can retrieve the screen coordinates of an associated node. Please consider that a node and a camera have to be selected in the widget. In the solution the widget is disabled by default. To see the output of the node's display position, enabling the widget and log filter (via CgiAppLog -> Info) in SceneComposer is mandatory. To get the screen space coordinates of an associated node you need the function Candera::Math3D::TransformPointToScreen, which transforms a point in world space into a point in screen space.

        First you need the world position of your node. With Node::GetWorldPosition you get the screen coordinates as output.
                Vector3 worldPosition = node->GetWorldPosition();
        
        With the world position of your node and with your camera you can transform the point to screen space and you retrieve the display position as a Candera::Vector2.
                Vector2 displayPos;
                static_cast<void>(Math3D::TransformPointToScreen(worldPosition, camera, displayPos));
        
        displayPos now contains the X and Y screen space coordinates of the selected node.

        Back to the Chapter menu


        3D Node Appearance
        Description

        Candera::Appearance groups following render attributes:

        Render attributes define the distinctive visualization of a geometry like Candera::Mesh, Candera::Billboard, and Candera::PointSprite. Further, render attributes can be shared across multiple objects, which conserve memory and enable sharing of appearance characteristics.

        A Candera::Appearance object is mandatory for any object in order to get rendered. Per default no Appearance attributes are attached.

        If the Appearance is activated, all render attributes that are set become activated. If no RenderMode is defined (null), then the default RenderMode is used instead.

        Chapters


        Appearance: Material
        Material Attributes

        Candera::Material describes the color attributes of an object's surface and is primarily used for lighting computations. If no material is set, lighting calculations in associated shaders can not be applied.

        The color attributes are defined as follows:

        Ambient RGB color that interacts with the ambient attribute of light. Emissive RGB color that defines the self-lighting of the material. This color is visible, even when Material is unlighted.
        The emissive color attribute does neither interact with any type of light source nor with other 3D objects. Diffuse RGBA color that interacts with the diffuse attribute of light. The alpha value of the diffuse color, defines
        the alpha factor of the entire Material, supposed that alpha blending is enabled (For details see Candera::RenderMode). Specular RGB color that interacts with the specular attribute of light.

        Furthermore with Specular Power the sharpness of a specular highlight, if lit by specular light, can be defined.

        Create a new Material
            m_material = Material::Create();
        
        Set Colors

        This sample code shows how to change the ambient color, the code for changing the diffuse color, the emissive color or the specular color looks similarly.

            // Set ambient color
            if (node->GetAppearance() != 0 && node->GetAppearance()->GetMaterial() != 0){
                node->GetAppearance()->GetMaterial()->SetAmbient(m_color);
            }
            // end Set ambient color
        

        Back to the sub chart menu


        Appearance: Texture 
        Description

        Candera::Texture encapsulates a Candera::TextureImage and a set of attributes specifying how it is applied to a vertex's texture coordinate. Candera implements a sharing mechanism based on TextureImages. These hold the actual VRAM handle. Multiple textures can share one TextureImage object. The TextureImage manages its upload to the VRAM.

        Attention:

          The Texture is only useable with an associated TextureImage. Do not share TextureImages, if TextureImage modification shall not be shared across Textures. In order to support MipMapping or repeated wrapping, the bitmap's width and height must be a power of 2 (n^2), like e.g. 2, 4, 8, 16 ,32, etc. However, height and width can be different, e.g.: 256x128.
          Texture Filtering
            Minification and magnification:

            Following texture filters can be used to improve visual quality of Textures: Magnification to upscale, Minification to downscale.

            Nearest Value of the texel that is nearest to the center of the pixel being textured. Linear The weighted average of the four texels that are closest to the center of the pixel being textured.


              Mipmapping: MipMapping can be used to avoid texture aliasing effects.
              None MipMapping disabled Nearest MipMapping uses nearest mip map level Linear MipMapping uses bilinear mipmap interpolation of the two nearest mip map levels


                WrapMode:

                It specifies how the texture is wrapped:

                Repeat Repeat the texture ClampToEdge Clamp fetches to the edge of the texture Linear MipMapping uses bilinear mipmap interpolation of the two nearest mip map levels


                  MaxAnisotropy:

                  It specifies the maximum degree of anisotropy to account for in texture filtering for the Texture object. Anisotropic filtering improves the quality of the textures when they are not uniformly scaled because, for example, the textured triangle is not exactly facing the camera. The value of maxAnisotropy must be greater or equal to 1.0f (isotropy) and is limited by the max detail of anisotropy supported by hardware, which can be retrieved with the function Candera::RenderDevice::GetMaxAnisotropySupportedByDevice.

                  Changing Texture Image And Setting Filters
                      m_textureImage = BitmapTextureImage::Create();
                      m_textureImage->SetName("LabelTextureImage");
                      static_cast<void>(m_textureImage->SetBitmap(m_bitmap));
                      if (m_textureImage == 0) {
                          FEATSTD_DEBUG_ASSERT(false);
                          return; // memory is freed in destructor/UpdateBitmap()
                      }
                  
                  
                      m_texture = Texture::Create();
                      m_texture->SetName("LabelTexture");
                      m_texture->SetTextureImage(m_textureImage);
                      m_texture->SetWrapModeU(Texture::ClampToEdge);
                      m_texture->SetWrapModeV(Texture::ClampToEdge);
                      m_texture->SetMinificationFilter(Texture::MinMagLinear);
                      m_texture->SetMagnificationFilter(Texture::MinMagLinear);
                  

                  Back to the sub chart menu


                  Appearance: Render Mode 
                  Description

                  Candera::RenderMode is an Appearance component that encapsulates polygon-level and per-fragment compositing render attributes. If an object's Appearance has set RenderMode to null, then the default RenderMode is used instead. For details how to set the default render mode, see Candera::Renderer::SetDefaultRenderMode.

                  If a Camera has a RenderMode attached [camera->GetApperance()->SetRenderMode(...)], then the Camera's RenderMode overrules the DefaultRenderMode during its render pass. Thus, all Nodes rendered by the Camera that do not have their own RenderMode set, use the RenderMode applied to the Camera.

                  If a RenderMode has set an inheritance bit for a certain render attribute, then the property of the base render mode is used, this is either the Camera's RenderMode if set or the DefaultRenderMode otherwise.

                          bool m_isColorWriteRedEnabled;       // Default value: true
                          bool m_isColorWriteGreenEnabled;     // Default value: true
                          bool m_isColorWriteBlueEnabled;      // Default value: true
                          bool m_isColorWriteAlphaEnabled;     // Default value: true
                          bool m_isDepthWriteEnabled;          // Default value: true
                          bool m_isDepthTestEnabled;           // Default value: true
                          bool m_isStencilTestEnabled;         // Default value: false
                          bool m_isBlendingEnabled;            // Default value: false
                  


                  Set a rendermode:

                      SharedPointer<RenderMode> rm = RenderMode::Create();
                      rm->SetBlendingEnabled(true);
                      rm->SetBlendMode(RenderMode::SourceAlpha, RenderMode::InverseSourceAlpha, RenderMode::Add);
                      rm->SetDepthTestEnabled(false);
                      rm->SetDepthWriteEnabled(false);
                      appearance->SetRenderMode(rm);
                  
                  
                  Render Mode Attributes
                    blending 

                    The next chapter Color Blending describes possible blending operations in detail.

                      culling 

                      Culling determines which side of a polygon is removed before rasterisation.

                      FrontFaceCulling Front of the polygon is removed BackFaceCulling Back of the polygon is removed NoCulling Front and back of the polygon are rendered
                        winding 

                        Winding defines the front face of a polygon. A polygon side is the front-face if its screen-space vertices are in the same order as the winding specifies.

                        ClockWise Clockwise ordered vertices define the front of the polygon. CounterClockWise Counterclockwise ordered vertices define the front of the polygon.

                        Candera::RenderMode::ComparisonFunction can be used with depth-, stencil-, or sampler state operations. It specifies how the source (new) data is compared against the destination (existing) data before passing the comparison operations (storing the data).

                        CompareNever Never pass the comparison. CompareLess If source data is less than destination data, the comparison passes. CompareEqual If source data is equal than destination data, the comparison passes. CompareLessEqual If source data is less than or equal to destination data, the comparison passes. CompareGreater If source data is greater than destination data, the comparison passes. CompareNotEqual If source data is not equal to destination data, the comparison passes. CompareGreaterEqual If source data is greater than or equal to destination data, the comparison passes. CompareAlways Always pass the comparison.
                          depth bias 

                          Depth bias that can be applied to co-planar primitives to reduce z-fighting, according to following function: Depth bias = (max * scaleFactor) + (r * units); where max is the maximum depth slope of the triangle being rendered and r is an implementation-defined constant that is guaranteed to produce the smallest resolvable offset.

                          olygons that are coplanar can be made to appear not coplanar by adding a z-bias to each one. This is a technique commonly used to ensure that shadows, decals, or hidden-line images on coplanar surfaces are displayed properly. The depth bias is added before the depth test is performed but does not influence the original depth value written into depth buffer.

                          Via Candera::RenderMode::SetDepthBias the depth bias can be set and Candera::RenderMode::SetDepthTestEnabled and Candera::RenderMode::SetDepthWriteEnabled enables it.

                            stencil buffer

                            StencilPlane specifies the face associated with the provided stencil function, which are FrontFace, BackFace and FrontAndBackFace. Front face stencil affects non-polygons and front-facing polygons whereas back face stencil affects back-facing polygons only.
                            StencilOperation defines the stencil-buffer operation.

                            SetToZero Set the stencil-buffer entry to zero. Keep Do not update the entry in the stencil buffer. Replace Replace the stencil-buffer entry with the reference value. Increment Increment the stencil-buffer entry, clamping to 2^n where n is the number of bits in the stencil buffer. Decrement Decrement the stencil-buffer entry, clamping to zero. Invert Invert the bits in the stencil-buffer entry. IncrementWrap Increment the stencil-buffer entry, wrapping to zero if the new value exceeds the maximum value DecrementWrap Decrement the stencil-buffer entry, wrapping to the maximum value if the new value is less than zero.

                            Back to the sub chart menu


                            Appearance: Render Mode - Color Blending 
                            Description

                            When Blending is enabled, the output from the fragment shader is blended with the current contents of the frame buffer, rather than merely overwriting it. Blending is mostly used to make objects appear transparent, but can also produce various other effects. (eg. anti-aliasing, DOF, or multi-pass rendering.) There are multiple ways of using blending, but generally, the procedure is as follows:

                              Set alpha value of a node Set alpha value of a material color Set alpha value of the material (this changes the alpha value of the materials diffuse color) Enable blending via RenderMode and use the alpha value of the texture in combination with Candera::RenderMode::BlendMode
                              Blend Operations
                                      enum BlendOperation
                                      {
                                          Add = 0,               
                                          Subtract = 1,          
                                          ReverseSubtract = 2,   
                                          Min = 3,               
                                          Max = 4                
                                      };
                              
                              Blend Factor
                                      enum BlendFactor
                                      {
                                          Zero = 0,                   
                                          One  = 1,                   
                                          SourceColor = 2,            
                                          InverseSourceColor = 3,     
                                          SourceAlpha = 4,            
                                          InverseSourceAlpha = 5,     
                                          DestColor = 6,              
                                          InverseDestColor = 7,       
                                          DestAlpha = 8,              
                                          InverseDestAlpha = 9,       
                                          ConstantColor = 10,         
                                          InverseConstantColor = 11,  
                                          ConstantAlpha = 12,         
                                          InverseConstantAlpha = 13,  
                                          SourceAlphaSaturate = 14    
                                      };
                              


                              BlendMode combines the source and destination blend factors with the operation used in blending equation.

                                RGB blending equation: final_RGB = source_RGB * sourceRGBFactor (+operationRGB+) destination_RGB * destRGBFactor. Alpha blending equation: final_alpha = source_alpha * sourceAlphaFactor (+operationAlpha+) destination_alpha * destAlphaFactor.

                                For the Blending Options ConstantColor, InverseConstantColor, ConstantAlpha, or InverseConstantAlpha a blending color can be set.

                                Set blending:

                                    SharedPointer<RenderMode> rm = RenderMode::Create();
                                    rm->SetBlendingEnabled(true);
                                    rm->SetBlendMode(RenderMode::SourceAlpha, RenderMode::InverseSourceAlpha, RenderMode::Add);
                                    rm->SetDepthTestEnabled(false);
                                    rm->SetDepthWriteEnabled(false);
                                    appearance->SetRenderMode(rm);
                                

                                Back to the sub chart menu


                                Appearance: Shader 
                                Description

                                Candera::Shader is an Appearance component representing a graphical processing unit (GPU) program, thus a vertex and fragment shader pair.

                                  The Shader program can be parametrized with uniforms and attributes. It's guaranteed by the shader that the program is only created once in VRAM. Shader is a device object that counts its uploads to VRAM automatically. Thus, a shader is only uploaded if it has not been uploaded before. Further, a shader is unloaded from VRAM, if the upload count is decreased to zero. Take care, that upload is invoked as many times as unload.

                                  Candera and SceneComposer offer reference shaders of both vertex and fragment shaders.
                                  For details refer to section Shader Usage.


                                  In SceneComposer via the appearance of a node its ShaderProgram can be chanced easily. Further it is possible to change shaders, the default shader configuration, to create new shaders and combine two of them to a new ShaderProgram.

                                  The Default Shader Configuration in SceneComposer
                                  Node Vertex Shader Fragment Shader Billboard RefTrans RefTex Mesh without texture RefTransLight1 RefColor Mesh with texture RefTransLight1 RefColorTex MorphingMesh without texture RefTransLight1Morph RefColor MorphingMesh with texture RefTransLight1Morph RefColorTex PointSprite RefTransPointSprite RefPointSprite SkyBox RefTransCubeMap RefCubeMapTex

                                  Back to the sub chart menu



                                  Appearance: Shader Parameter Setters 
                                  Description

                                  The Candera::ShaderParamSetter class is used to pass uniform parameters to a Shader program. The most relevant methods for this class are Candera::ShaderParamSetter::SetUniform which creates a new uniform (see example below):

                                      shaderParamSetter->SetUniform(m_uniformName, Shader::Float, &m_uniformValue);
                                  

                                  and the Candera::ShaderParamSetter::Activate which activates all the uniforms previously set by the SetUniform method in the Shader.

                                  In a class derived from ShaderParamSetter, the methods which calculates the auto-uniforms (e.g. ModelViewProjectionMatrix4), should be invoked in the Activate method.

                                  Generic Shader Param Setters

                                  Candera::GenericShaderParamSetter is a class derived from Candera::ShaderParamSetter which bundles uniform shader parameters that are calculated by Candera. The class interface offers, for each of these parameters, a specialized method which enables / disables the parameter.

                                      shaderParamSetter->SetModelMatrix4Enabled(true);
                                      shaderParamSetter->SetModelMatrix3Enabled(true);
                                      shaderParamSetter->SetNormalModelMatrix3Enabled(true);
                                      shaderParamSetter->SetModelViewMatrix4Enabled(true);
                                      shaderParamSetter->SetModelViewMatrix3Enabled(true);
                                      shaderParamSetter->SetNormalModelViewMatrix3Enabled(true);
                                      shaderParamSetter->SetModelViewProjectionMatrix4Enabled(true);
                                      shaderParamSetter->SetCameraLookAtVectorEnabled(true);
                                      shaderParamSetter->SetCameraPositionEnabled(true);
                                      shaderParamSetter->SetLightActivationEnabled(true);
                                      shaderParamSetter->SetMaterialActivationEnabled(true);
                                      shaderParamSetter->SetTextureActivationEnabled(true);
                                      shaderParamSetter->SetLightsCoordinateSpace(Light::World);
                                  

                                  If a parameter is enabled then it will be calculated and passed to the shader, if disabled the parameter is neither calculated nor passed.

                                  Default Parameters

                                  Some often needed shader parameters are enabled by default:

                                    ModelViewProjectionMatrix4 LightActivation MaterialActivation TextureActivation

                                    If needed, for performance reasons, those parameters might be disabled.

                                    Generic Param Setters in SceneComposer

                                    In SceneComposer the generic parameter setters are accessible through the graphic interface in two ways:

                                      as customizable uniform setter, from the Toolbox panel in the Attachments bar. Once added in the Appearance node list this uniform setter should be configured in the Properties panel by enabling the desired uniforms. as a predefined uniform setter, from the Templates panel in the UniformSetters list.

                                      SceneComposer provides the following predefined uniform setters:

                                        TransAnisotropicLightShaderParamSetter TransLightBumpMapShaderParamSetter TransLightShaderParamSetter TransLightSphereMapShaderParamSetter TransShaderParamSetter

                                        The table below shows some examples of shaders that can be set by each of the predefined shader parameter setters:

                                        Shader Param Setter Shader Program TransAnisotropicLightShaderParamSetter RefTransAnisotropicLight1_RefAnisotropicLight1SpecularTex TransLightBumpMapShaderParamSetter RefTransLight1BumpMap_RefLight1BumpMap TransShaderParamSetter RefTransLight1_RefColor TransLightSphereMapShaderParamSetter RefTransLight1SphereMap_RefColorTex TransLightShaderParamSetter RefTransWorldLight1_RefColor

                                        Shader parameter setters can be applied to a 3D node by selecting it in the panel and then drag-and-drop it in the Appearance list of the node.

                                        Back to the sub chart menu


                                        Customized Shader Parameter Setter 
                                        Customized Shader Parameter Setter - Example

                                        If for any reason the standard shader parameter setters are not sufficient, it is possible to create a customized shader parameter setter. However, a custom shader parameter setter cannot be configured in SceneComposer, it must be associated to the desired node by coding.

                                        The following example explains how to create and use a customized shader parameter setter in a widget. Refer to the

                                          ShaderParamSetterWidget in combination with the ShaderParamSetterSolution,
                                          both present in the cgi_studio_player folder.

                                          The widget ShaderParamSetterWidget allows to set the u_Material.emissive and the u_MVPMatrix uniform parameters for any node using an appropriate shader program (for example, the nodes in the ShaderParamSetterSolution are using the RefTransLight1_RefColor shader program).

                                          Simple Shader Parameter Setter for u_Material.emissive & u_MVPMatrix Uniforms

                                          In order to pass the u_Material.emissive and u_MVPMatrix uniforms to a shader program, the widget uses an instance of the class SimpleShaderParameterSetter:

                                              // Create uniform setter instance
                                              // m_shaderParamSetter is of type SharedPointer<SimpleShaderParamSetter> ;
                                              m_shaderParamSetter = SimpleShaderParamSetter::Create();
                                              // end Create uniform setter instance
                                          


                                          The only method that needs to be overridden in the SimpleShaderParameterSetter is Candera::ShaderParamSetter::Activate.

                                          The example ShaderParamSetterWidget uses this SimpleShaderParameterSetter by attaching the created instance to the node, which is associated to the widget:

                                              // Attach uniform setter
                                              if ( (GetNode() != 0) && (GetNode()->GetAppearance() != 0) ) {
                                                  GetNode()->GetAppearance()->SetShaderParamSetter(m_shaderParamSetter);
                                              }
                                              // end Attach uniform setter
                                          


                                          Whenever the widget property "Uniform Color" is modified, the widget sets the given color value (m_color) as u_Material.emissive uniform to the SimpleShaderParameterSetter:

                                              // Set u_Material.emissive uniform
                                              FEATSTD_UNUSED(m_shaderParamSetter->SetUniform(ShaderParamNames::GetUniformName(ShaderParamNames::MaterialEmissive), Shader::FloatVec4, reinterpret_cast<Float*>(&m_shaderColor[0]), 1));
                                              // end Set u_Material.emissive uniform
                                          


                                          The node vertices are mapped from the model space to the screen space using the Model-View-Projection Matrix (u_MVPMatrix). SimpleShaderParameterSetter calculates the u_MVPMatrix using the node and camera attributes and then passes it to the shader:

                                              // Set u_MVPMatrix uniform
                                              const Matrix4 mvpMatrix = node.GetWorldTransform() * RenderDevice::GetActiveCamera()->GetViewProjectionMatrix();
                                              return shader.SetUniform( mvpMatrix.GetData(), ShaderParamNames::GetUniformName(ShaderParamNames::ModelViewProjectionMatrix4), Shader::FloatMat4 );
                                              // end Set u_MVPMatrix uniform
                                          


                                          Modifications made using the SetUniform method become effective each time the camera renders the scene because the method Activate is invoked internally by the node.

                                          Back to the sub chart menu


                                          Multipass Appearance 
                                          Description

                                          A Candera::MultiPassAppearance is a dedicated Appearance which enables a node to be rendered multiple times with different appearance settings which are blended in order to achieve a certain visual result like e.g. fur or blurred rendering.

                                          The sequence of render passes is created by chaining instances of MultiPassAppearance using the SetNextPass method:

                                              multiPassAppearance1->SetNextPass(multiPassAppearance2);
                                              multiPassAppearance2->SetNextPass(multiPassAppearance3);
                                          

                                          Back to the sub chart menu

                                          Back to the Chapter menu



                                          3D Scene Graph Dynamics
                                          Description

                                          Usually all required nodes are already specified and preconfigured via SceneComposer, so in most cases it won't be necessary to make any adaptations within the scene graph loaded from an asset at runtime.

                                          However, some use cases might require such adaptations. This tutorial covers the most common means to manipulate the scene graph structure dynamically.

                                          Chapters
                                          Example Solution
                                            SceneGraphDynamicsSolution_3D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes


                                            Adding and Removing 3D Nodes 
                                            3D Scene Graph Dynamics Example

                                            For creating and adding a new node, the following can be used:

                                              SceneGraphDynamicsSolution_3D from folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes SceneGraphDynamicsWidget_3D (this is used in the example solution - refer to SceneGraphDynamicsWidget_3D)

                                              As an example use case, a Candera::Billboard can be created, added and removed. Use the SceneGraphDynamicsWidget_3D properties described below:

                                                AddBillboard: If AddBillboard is enabled a new Billboard is created and added to the widget node. If disabled, the Billboard will be removed.

                                                        // Definition of WidgetProperty "AddBillboard"
                                                        CdaProperty(AddBillboard, bool, GetAddBillboard, SetAddBillboard)
                                                            CdaDescription("If AddBillboard is enabled a new Billboard is created and added to the widget Candera::Node. If disabled, the Billboard will be removed.")
                                                        CdaPropertyEnd()
                                                        // End Definition of WidgetProperty "AddBillboard"
                                                


                                                Creating a new Billboard

                                                The following code snippet generates a basic Candera::Billboard (size 30 x 30) with a Candera::Material and a matching Candera::Shader. The Shader has to be provided in the asset and is delivered through the AssetProvider by its name. Further, some translation is applied to the new Billboard.

                                                        // Create and init a new Billboard
                                                
                                                        SharedPointer<Appearance> myAppearance = Appearance::Create();
                                                        SharedPointer<Material> myMaterial = Material::Create();
                                                        myMaterial->SetEmissive(Color(0.5F, 0.0F, 0.0F, 1.0F));
                                                        myAppearance->SetMaterial(myMaterial);
                                                        myAppearance->SetShader(Base::GetAssetProvider()->GetShader(CgiAssetNames::RefTransLight1_RefColor));
                                                        myAppearance->SetName("Generated Appearance");
                                                
                                                        m_billboard = Billboard::Create(30.0F, 30.0F);
                                                        m_billboard->SetAppearance(myAppearance);
                                                        m_billboard->Translate(Vector3(30.0F, 0.0F, 0.0F));
                                                
                                                        // end Create and init a new Billboard
                                                


                                                Adding the new Billboard to the scene graph

                                                Next the Billboard is uploaded to VRAM and appended to the node associated with the widget.

                                                        // Add Billboard
                                                
                                                        static_cast<void>(m_billboard->Upload());
                                                        static_cast<void>(node->AddChild(m_billboard));
                                                
                                                        // end Add Billboard
                                                
                                                Removing and destructing the Billboard

                                                To remove the Billboard simply from the scene graph, use Candera::Node::RemoveChild. If the Billboard will be used for further operations e.g. attaching it to an other node removing would be enough. Since in this example the Billboard isn't used further it should not only be removed but also be destructed completely (freeing the resources).

                                                The following code snippet removes the previously generated billboard from its parents, unloads the Billboard from VRAM and frees with Candera::Node::Dispose the resources.

                                                        // Remove previously generated billboard and destruct it
                                                
                                                        Node* parent = m_billboard->GetParent();
                                                        if (parent != 0){
                                                            static_cast<void>(parent->RemoveChild(m_billboard));
                                                            FEATSTD_LOG_ERROR("- Node %s removed from parent %s ...\n", m_billboard->GetName(), parent->GetName());
                                                        }
                                                        // Destruct node
                                                
                                                        static_cast<void>(m_billboard->Unload());
                                                        m_billboard->Dispose();
                                                        m_billboard = 0;
                                                
                                                        // end Destruct node
                                                
                                                        // end Remove previously generated billboard and destruct it
                                                


                                                As Candera::Node::Dispose internally calls the Candera::Node::RemoveChild on parent node following code would be enough for removing and destructing a node.

                                                        // Destruct node
                                                
                                                        static_cast<void>(m_billboard->Unload());
                                                        m_billboard->Dispose();
                                                        m_billboard = 0;
                                                
                                                        // end Destruct node
                                                

                                                In SceneComposer the newly added Node does not appear in the Scene Tree view because it is only added dynamically by the widget.
                                                - The used Shader for the generated Billboard in the widget has to be included when generating an asset from the solution - ensure that "Always include in asset" flag is marked at the Shaders properties.
                                                - The widget must control memory and VRAM management of its internal dynamic subtree autonomously.

                                                Widget Interaction in the Player

                                                First, the asset must be exported and loaded in the Player. Then, one of the two existing SceneGraphDynamicsWidget_3D widgets must be selected for the 3D scene. After, ChangeAppearance, CloneOperation and AddBillboard properties can be enabled/disabled (1/0) to obtain different results.

                                                Back to the sub chart menu


                                                Changing Appearance and other 3D Node Attachments 

                                                For changing the appearance of a node, the following property of the SceneGraphDynamicsWidget_3D can be used:

                                                  ChangeAppearance: If ChangeAppearance is enabled, the appearance of the widgets associated node will be changed to a new generated appearance. If disabled, the previous appearance will be restored.

                                                          // Definition of WidgetProperty "ChangeAppearance"
                                                          CdaProperty(ChangeAppearance, bool, GetChangeAppearance, SetChangeAppearance)
                                                              CdaDescription("If ChangeAppearance is enabled, the appearance will be exchanged to a new generated appearance. If disabled, the previus appearance will be restored.")
                                                          CdaPropertyEnd()
                                                          // End Definition of WidgetProperty "ChangeAppearance"
                                                  

                                                  Try the ChangeAppearance property at the SceneGraphDynamics_3D_Billboard widget in the example solution to change the Billboards appearance from a texture appearance to a material appearance.

                                                  Creating and changing an Appearance

                                                  The following code snippet generates a basic Candera::Appearance. A Candera::Material is created and its emissive color is set to a light green. The material and a proper shader is set to the Appearance. The shader has to be provided in the asset and is delivered through the AssetProvider by its name.

                                                      // Create and set a new Appearance
                                                  
                                                      SharedPointer<Appearance> myAppearance = Appearance::Create();
                                                      myAppearance->SetMaterial(Material::Create());
                                                      myAppearance->GetMaterial()->SetEmissive(Color(0.0F, 0.5F, 0.0F, 1.0F));
                                                      myAppearance->SetShader(Base::GetAssetProvider()->GetShader(CgiAssetNames::RefTransLight1_RefColor));
                                                      myAppearance->SetName("Generated Appearance");
                                                  
                                                      // end Create and set new Appearance
                                                  

                                                  In the next step the node's previous Appearance is saved (for restoring purpose) and the new generated appearance is set to the node associated with the widget.

                                                      // Change Appearance
                                                  
                                                      m_previousAppearance = node->GetAppearance();
                                                      node->SetAppearance(myAppearance);
                                                      static_cast<void>(myAppearance->Upload());
                                                  
                                                      // end Change Appearance
                                                  
                                                  Restoring / releasing an Appearance

                                                  Restore the previous Appearance and destruct the dynamically generated appearance.

                                                          // Restoring appearance and destructing
                                                  
                                                          SharedPointer<Appearance> currentAppearance = node->GetAppearance();
                                                          static_cast<void>(currentAppearance->Unload());
                                                          currentAppearance.Release();
                                                          node->SetAppearance(m_previousAppearance);
                                                  
                                                          // end Restoring appearance and destructing
                                                  

                                                  In SceneComposer the changed Appearance does not appear in the Appearance panel because it is only changed dynamically by the widget.
                                                  - The used shader for the generated Billboard in the widget has to be included when generating an asset from the solution - ensure that "Always include in asset" flag is marked at the Shaders properties.
                                                  - The widget must control memory and VRAM management of dynamically created node attachments autonomously.

                                                  Back to the sub chart menu


                                                  Cloning 3D Nodes 

                                                  For cloning a node, the following property of the SceneGraphDynamicsWidget_3D can be used:

                                                    NodeToClone: Select an arbitrary node in the scene graph, which shall be cloned and added to the widget node

                                                            // Definition of WidgetProperty "NodeToClone"
                                                            CdaProperty(NodeToClone, Candera::Node*, GetNodeToClone, SetNodeToClone)
                                                                CdaDescription("Select a Candera::Node which shall be cloned and added to the widget Candera::Node. The Candera::Node must be a child of this widget's scene.")
                                                            CdaPropertyEnd()
                                                            // End Definition of WidgetProperty "NodeToClone"
                                                    


                                                      CloneOperation: If enabled, the clone operation will be executed and the cloned node will be added to the widget node.

                                                              // Definition of WidgetProperty "CloneOperation"
                                                              CdaProperty(CloneOperation, bool, GetCloneOperation, SetCloneOperation)
                                                                  CdaDescription("If CloneOperation is enabled, the Candera::Node to clone will be cloned and added to the widget Candera::Node. If disabled, the clone will be removed.")
                                                              CdaPropertyEnd()
                                                              // End Definition of WidgetProperty "CloneOperation"
                                                      


                                                      For the cloning operation, refer to Candera::Node::Clone. The following code snippets illustrate, what the SceneGraphDynamicsWidget_3D is actually doing for cloning a node and destructing it again.

                                                      Validating Node to Clone

                                                      This example should allow to clone nodes, which are part of the scene graph the widget is linked to. The scene graph can be traversed from a given node up to its actual top level scene node to check whether it is part of the scene graph.

                                                          // Search the parent scene of a given node
                                                      
                                                          Node* currentNode = node;
                                                      
                                                          while (currentNode != 0) {
                                                              if (currentNode->IsTypeOf(Scene::GetTypeId())) {
                                                                  return static_cast<Scene*>(currentNode);
                                                              }
                                                              currentNode = currentNode->GetParent();
                                                          }
                                                          return 0;
                                                      
                                                          // end Search the parent scene of a given node
                                                      
                                                      Creating and Adding Clone

                                                      If the widget node and the node to clone have same top level scene, the node can be cloned and added to the widget node according to the following code snippet.

                                                              // Clone the node and add it to the widgets associated node
                                                      
                                                              m_clonedNode = TreeCloner().CreateClone(*m_nodeToClone);
                                                              static_cast<void>(node->AddChild(m_clonedNode));
                                                              static_cast<void>(m_clonedNode->UploadAll());
                                                              m_clonedNode->SetName("Clone");
                                                      
                                                              // end Clone the node and add it to the widgets associated node
                                                      

                                                      Nodes can be attached to any 3D node.

                                                      TreeCloner and Cloning Strategies

                                                      For more complex cloning see Candera::TreeCloner and Candera::TreeCloneStrategy. Candera::TreeClonerBase is provided for cloning trees.

                                                        The default clone strategy is to call the Clone interface on each node, and build the clone tree with the same node pattern as the original tree. For deeper cloning, TreeClonerBase supports attaching a Candera::TreeCloneStrategy. This TreeCloneStrategy is typically aware of different types of nodes, and delegates to other strategies.
                                                        Removing and Destructing Clone

                                                        Analogous to Removing and destructing the Billboard (removing/destructing a 3D node) the cloned node is destructed.

                                                                // Remove a previously cloned node
                                                        
                                                                static_cast<void>(m_clonedNode->UnloadAll());
                                                                m_clonedNode->Dispose();
                                                                m_clonedNode = 0;
                                                        
                                                                // end Remove a previously cloned node
                                                        

                                                        In SceneComposer the newly added node clone does not appear in the Scene Tree view because it is only added dynamically by the widget.
                                                        - It is not allowed to modify the scene graph maintained by SceneComposer outside of the subtree owned by the widget!
                                                        - The widget must control memory and VRAM management of its internal dynamic subtree autonomously.

                                                        Back to the sub chart menu

                                                        Back to the Chapter menu



                                                        3D Render Order
                                                        Description

                                                        There are various reasons why sorting of objects to render is required:

                                                          Transparency: Transparent objects must be rendered from back to front, while opaque objects must be rendered from front to back. Performance: Front to back order or advanced techniques like state sorting provide the best performance Other: Custom rank, Skybox, other background geometry, dialogs, pop-ups, etc.
                                                          Chapters



                                                          Render Order: Involved Classes 
                                                          Involved Render Order Classes
                                                          Candera::RenderOrder

                                                          Defines the sequence of nodes to render per scene and camera.
                                                          Sorting is done according to following criteria:

                                                            Rank of render order bins: Candera::RenderOrder::SetBinRank. Sorting of Nodes within bin (see below).

                                                            Default bins are 'opaque' and 'transparent'. If no assignment is set, nodes are automatically assigned to opaque or transparent, according to the Node's transparency settings (RenderMode state).

                                                            Candera::RenderOrderBin RenderOrder maintains a set of RenderOrderBins. A bin
                                                              Contains nodes that have rendering enabled
                                                              Candera::RenderOrderBin::SetOrderCriterion: Sorts nodes according to applied Candera::OrderCriterion 
                                                              Candera::RenderOrderBin::SetRank: defines sequence of bin within render order
                                                              Distinction between camera dependent and camera independent bins Candera::OrderCriterion

                                                              Nodes within a bin are sorted according to an OrderCriterion.
                                                              Predefined for camera dependent bins:

                                                                Candera::DistanceToCameraOrderCriterion (sorting from front to back for opaque bin) Candera::ReverseDistanceToCameraOrderCriterion (sorting from back to front for transparent bin)

                                                                Predefined for camera independent bins, sorted by explicit rank values:

                                                                  Candera::RankOrderCriterion (lower render order rank is before higher render order rank.) Candera::ReverseRankOrderCriterion (higher render order rank is before lower render order rank) Candera::RenderStateOrderCriterion (takes in consideration the Node's Shader, Texture and RenderMode, whose changes are considered the most expensive) Candera::Node A node must be assigned to a bin, and if this bin is sorted by rank, the node must also specify it's rank inside the bin.
                                                                    Candera::Node::SetRenderOrderBinAssignment: Defines bin assignment. If not set, then auto assignment is processed: Opaque or transparent, according to Node's RenderMode state
                                                                    Candera::Node::SetRenderOrderRank: Defines render order rank that is utilized if the bin assigned to is sorted by rank Candera::Scene Candera::Scene::SetRenderOrder: One RenderOrder is exactly assigned to one Scene. Candera::Renderer Uses RenderOrder to render Nodes according to its defined sequence.

                                                                    Back to the sub chart menu


                                                                    Default Render Order: Sorting by Distance to Camera 
                                                                    Default Render Order

                                                                    By default, all objects part of a scene are automatically sorted by Candera according to their render attributes into two predefined render order bins:

                                                                      Opaque bin: Opaque objects are rendered using Candera::DistanceToCameraOrderCriterion Transparent bin: Transparent objects are rendered using Candera::ReverseDistanceToCameraOrderCriterion

                                                                      Both default bins are protected, which means that they are under control of Candera and cannot be deleted.

                                                                      Predefined Render Order in SceneComposer

                                                                      In SceneComposer, each 3D scene gets the predefined render order bins assigned by default:

                                                                      drawing-4-1676882062.png

                                                                      Predefined Render Order in Candera

                                                                      To apply the default behaviour with auto-assignment of transparent and opaque objects via Candera API, refer to following example:

                                                                      // Create default render order with 2 default bins and max. number of 10 nodes each (opaque and transparent bin).
                                                                      // Default rank for opaque bin is 10 and transparent bin is 20
                                                                      static RenderOrder* renderOrder = RenderOrder::Create(10, 10);
                                                                      // Assign render order to scene.
                                                                      m_scene->SetRenderOrder(&renderOrder);
                                                                      

                                                                      Back to the sub chart menu


                                                                      Fixed Render Order 

                                                                      To customize the default render order with a fixed render order, scene nodes must be assigned to custom render order bins sorted by explicit rank values.

                                                                        Using Candera::RankOrderCriterion, the scene will be rendered so that lower render order rank is before higher render order rank. When using Candera::ReverseRankOrderCriterion, higher render order rank is before lower render order rank.
                                                                        Code Example: Fixed Render Order

                                                                        As an example, create a render order with 3 bins and max. number of 10 nodes for O&T bin:

                                                                        static RenderOrder renderOrder(3, 10, 10);
                                                                        m_scene->SetRenderOrder(&renderOrder);
                                                                        

                                                                        Create new render order bin with name "UserBin", rank "30", max. Number of 10 nodes:

                                                                        renderOrder.CreateBin("UserBin", 30, 10);
                                                                        

                                                                        Create dedicated order criterion which sorts nodes by its render order rank:

                                                                        static RankOrderCriterion userCriterion;
                                                                        

                                                                        Assign order criterion to UserBin:

                                                                        renderOrder.SetBinOrderCriterion("UserBin", &userCriterion);
                                                                        

                                                                        Assign nodes to dedicated bins:

                                                                        m_mesh1->SetRenderOrderBinAssignment("UserBin");
                                                                        m_mesh2->SetRenderOrderBinAssignment("UserBin");
                                                                        

                                                                        Set dedicated render order rank for nodes:

                                                                        m_mesh1->SetRenderOrderRank(2);
                                                                        m_mesh2->SetRenderOrderRank(1);
                                                                        

                                                                        Back to the sub chart menu


                                                                        Performance Optimized Render Order 

                                                                        Candera::RenderStateOrderCriterion implements a proof of concept OrderCriterion used for batching nodes to minimize render state changes. It takes into consideration the nodes shader, texture and render mode, whose changes are considered the most expensive.

                                                                          After sorting all the nodes using the Candera::OrderCriterionValue, rendering is done in batches of nodes with the same shader. Inside a batch of nodes with the same shader, the rendering will be done in batches of nodes with the same texture. Inside a batch of nodes with the same shader and texture, the rendering will be done in batches of nodes with the same blending enabled value.

                                                                          The batching continues until the least expensive state change (CullingMode).

                                                                          - Usage of Candera::RenderStateOrderCriterion does not guarantee best batching algorithm, which should be implemented after benchmarking the target render device's state change costs.
                                                                          - RenderStateOrderCriterion groups the nodes only by their first appearance and texture. Nodes with multi-pass rendering (MultiPassAppearance), or with multiple texture units, most probably will break the batches and cancel some performance gains.
                                                                          - CANDERA_RENDER_STATE_CACHING_ENABLED should be defined to use Canderas render state caching mechanism.

                                                                          Back to the sub chart menu

                                                                          Back to the Chapter menu



                                                                          Searching for Nodes with SearchTreeTraverser
                                                                          Searching for Nodes

                                                                          With Candera::SearchTreeTraverser it is possible to find nodes within a given scene tree by certain criteria. The search scene graph traverser is a Candera::TreeTraverserBase implementation that evaluates each node with a given Candera::SearchCriterion.

                                                                          Following code snippets illustrate how to use the traverser.

                                                                          Creating a plugin that registers a configuration and uses the default configuration editor.

                                                                          First create a Candera::SearchTreeTraverser and then set its Candera::SearchCriterion. The search criterion validates nodes based on the implemented criterion.

                                                                          In the example below the criterion is a Candera::ScopeMaskSearchCriterion.

                                                                              // Create criterion
                                                                              ScopeMaskSearchCriterion<Node> scopeMaskCriterion;
                                                                              scopeMaskCriterion.SetScopeMask(scopeA);
                                                                              
                                                                              // Create SearchTreeTraverser
                                                                              SearchTreeTraverser<Node> scopeSearchTraverser;
                                                                              scopeSearchTraverser.SetSearchCriterion(&scopeMaskCriterion);
                                                                          
                                                                          Tree Traversing

                                                                          To start a search within a node tree, call Candera::SearchTreeTraverser::Traverse(). With the Candera::SearchTreeTraverser::SetOnFoundAction you can define if the search should stop after the first node that fulfills the search criterion is found, or if it should continue to gather all valid nodes.

                                                                          Possible TraverserActions are:

                                                                            ProceedTraversing: Find all nodes matching the given search criterion (traversing is stopped at the end of the tree) StopTraversingForDescendants: Find only nodes on the top level of the tree (traversing stops at child nodes and proceeds at siblings, until the end of the tree) StopTraversing: Find only the first node matching the search criterion (traversing is stopped immediately).

                                                                            The nodes fulfilling the search criterion are retained and are available to be later retrieved. Get the nodes one by one with Candera::SearchTreeTraverser::GetSearchResult. The order of the nodes is not defined and each node can be retrieved only once. When no more nodes are available, the method returns 0.

                                                                            Following are examples for the different TraverserActions.

                                                                            ProceedTraversing

                                                                            This action is used if the traversing should continue with the next child (if the current node has any) or with the next sibling.

                                                                            First define the action and then call the Traverse() method. All nodes that fulfill the search criterion are found and stored internally in a list.

                                                                                // Set on found action and traverse
                                                                                scopeSearchTraverser.SetOnFoundAction(Candera::TreeTraverserBase<Node>::ProceedTraversing);
                                                                                scopeSearchTraverser.Traverse(*groupRoot);
                                                                                
                                                                                // Get results
                                                                                UInt32 nodeCount = 0;
                                                                                for (Node* node = scopeSearchTraverser.GetSearchResult(); node != 0; node = scopeSearchTraverser.GetSearchResult()) {
                                                                                    nodeCount++;
                                                                                }
                                                                            
                                                                            StopTraversingForDescendants

                                                                            Used if the traversing should stop for all child nodes and continue with the next sibling.

                                                                                // Set on found action and traverse
                                                                                scopeSearchTraverser.SetOnFoundAction(Candera::TreeTraverserBase<Node>::StopTraversingForDescendants);
                                                                                scopeSearchTraverser.Traverse(*groupRoot);
                                                                            
                                                                            StopTraversing

                                                                            If you search for only one node which fulfills your criteria, you can use StopTraversing. The traversing will stop immediately after the first node is found.

                                                                                // Set on found action and traverse
                                                                                scopeSearchTraverser.SetOnFoundAction(Candera::TreeTraverserBase<Node>::StopTraversing);
                                                                                scopeSearchTraverser.Traverse(*groupRoot);
                                                                                Node* resultNode = scopeSearchTraverser.GetSearchResult();
                                                                            

                                                                            Another call of Candera::SearchTreeTraverser::GetSearchResult would return 0, because we use StopTraversing here. This leads to one result only.

                                                                            Back to the Chapter menu


                                                                            Vertex Geometry Builder
                                                                            Description

                                                                            The Candera::VertexGeometryBuilder class helps effectively build Candera::VertexGeometry objects.

                                                                            Chapters
                                                                            Example Solution
                                                                              VertexGeometryBuilderSolution in the folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes The basic vertex geometry builder operations are exemplified in the widget VertexGeometryBuilderWidget. What the widget does, basically, is to generate the vertex buffer for the four 3D models which are rendered successively in the scene depending on the value set for the widget property "Model Type".


                                                                              Procedural Geometry 
                                                                              Example: Wireframe Cube with LineList

                                                                              First example shows how to generate a wireframe cube using a Candera::LineList object.

                                                                              The vertex geometry will be generated procedurally using a Candera::VertexGeometryBuilder object (e.g. m_builder).

                                                                              Vertex Element Format: Position and Color

                                                                              At the beginning we have to specify what kind of information will be set in the vertices. Of course we need information about the position and, optionally, for an improved visual effect, we could also add color information.

                                                                                  // Set the data type to be used: position & color
                                                                                  m_builder.SetVertexElementFormat(VertexGeometry::Position, 0, VertexGeometry::Float32_3);
                                                                                  m_builder.SetVertexElementFormat(VertexGeometry::Color, 0, VertexGeometry::Float32_4);
                                                                              
                                                                              Vertex Data: Position

                                                                              The position information for the vertices is obtained from the array c_cubeData which, in fact, stores the coordinates of the points A and G. The coordinates for the rest of the vertices are obtained relatively to this points (e.g. F(XA, YG, ZG) or D(XG, YA, ZA)

                                                                              drawing-4-1676882299.png


                                                                              // Coordinates for the points A & G
                                                                              static const Float c_cubeData[2][3] = {
                                                                                  {-1.0F, -1.0F, -1.0F },
                                                                                  {1.0F, 1.0F, 1.0F }
                                                                              };
                                                                              
                                                                              VertexGeometryBuilder: Set Vertex Elements

                                                                              Because the LineType property of the LineList object will be set to LineType::Lines, the vertex buffer will have to contain a pair of vertices for each line of the cube: 2 vertices/line * 12 lines = 24 vertices.

                                                                                  // Set the position & color information for each vertex
                                                                                  // Line segment AD
                                                                                  m_builder.SetVertexElement(VertexGeometry::Position, 0, c_cubeData[0][0], c_cubeData[0][1], c_cubeData[0][2]); // A
                                                                                  m_builder.SetVertexElement(VertexGeometry::Color, 0, 1.F, 0.F, 1.F, 1.F); // magenta
                                                                                  // Increment the vertex cursor
                                                                                  m_builder.IncrementVertexCursor();
                                                                                  m_builder.SetVertexElement(VertexGeometry::Position, 0, c_cubeData[1][0], c_cubeData[0][1], c_cubeData[0][2]); // D
                                                                                  m_builder.SetVertexElement(VertexGeometry::Color, 0, 1.F, 1.F, 1.F, 1.F); // white
                                                                                  m_builder.IncrementVertexCursor();
                                                                                  // Line segment AB
                                                                                  m_builder.SetVertexElement(VertexGeometry::Position, 0, c_cubeData[0][0], c_cubeData[0][1], c_cubeData[0][2]); // A
                                                                                  m_builder.SetVertexElement(VertexGeometry::Color, 0, 1.F, 0.F, 1.F, 1.F); // magenta
                                                                                  m_builder.IncrementVertexCursor();
                                                                                  m_builder.SetVertexElement(VertexGeometry::Position, 0, c_cubeData[0][0], c_cubeData[0][1], c_cubeData[1][2]); // B
                                                                                  m_builder.SetVertexElement(VertexGeometry::Color, 0, 1.F, 1.F, 0.F, 1.F); // yellow
                                                                                  // ...
                                                                              
                                                                              Create Vertex Buffer

                                                                              Create a Candera::VertexBuffer object and attach to it the vertex geometry obtained from the Candera::VertexGeometryBuilder:

                                                                                  VertexGeometry* vertexGeom = m_builder.GetVertexGeometry();
                                                                                  SharedPointer<VertexBuffer> vertexBuffer = VertexBuffer::Create();
                                                                                  static_cast<void>(vertexBuffer->SetVertexGeometry(vertexGeom, VertexBuffer::VertexGeometryDisposer::Dispose));
                                                                                  vertexBuffer->SetPrimitiveType(VertexBuffer::Lines);
                                                                              
                                                                              Create LineList using the Vertex Buffer

                                                                              Attach the vertex buffer to LineList object:

                                                                                  // Create and configure the line list object
                                                                                  m_lineList = LineList::Create();
                                                                                  m_lineList->SetAppearance(Appearance::Create());
                                                                                  m_lineList->GetAppearance()->SetMaterial(Material::Create());
                                                                                  m_lineList->GetAppearance()->GetMaterial()->SetEmissive(Color(1.0F, 1.0F, 0.0F));
                                                                                  m_lineList->GetAppearance()->SetShader(m_shaderLightMaterial);
                                                                                  m_lineList->SetLineType(LineList::Lines);
                                                                                  m_lineList->SetWidth(1.0);
                                                                                  m_lineList->SetIntersectionTestEnabled(false);
                                                                                  m_lineList->SetVertexBuffer(vertexBuffer);
                                                                                  m_lineList->SetScopeMask(ScopeMask(false));
                                                                                  static_cast<void>(m_lineList->SetScopeEnabled(1, true));
                                                                                  m_lineList->SetRenderingEnabled(true);
                                                                                  m_lineList->SetName("Wireframe");
                                                                                  static_cast<void>(m_lineList->Upload());
                                                                              
                                                                              Wireframe Cube Result

                                                                              The image below shows the resulting wireframe cube:

                                                                              drawing-4-1676882342.png

                                                                              For an easier manipulation of the widget in SceneComposer all the shaders are hardcoded in the source file (see cgi_studio_player\src\LegacyWidgets\Tutorial\3D\VertexGeometryBuilderWidget.cpp) and then created by the widget at the initialization time.

                                                                              Alternatively obtain shaders from Candera::AssetProvider (e.g. GetAssetProvider()->GetShader("...")) in case the application uses an asset library.

                                                                              Back to the sub chart menu


                                                                              Indexed Geometry 
                                                                              Example: Solid Cube from one Triangle Strip

                                                                              The next example will show how to create a solid cube from one triangle strip using a Candera::Mesh object. In this case the cube is determined by only 14 vertices which have to be ordered in a special way.

                                                                              The figure below presents a cube unfolded and a possible solution of ordering the vertices:

                                                                              drawing-4-1676882414.png

                                                                              Indexed Vertex Sequence

                                                                              The vertex sequence is stored in the c_index_order array, encoding the order:

                                                                                G->C->F->B->A->C->D->H->A->E->F->H->G->C.

                                                                                Each array element represents an offset it the vertex buffer.

                                                                                // The vertex sequence - triangle strip
                                                                                static const UInt16 c_index_order[] = { 12, 11, 7, 3, 0, 11, 1, 17, 0, 5, 7, 17, 12, 11 };
                                                                                

                                                                                The vertex geometry builder object used in the previous example has already 24 vertices set with position and color information. Because only 14 vertices out of 24 are needed in this case and, also, because their sequence has to be different, an index buffer is added:

                                                                                    // Change the order of the vertices using indexes
                                                                                    for (Int index = 0; index < 14; index++) {
                                                                                        // Define the value of the index
                                                                                        m_builder.SetIndexElement(c_index_order[index]);
                                                                                        // Increment the index cursor
                                                                                        m_builder.IncrementIndexCursor();
                                                                                    }
                                                                                
                                                                                Create TriangleStrip Vertex Buffer

                                                                                Create the vertex buffer using the geometry from the builder:

                                                                                    VertexGeometry* vertexGeom = m_builder.GetVertexGeometry();
                                                                                    SharedPointer<VertexBuffer> vertexBuffer = VertexBuffer::Create();
                                                                                    static_cast<void>(vertexBuffer->SetVertexGeometry(vertexGeom, VertexBuffer::VertexGeometryDisposer::Dispose));
                                                                                    vertexBuffer->SetPrimitiveType(VertexBuffer::TriangleStrip);
                                                                                
                                                                                Create Mesh using the Vertex Buffer

                                                                                Configure mesh and attach the vertex buffer:

                                                                                    m_mesh = Mesh::Create();
                                                                                    m_mesh->SetVertexBuffer(vertexBuffer);
                                                                                    m_mesh->SetAppearance(appearance);
                                                                                    m_mesh->SetRenderingEnabled(false);
                                                                                    m_mesh->SetName("SolidNonTextured");
                                                                                    static_cast<void>(m_mesh->Upload());
                                                                                
                                                                                Solid Cube Result

                                                                                The image below shows the resulting solid cube:

                                                                                drawing-4-1676882451.png



                                                                                Remove & Add Vertex Elements 
                                                                                Example: Textured Cube

                                                                                In this example the vertex geometry builder object will be used to generate the vertex geometry for a textured cube.

                                                                                Adding texture to a mesh requires that its vertices should contain specific information like normal and texture coordinate. Also, the color information is no longer needed so it can be removed:

                                                                                    // Vertex Elements Manipulation
                                                                                    // Remove color data associated to the vertices
                                                                                    m_builder.RemoveVertexElement(VertexGeometry::Color,0);
                                                                                    // Add data type to be used: texture coordinate & normal
                                                                                    m_builder.SetVertexElementFormat(VertexGeometry::TextureCoordinate, 0, VertexGeometry::Float32_2);
                                                                                    m_builder.SetVertexElementFormat(VertexGeometry::Normal, 0, VertexGeometry::Float32_3);
                                                                                
                                                                                Vertex Data: Normals and Texture Coordinates

                                                                                After adding the new data types for the vertices it is time to add the corresponding information. First, add normals for vertices:

                                                                                    // Move the cursor to the first vertex
                                                                                    m_builder.SetVertexCursor();
                                                                                    for (UInt32 i = 0; i < m_builder.GetVertexCount(); i++ )
                                                                                    {
                                                                                        m_builder.SetVertexElement(VertexGeometry::Normal, 0, 0.0F, 0.0F, 1.0F);
                                                                                        m_builder.IncrementVertexCursor();
                                                                                    }
                                                                                

                                                                                In order to map the UV texture coordinate values correctly, the cube faces should be drawn using 4 vertices per face, so, in this case, all 24 vertices will be used. Of course, the vertex order has to be adjusted.

                                                                                The new vertex order is stored in the c_indexDataTexturedCube array.

                                                                                // Vertex order - textured cube
                                                                                static const UInt16 c_indexDataTexturedCube[24] = {
                                                                                    1,17,0,5,
                                                                                    2,6,3,7,
                                                                                    9,8,11,12,
                                                                                    13,14,19,21,
                                                                                    15,23,16,22,
                                                                                    4,10,20,18
                                                                                };
                                                                                

                                                                                Now, reorder the vertices:

                                                                                    // Overwrite the index buffer
                                                                                    // Move the cursor to the first index
                                                                                    m_builder.SetIndexCursor();
                                                                                    for (UInt32 i = 0; i < m_builder.GetVertexCount(); i++ )
                                                                                    {
                                                                                        // Define the value of the index
                                                                                        m_builder.SetIndexElement(c_indexDataTexturedCube[i]);
                                                                                        m_builder.IncrementIndexCursor();
                                                                                    }
                                                                                

                                                                                The vertices of each face of the cube should be set with texture coordinate information as shown below:

                                                                                drawing-4-1676882513.png



                                                                                Set the texture coordinates for vertices:

                                                                                    Int idx = 0;
                                                                                    for (Int nb_of_faces = 0; nb_of_faces<6; nb_of_faces++) {
                                                                                        for (Int u=0; u<=1; u++) {
                                                                                            for (Int v=0; v<=1; v++) {
                                                                                                //Set the position of the vertex cursor
                                                                                                m_builder.SetVertexCursor(c_indexDataTexturedCube[idx]);
                                                                                                m_builder.SetVertexElement(VertexGeometry::TextureCoordinate, 0, static_cast<Float>(u), static_cast<Float>(v));
                                                                                                idx++;
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                

                                                                                The vertex buffer is created and configured in the same way as in the previous example.

                                                                                The mesh setup is also similar but, unlike the solid cube, the textured cube appearance has to be set with a texture and a texture shader.

                                                                                Textured Cube Result

                                                                                Here is the final result:

                                                                                drawing-4-1676882532.png



                                                                                Range Data Usage 
                                                                                Example: Solid Cube using Range Data

                                                                                This example will show how to create a solid cube as in the second example but using range data.

                                                                                First, all existing data from the vertex geometry builder is removed.

                                                                                    // Clear all data stored by the builder
                                                                                    m_builder.Clear();
                                                                                

                                                                                The vertex data is taken from the two buffers c_positionData and c_colorData.

                                                                                static const Float c_positionData[8][3] = {
                                                                                    { -1.0F, 1.0F, 1.0F},
                                                                                    { 1.0F, 1.0F, 1.0F},
                                                                                    { -1.0F, -1.0F, 1.0F},
                                                                                    { 1.0F, -1.0F, 1.0F},
                                                                                    { -1.0F, 1.0F, -1.0F},
                                                                                    { 1.0F, 1.0F, -1.0F},
                                                                                    { -1.0F, -1.0F, -1.0F},
                                                                                    { 1.0F, -1.0F, -1.0F}
                                                                                };
                                                                                
                                                                                static const Float c_colorData[8][4] = {
                                                                                    { 0.0F, 0.0F, 1.0F, 1.0F},
                                                                                    { 0.0F, 1.0F, 0.0F, 1.0F},
                                                                                    { 0.0F, 1.0F, 1.0F, 1.0F},
                                                                                    { 1.0F, 0.0F, 0.0F, 1.0F},
                                                                                    { 1.0F, 0.0F, 1.0F, 1.0F},
                                                                                    { 1.0F, 1.0F, 0.0F, 1.0F},
                                                                                    { 1.0F, 1.0F, 1.0F, 1.0F},
                                                                                    { 1.0F, 0.5F, 1.0F, 1.0F}
                                                                                };
                                                                                

                                                                                The vertex sequence is taken from the array c_indexData.

                                                                                // Range data index
                                                                                static const UInt16 c_indexData[] = {3, 2, 1, 0, 4, 2, 6, 3, 7, 1, 5, 4, 7, 6 };
                                                                                

                                                                                Use the methods Candera::VertexGeometryBuilder::SetVertexElementRange and Candera::VertexGeometryBuilder::SetIndexElementRange to add the required information.

                                                                                    // Add position, color and an index from range data
                                                                                    // Splice values to the position buffer starting with the first vertex
                                                                                    static_cast<void>(m_builder.SetVertexElementRange(VertexGeometry::Position, 0, 0, VertexGeometry::Float32_3,
                                                                                        8, 3*sizeof(Float), c_positionData ));
                                                                                    // Splice values to the color buffer starting with the first vertex
                                                                                    static_cast<void>(m_builder.SetVertexElementRange(VertexGeometry::Color, 0, 0, VertexGeometry::Float32_4,
                                                                                        8, 4*sizeof(Float), c_colorData ));
                                                                                
                                                                                    // Splice values to the index buffer starting with the first index
                                                                                    static_cast<void>(m_builder.SetIndexElementRange(0, sizeof(c_indexData)/sizeof(UInt16),c_indexData));
                                                                                

                                                                                The vertex buffer configuration and the mesh setup are identical with the ones from the second example.

                                                                                Here is the final result:

                                                                                drawing-4-1676882596.png

                                                                                Back to the sub chart menu


                                                                                Concatenate Geometries 
                                                                                VertexGeometryBuilder::SpliceGeometry

                                                                                In some cases it might be useful to concatenate two vertex geometries. This can be done by using the Candera::VertexGeometryBuilder::SpliceGeometry method as shown below:

                                                                                    m_builder.SpliceGeometry(0, 0, vertexGeometry1);
                                                                                    m_builder.SpliceGeometry(vertexGeometry1->GetVertexCount(), vertexGeometry1->GetIndexCount(), vertexGeometry2);
                                                                                    vertexGeometry1cat2 = builder.GetGeometry();
                                                                                

                                                                                Back to the sub chart menu

                                                                                Back to the Chapter menu


                                                                                Vertex Geometry Modifier
                                                                                Overview

                                                                                The VertexGeometryModifier, in conjunction with a VertexAccessor, helps to modify VertexGeometry objects by the means of the setters offered by the class interface. The interface offers also getters which are helpful to retrieve the values of the vertex elements from a given vertex buffer.

                                                                                Example

                                                                                The example below shows how to change the position values for the vertices from a vertex buffer of a given mesh.

                                                                                            VertexGeometry* vertexGeom;
                                                                                            bool isMutable = m_mesh3->GetVertexBuffer()->GetVertexGeometry()->GetVertexArrayResourceHandle().m_isMutable;
                                                                                            // Get the vertex geometry of the mesh
                                                                                            if (isMutable) {
                                                                                                vertexGeom = m_mesh3->GetVertexBuffer()->GetVertexGeometry();
                                                                                            }
                                                                                            else {
                                                                                                DiagnosticPlatform::ConsoleOut("VertexGeometryData not mutable");
                                                                                                break;
                                                                                            }
                                                                                             // The vertex accessor will be used by the vertex geometry modifier to access the vertices
                                                                                            VertexAccessor accessor(*vertexGeom);
                                                                                
                                                                                            // Create a vertex geometry modifier specifying as usage the type of vertex attribute
                                                                                            // which will be changed
                                                                                            VertexGeometryModifier modifier(*vertexGeom, VertexGeometry::Position, 0);
                                                                                            Float vertexData[3];
                                                                                            for(Int i = 0; i<8; i++) {
                                                                                                if(s_inflate) {
                                                                                                // Retrieve the position data of the vertex "i" in the vertexData array
                                                                                                modifier.GetVertexElement(accessor.GetVertex(i), vertexData, 3);
                                                                                
                                                                                                // Alter the data and set it back
                                                                                                modifier.SetVertexElement(accessor.GetMutableVertex(i), vertexData[0]*1.3F, vertexData[1]*1.3F, vertexData[2]*1.3F);
                                                                                                } 
                                                                                                else {
                                                                                                    // Set the position of the vertex with data get from an array (Float c_positionData[8][3])
                                                                                                    modifier.SetVertexElement(accessor.GetMutableVertex(i), c_positionData[i], 3);
                                                                                                }
                                                                                            }
                                                                                
                                                                                            // Update the vertex buffer on the mesh
                                                                                            m_mesh3->GetVertexBuffer()->Update(0, m_mesh3->GetVertexBuffer()->GetVertexGeometry()->GetVertexCount());
                                                                                

                                                                                Back to the Chapter menu


                                                                                Candera 3D Listeners

                                                                                Applications can receive notifications on scene graph events. Therefore implement and use a listener, which defines hooks to receive those notifications.

                                                                                Following listener interfaces are provided in Candera 3D:

                                                                                  Candera::RendererListener defines hooks that are called before or after a node is rendered. It supports events for OnNodePreRender and OnNodePostRender, so you are informed before and after a node is rendered. Candera::NodeListener defines hooks that are called when certain node functions are triggered, e.g. when a node's transformation changes. Candera::SceneListener defines hooks that are called on certain scene actions. The listener informs when a scene is activated. Candera::AnimationPlayerListener defines several hooks for the AnimationPlayer. It informs about changes of the animation, like when an animation has started, stopped, finished, resumed, paused and when the direction has changed. Candera::CameraListener defines hooks that are called before or after a camera is rendered. It supports events for OnPreRender, OnPostRender, OnProjectionChanged and OnViewChanged. Candera::ProjectionListener defines hooks that are called when projection parameters are changed. It supports OnProjectionChanged, which means the camera reacts to changes of the projection matrix associated and updates frustums accordingly.

                                                                                  In order to register a listener simply derive from the listener class and override pure virtual functions with custom code.

                                                                                  Example Listener Implementation

                                                                                  Refer to Using Animation Callback Functions for an example how to implement and use an Animation listener.

                                                                                  Back to the Chapter menu



                                                                                  2D Scene Graph and Nodes 

                                                                                  Chapters
                                                                                  Example Solutions
                                                                                    NodeManipulationSolution_2D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes EffectsSolution_2D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes SceneGraphDynamicsSolution_2D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes Layout2DSolution in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes

                                                                                    Back to the top menu


                                                                                    2D Scenes and Nodes
                                                                                    Scene Graph

                                                                                    The 2D scene graph is a tree structure which organizes nodes of type Candera::Node2D. The root of each scene graph has to be a node of type Candera::Scene2D. All nodes of type Candera::Node2D can hold sub nodes added by Candera::Node2D::AddChild().

                                                                                    Nodes of type Candera::RenderNode are representing content which has to be rendered to the target, e.g. text or a bitmap. At least one node of type Candera::Camera2D which is the link to the render target (e.g. a display) has to be part of the scene graph.

                                                                                    drawing-4-1676946524.png

                                                                                    RenderNode

                                                                                    Only nodes of type RenderNode are considered during rendering. Each render node requires a list of effects (effect chain) which implements the visual representation of that node. Each render node has a depth value as parameter which defines the order of rendering (z-order). Higher value means background, lower value means foreground.

                                                                                    drawing-4-1676946545.png

                                                                                    Transformations

                                                                                    The functionality to define the local coordinate system is derived from Candera::Transformable2D and consists of following components:

                                                                                      position, rotation, scale, and the pivot offset.

                                                                                      This information is always relative to its parent node. Changing one of these parameters affects the presentation of all child nodes. If for example a node is rotated, all child nodes are rotated accordingly. Each nodes rotation, translation (position) and scale values are combined in one transformation matrix which is multiplied with the parent nodes transformation matrix.

                                                                                      Back to the Chapter menu


                                                                                      2D Node Transformations 
                                                                                      2D Node Manipulation Example

                                                                                      To illustrate basic node transformation operations, the NodeManipulationWidget_2D and the DisplayPositionWidget2D part of the Tutorial Widgets cand be used. An usage example for NodeManipulationWidget_2D can be seen in NodeManipulationSolution_2D solution provided in the content folder of cgi_studio_player.

                                                                                      Please consider:

                                                                                        A Node2DToTransform on which the following transformations are made has to be selected in the widget. Only if the widget is enabled (this property is also derived from a base class), the setter methods of the widget properties will take effect. If a widget property setter changes a node property of the associated node, the visual effect can be seen, but note that the static node properties maintained by SceneComposer are not changed accordingly! Widget dynamics are never reflected to static scene structure. It is recommended to use SceneComposer only for property configuration and dynamics only in the Player.
                                                                                        Translations

                                                                                        Once the NodeManipulationWidget_2D is linked with a node from the static scene tree and enabled, the position coordinates can be set in the Player for this property to change the position.

                                                                                                    // Set node position
                                                                                                    m_node->SetPosition(m_position);    // set absolute node position
                                                                                                    // End Set node position
                                                                                        


                                                                                                    // Translate node
                                                                                                    m_node->Translate(m_translate);     // translate actual node position
                                                                                                    // End Translate node
                                                                                        

                                                                                        Candera::Transformable2D::SetPosition sets the absolute position of a node compared to Candera::Transformable2D::Translate, which adds the given vector to the current position. So setting the position first and then translating the node gives a different behavior than vice versa.

                                                                                        Rotations

                                                                                        Similar to translation, rotation can also be applied via Candera::Transformable2D::Rotate or Candera::Transformable2D::SetRotation.

                                                                                                    // Rotate node
                                                                                                    m_node->Rotate(m_rotate);
                                                                                                    // End Rotate node
                                                                                        
                                                                                        Scaling

                                                                                        Again there is also a Candera::Transformable2D::Scale and Candera::Transformable::SetScale method.

                                                                                                    // Scale node
                                                                                                    m_node->Scale(m_scale);
                                                                                                    // End Scale node
                                                                                        
                                                                                        Pivot Point

                                                                                        It is possible to change your pivot point with the Candera::Transformable2D::TranslatePivotPoint (or Candera::Transformable2D::SetPivotPoint) method. The pivot point can be used to define e.g. the rotation point that the node should rotate around. It affects the scaling too.

                                                                                        How to get the screen space coordinates of a node

                                                                                        With the DisplayPositionWidget2D you can retrieve the screen coordinates of an associated node. Please consider that a node and a camera have to be selected in the widget. In the solution the widget is disabled by default, so if you want to see an output of your display position, you need to enable it. To get the screen space coordinates of an associated node, you simply need to add the render target position of your node to the window position.

                                                                                          First you need the world position of your node. With this position you can retrieve the viewport position, which you need for retrieving the render target position.
                                                                                                  Vector2 worldPosition = node->GetWorldPosition();
                                                                                                  Vector2 viewportPos = Math2D::TransformSceneToViewport(*camera, worldPosition);
                                                                                                  Vector2 renderTargetPos = Math2D::TransformViewportToRenderTarget(*camera, viewportPos);
                                                                                          
                                                                                          Now you need the window.
                                                                                                  Window* w = camera->GetRenderTarget()->GetGraphicDeviceUnit()->ToWindow();
                                                                                                  if (w != 0) {
                                                                                                      Vector2 delta(static_cast<Float>(w->GetX()), static_cast<Float>(w->GetY()));
                                                                                          
                                                                                          With these two Candera::Vector2 you can calculate the screen space Candera::Vector2 of your node.
                                                                                                      Vector2 displayPos = delta + renderTargetPos;
                                                                                          
                                                                                          displayPos now contains the X and Y screen space coordinates of the selected node.

                                                                                          Back to the Chapter menu


                                                                                          2D Effects 
                                                                                          Description

                                                                                          Candera2D renders content exclusively by pieces of code which are named effects. Effects represent semantic functionality which considers hardware and driver capabilities.

                                                                                          The set of effects supported depends on the feature set of the underlying graphic device unit. This tutorial is based on the reference platform iMX6. Refer to the CanderaPlatformDevice API documentation to learn about the set of 2D effects supported on the platform used.

                                                                                          Chapters
                                                                                          Example Solution
                                                                                            2DCombinedEffects in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes


                                                                                            2D Effect Types

                                                                                            Effects can be distinguished in three types of operations:

                                                                                              Candera::BrushEffect2D provides means of generating graphical content out of user-defined data. An example would be an effect which generates a rectangle of solid color based on red, green and blue values. Brush effects generate pixel data as output. Candera::InPlaceEffect2D requires input data provided. Input data is always given in form of pixel data and is supposed to be provided by either a Brush Effect or another InPlace Effect. These kinds of effects can utilize any additional parameters to transform the pixel data to output data. The output is again pixel data. Candera::BlendEffect2D is very similar to InPlaceEffect2D. To be specific, every InPlace effect resembles a specialization of blend effect, namely that they blend with a fixed functionality. What makes Blend Effects special is only their purpose of being the effect which also takes the render target into account as an input. This allows blend effects to transform the input and the render target to any kind of combination of both. Output is again pixel data.

                                                                                              The effect types can be linked together so that they resemble an Effect Chain. An effect chain consists of one brush effect, zero to n InPlace effects and one blend effect.

                                                                                                The Brush Effect references already existing pixel data, so it defines the source data of the node (bitmap, solid color, text). InPlace Effects define pixel manipulation functions like mask, color transformation, etc. The Blend Effect is attached at the end of the chain so that the pixel data generated by the Brush Effect is processed together with the render target's pixel data to a combination.
                                                                                                Combined Effects

                                                                                                A Combined Effect is a single effect which represents a whole sequence of other effects in an effect chain. For example, if you want to render bitmap data with an alpha function, there usually is a combined effect which represents the Brush Effect and the Blend Effect in one single object.

                                                                                                  Combined Effect for Brush and Blend Effect: Candera::BitmapBrushBlend.

                                                                                                  This single object can take the advantage to perform operation in a single step as the external interfaces (pixel data) can be replaced internally by setting options in the native rendering API.

                                                                                                  Refer to Candera::CombinedEffect2D about which CombinedEffects are supported by Candera.



                                                                                                  Combined Effects Examples

                                                                                                  An example of various effects and how they are configured can be seen in 2DCombinedEffects solution from cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes.

                                                                                                  Bitmap Effects

                                                                                                  In order to render an image, a BitmapNode with one of the following effects must be set in a 2D scene:

                                                                                                  For the above effects, the following properties can be set to obtain different rendering results:

                                                                                                    Color - values for red, green, blue and alpha must be set Color Blend Factor for source and destination Color Blend Operation Alpha Blend Factor for source and destination Alpha Blend Operation

                                                                                                    An example of Bitmap effects with different properties is shown below:

                                                                                                    drawing-4-1676946798.png

                                                                                                    Candera::BitmapBrushColorBlend is a combined effect between Candera::BitmapBrushBlend and Candera::BitmapBrushColor. The properties of this effect sum up the properties of the other two. The values for the properties for Candera::BitmapBrushColorBlend used in the example, for left most, centre and right most images, are:

                                                                                                    drawing-4-1676946814.png

                                                                                                    Text Effects

                                                                                                    In order to render text, a TextNode with one of the following effects must be set in a 2D scene:

                                                                                                    Text, TextColor and Style properties can be set for the above effects. The Font of the text must be set for the Style property.

                                                                                                    For Candera::TextBrushBlend , the properties Color Blend Factor and Operation and Alpha Blend Factor and Operation can also be set to obtain different rendering results.

                                                                                                    An example of Candera::TextBrushBlend and related properties is shown below:

                                                                                                    drawing-4-1676946839.png

                                                                                                    Brush Effects

                                                                                                    The following effects can be used with a RenderNode in a 2D scene:

                                                                                                    Fill Color must be set for the above effects.

                                                                                                    For Candera::SolidColorBrushBlend, the properties Color Blend Factor and Operation and Alpha Blend Factor and Operation can also be set to obtain different rendering results.

                                                                                                    An example of Candera::SolidColorBrushBlend and related properties is shown below:

                                                                                                    drawing-4-1676946859.png


                                                                                                    drawing-4-1676946878.png

                                                                                                    Mask Effects

                                                                                                    As the name suggests, Mask effects allows masking different areas of a given image by applying a mask image with transparent areas.

                                                                                                    The following effects can be used with a BitmapNode:

                                                                                                    For the above effects, the following properties must be set:

                                                                                                      Image – the image on which the mask will be applied Mask – the mask image with transparent areas Mask Node – node used to control the position of the mask. If set to 0, the position of the current node is used. For iMX6, the mask takes into account the scale, the rotation and the pivot of the node.

                                                                                                      An example of mask effects is presented below:

                                                                                                      drawing-4-1676946920.png

                                                                                                      Left most image has no Mask Node set, therefore the BitmapNode associated with the effect is used. The image from the center has Mask Node set to a RenderNode with Rotation property = -50. Thus, the mask also appears rotated. Right most image has Mask Node set to a RenderNode with different values for Scale property (x= 0,5 ; y = 0,5). Thus, the mask also appears smaller.

                                                                                                      The properties Color Blend Factor and Operation and Alpha Blend Factor and Operation can also be set to obtain different rendering results.



                                                                                                      Manipulating an Effect on a Render Node

                                                                                                      To illustrate effect manipulation operations, the NodeManipulationWidget_2D part of the Tutorial Widgets in combination with the NodeManipulationSolution_2D provided in the content folder of cgi_studio_player can be used.


                                                                                                      The type Candera::RenderNode defines a node that shall be rendered. Each render node requires an effect chain, which implements the visual representation of the node.

                                                                                                      The following properties manipulate a Candera::SolidColorBrushBlend effect on a render node (this is a already combined effect with brush, inplace and blend):

                                                                                                        RenderNodeToManipulate: Select a RenderNode to manipulate its effect. Because of casts in the widgets code only select a render node with Candera::SolidColorBrushBlend, otherwise the casts will fail! (See Manipulating an effect) Set the widgets SolidColor, FillArea, Blend values to change the properties of the effect dynamically.
                                                                                                        Manipulating an Effect

                                                                                                        First the selected render node (which comes with type Candera::Node2D by the CDAProperty) is casted to a Candera::RenderNode.

                                                                                                            // Cast Node2D to RenderNode
                                                                                                            m_renderNode = Dynamic_Cast<RenderNode*>(node);
                                                                                                            // End Cast Node2D to RenderNode
                                                                                                        

                                                                                                        Next the first effect of the selected render node of type Candera::Effect2D is casted to Candera::SolidColorBrushBlend to get access to specialised properties.

                                                                                                        This simple example is based on a RenderNode with SolidColorBrushBlend effect, so if the example solution is changed, please take care to use only SolidColorBrushBlend on the node to manipulate.


                                                                                                            // Get and cast first effect of render node
                                                                                                            Effect2D* effect2D = node->GetEffect(0);
                                                                                                            SolidColorBrushBlend* effect = Dynamic_Cast<SolidColorBrushBlend*> (effect2D);
                                                                                                            // End Get and cast first effect of render node
                                                                                                        

                                                                                                        Now properties of the effect can be set.

                                                                                                                // Set solid color
                                                                                                                SolidColorBrush& brush = effect->GetSolidColorBrush();
                                                                                                                brush.Color() = m_color;
                                                                                                                // End Set solid color
                                                                                                        


                                                                                                                // Set fill area
                                                                                                                brush.Size() = m_rect;
                                                                                                                // End Set fill area
                                                                                                        

                                                                                                        The effect should be updated each time a property is changed. A good place for updating the effect might be the widget Update method.

                                                                                                                // Update effect
                                                                                                                static_cast<void>(effect->Update());
                                                                                                                // End Update effect
                                                                                                        

                                                                                                        Arbitrary properties on arbitrary effects can be manipulated the same way.



                                                                                                        How to Integrate a Custom Combined Effect into SceneComposer
                                                                                                        Integrate a custom effect to Candera and SceneComposer
                                                                                                          Create and implement your own effect. Integrate the effect into the effect library of the device.

                                                                                                          For DEVICE that would mean to modify cgi_studio_candera/src/CanderaPlatform/Device/DEVICE/2D/DEVICEEffectLibrary.cpp, so that the new effect implementation is included and the Effect2DLibrary MetaInfo is extended by the new effect. (DEVICE stands for your specific device)

                                                                                                            Integrate the new device library in SceneComposer. Therefore set CMake source to cgi_studio_player/src and build a SCHost.dll. The library CanderaDevice<device>_x86_Win32_<device>_Simulation_MSVC.lib is linked to the SCHost.dll, which than has the new effect included. Start SceneComposer with the new SCHost.dll. The new effect is listed in the toolbox for a 2D scene.
                                                                                                            How to create a combination of two effects

                                                                                                            There are several effects which can be combined to a new effect. How to combine two effects to a new one is shown in Candera::GlBitmapBrushColorMaskBlend implementation.

                                                                                                            For the new effect Candera::GlBitmapBrushColorMaskBlend you need a combination of Candera::BitmapBrushColorBlend and Candera::GlBitmapBrushMaskBlend. Create and implement the new effect analogous to Candera::GlBitmapBrushMaskBlend. Now apply following changes:

                                                                                                              The new effect contains both, MaskEffect and ColorEffect as member (wrapper, see in .h file). The implementation of the method Render() is a combination of Candera::BitmapBrushColorBlend::Render() and Candera::GlBitmapBrushMaskBlend::Render(). This method has to handle all four effects in the following order:
                                                                                                                blend effect, color effect, mask effect and brush effect. Upload(), Unload(), and Update() have to handle all four effects. Apply changes to the Effect Meta Info. The new effect needs all four effects (BitmapBrush, ColorEffect, MaskEffect, BlendEffect).




                                                                                                                Back to the Chapter menu


                                                                                                                2D Scene Graph Dynamics 
                                                                                                                Description

                                                                                                                Usually all required nodes are already specified and preconfigured via SceneComposer, so in most cases it won't be necessary to make any adaptations within the scene graph loaded from an asset at runtime.

                                                                                                                However, some use cases might require such adaptations. This tutorial covers the most common means to manipulate the scene graph structure dynamically.

                                                                                                                Chapters
                                                                                                                Example Solution
                                                                                                                  SceneGraphDynamicsSolution_2D in folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes


                                                                                                                  Adding and Removing 2D Nodes
                                                                                                                  Scene Graph Dynamics 2D Example

                                                                                                                  There are some differences between a 2D and a 3D scene graph. This chapter will explain the differences in detail.

                                                                                                                  For 2D scene graph dynamics, the following examples can be used:

                                                                                                                    SceneGraphDynamicsSolution_2D from folder cgi_studio_player/content/Tutorials/03_SceneGraphAndNodes SceneGraphDynamicsWidget_2D
                                                                                                                    Adding and Removing 2D Nodes

                                                                                                                    In the widget a RenderNode with text is created and added/removed to/from the 2D scene graph. For adding and removing 2D nodes on the scene graph the following properties can be used:

                                                                                                                      AddToNode2D: Select the node where the new RenderNode should be attached. This node can be any sub-type of Candera::Node2D.

                                                                                                                              CdaProperty(AddToNode, Candera::Node2D*, GetAddToNode, SetAddToNode)
                                                                                                                                  CdaDescription("Node2D, where a new TextNode shall be added to")
                                                                                                                                  CdaCategory("Adding and Removing 2D Nodes")
                                                                                                                              CdaPropertyEnd()
                                                                                                                      

                                                                                                                        TextNodeFont: Select the font of the new text node.

                                                                                                                                CdaProperty(TextNodeFont, Candera::TextRendering::Font, GetTextNodeFont, SetTextNodeFont)
                                                                                                                                    CdaDescription("Truetype Font of the new TextNode")
                                                                                                                                    CdaCategory("Adding and Removing 2D Nodes")
                                                                                                                                CdaPropertyEnd()
                                                                                                                        

                                                                                                                          AddTextNode: If AddTextNode is enabled, a new text node with the selected font is created and attached to the selected node. If disabled, the text node is removed from the scene graph again.

                                                                                                                                  CdaProperty(AddTextNode, bool, GetAddTextNode, SetAddTextNode)
                                                                                                                                      CdaDescription("If AddTextNode is enabled, a new TextNode with selected TextNodeFont will be added to the selected AddToNode property. If disabled the new TextNode will be removed.")
                                                                                                                                      CdaCategory("Adding and Removing 2D Nodes")
                                                                                                                                  CdaPropertyEnd()
                                                                                                                          
                                                                                                                          Creating a new Text Node

                                                                                                                          To display a new text, a new RenderNode is created with a Candera::TextBrushBlend effect.

                                                                                                                          2D effects are part of the device package, therefore in order to create a concrete instance of the effect, the effect must be enabled for the device. Please see chapter 2D Effects of this tutorial to see how to enable an effect for a certain device.

                                                                                                                          Candera::TextBrushBlend::Create creates a shared pointer of type Candera::TextBrushBlend, on which properties like text, font and color are set. Then the RenderNode is created and the effect is added.

                                                                                                                                  Candera::MemoryManagement::SharedPointer<Candera::TextBrushBlend> brush = Candera::TextBrushBlend::Create();
                                                                                                                                  Candera::MemoryManagement::SharedPointer<Candera::TextRendering::SharedStyle> style = Candera::TextRendering::SharedStyle::Create();
                                                                                                                          
                                                                                                                                  brush.GetSharedInstance().GetTextBrush().Text().Set("Node Added", 0);
                                                                                                                                  brush.GetSharedInstance().GetTextBrush().Color().Set(m_ColorTurquoise);
                                                                                                                          
                                                                                                                                  style.GetSharedInstance().SetDefaultFont(m_font);
                                                                                                                                  brush.GetSharedInstance().GetTextBrush().Style().Set(style);
                                                                                                                          
                                                                                                                                  //create and init new RenderNode
                                                                                                                                  m_addedNode = RenderNode::Create();
                                                                                                                                  m_addedNode->SetName("AddedNode");
                                                                                                                                  static_cast<void>(m_addedNode->AddEffect(brush.GetPointerToSharedInstance()));
                                                                                                                                  m_addedNode->SetPosition(Vector2(259.0F, 296.0F));
                                                                                                                          
                                                                                                                          Adding Text Node to Scene Graph

                                                                                                                          Next the text node is uploaded to VRAM and appended to the selected node.

                                                                                                                                  static_cast<void>(m_addedNode->Upload());
                                                                                                                                  static_cast<void>(m_addToNode->AddChild(m_addedNode));
                                                                                                                          
                                                                                                                          Removing and Destructing Text Node

                                                                                                                          A 2D node can be removed by calling Candera::Node2D::RemoveChild. This is also described in the 3D part of this chapter (see Removing and destructing the Billboard). For removing and completely destructing the node, following code is used:

                                                                                                                                  static_cast<void>(m_addedNode->Unload());
                                                                                                                                  m_addedNode->Dispose();
                                                                                                                                  m_addedNode = 0;
                                                                                                                          

                                                                                                                          The text node is unloaded from VRAM. The method Candera::Node2D::Dispose removes the node from its parent and frees the resources.

                                                                                                                          In SceneComposer the manipulated scene graph and the changed properties do not appear because it is only changed dynamically by the widget.

                                                                                                                          The widget must control memory and VRAM management of its internal dynamic subtree autonomously.



                                                                                                                          Replacing a 2D Effect
                                                                                                                          Replacing an Effect

                                                                                                                          In the SceneGraphDynamicsWidget_2D example, the effect of a Candera::RenderNode can be either replaced by a Candera::SolidColorBrushBlend or a Candera::BitmapBrushBlend effect. Of course the same procedure works for Text effects.

                                                                                                                          To replace the effect in the example, the following properties can be used:

                                                                                                                            NodeToChange: Select any render node with an effect whose appearance should be changed. Ensure that just a render node which has an effect is selected (in the sample solution this could be e.g. the node BitmapNode_BarTop). For further information see Adding Replacing Effect.

                                                                                                                                    CdaProperty(NodeToChange, Candera::Node2D* , GetNodeToChange, SetNodeToChange)
                                                                                                                                        CdaDescription("Select a RenderNode which effect should be exchanged")
                                                                                                                                        CdaCategory("Replacing a 2D Effect")
                                                                                                                                    CdaPropertyEnd()
                                                                                                                            

                                                                                                                              ChangeEffect: If ChangeEffect is enabled, the effect of the selected NodeToChange will be removed and a Candera::SolidColorBrushBlend effect is added to the node, instead. If disabled, the actual effect will be removed too and a Candera::BitmapBrushBlend effect is added to the node.

                                                                                                                                      CdaProperty(ChangeEffect, bool, GetChangeEffect, SetChangeEffect)
                                                                                                                                          CdaDescription("Change effect of selected NodeToChange. Set either a SolidColorBrushAlphaBlend (enabled) or BitmapBrushAlphaBlend effect (disabled).")
                                                                                                                                          CdaCategory("Replacing a 2D Effect")
                                                                                                                                      CdaPropertyEnd()
                                                                                                                              
                                                                                                                              Creating a Color Effect

                                                                                                                              First a new effect is created by creating an instance of Candera::SolidColorBrushBlend.

                                                                                                                              2D effects are part of the device package, therefore in order to create a concrete instance of the effect, the effect must be enabled for the device. Please see chapter 2D Effects of this tutorial to see how to enable an effect for a certain device.


                                                                                                                                      Candera::SolidColorBrushBlend::SharedPointer brush = Candera::SolidColorBrushBlend::Create();
                                                                                                                                      brush->GetSolidColorBrush().Size().Set(m_Rect);
                                                                                                                                      brush->GetSolidColorBrush().Color().Set(m_ColorBlue);
                                                                                                                                      brush->GetBlendEffect().SetBlendMode(RenderDevice2D::SourceAlpha, RenderDevice2D::InverseSourceAlpha, RenderDevice2D::Add);
                                                                                                                              
                                                                                                                              Adding Replacing Effect

                                                                                                                              Once the effect is created it can be added to the render node. In the following code snippet the selected NodeToChange is casted to a Candera::RenderNode (for this a RenderNode must be selected, otherwise the cast will fail). The first effect of the node is removed via its reference and the new created effect added.

                                                                                                                                  RenderNode* rn = Dynamic_Cast<RenderNode*>(m_nodeToChange);
                                                                                                                                  if (rn == 0) {
                                                                                                                                      return;
                                                                                                                                  }
                                                                                                                              
                                                                                                                                  static_cast<void>(rn->Unload());
                                                                                                                              
                                                                                                                                  //remove old effect
                                                                                                                                  Effect2D* oldEffect = rn->GetEffect(0);
                                                                                                                                  static_cast<void>(rn->RemoveEffect(oldEffect));
                                                                                                                              
                                                                                                                                  //add new effect
                                                                                                                                  static_cast<void>(rn->AddEffect(effect));
                                                                                                                                  static_cast<void>(rn->Upload());
                                                                                                                              
                                                                                                                              Creating a Bitmap Effect

                                                                                                                              Creating a Candera::BitmapBrushBlend effect is similar to creating other effects (see Creating a Color Effect). Just apply other properties.

                                                                                                                                      Candera::MemoryManagement::SharedPointer<Candera::BitmapBrushBlend> brush = Candera::BitmapBrushBlend::Create();
                                                                                                                                      Bitmap::SharedPointer bitmap = Base::GetAssetProvider()->GetBitmapById(CgiAssetNames::cosmosbgBmp);
                                                                                                                                      if (m_image != 0) {
                                                                                                                                          static_cast<void>(m_image->SetBitmap(bitmap));
                                                                                                                                      }
                                                                                                                                      brush.GetSharedInstance().GetBitmapBrush().Image().Set(m_image);
                                                                                                                                      brush.GetSharedInstance().GetBlendEffect().SetBlendMode(RenderDevice2D::SourceAlpha, RenderDevice2D::InverseSourceAlpha, RenderDevice2D::Add);
                                                                                                                              


                                                                                                                              In SceneComposer the manipulated scene graph and the changed properties do not appear because it is only changed dynamically by the widget.

                                                                                                                              The widget must control memory and VRAM management of its internal dynamic subtree autonomously.

                                                                                                                              Don't forget to set a name for the dynamically created nodes.



                                                                                                                              Cloning 2D Nodes 

                                                                                                                              Cloning 2D nodes is equivalent to cloning of 3D nodes. In accordance to Tree Cloning Strategies, the following support is provided for deep cloning:

                                                                                                                                Candera::TreeCloner2D is a specialization for the 2D scene tree of Candera::TreeClonerBase. Candera::DeepNode2DCloneStrategy provides a generic node strategy that clones the delegates the cloning of derived Nodes to specialized strategies. Candera::DeepCompositeGroup2DCloneStrategy resolves node binding by use of Candera::TreeMatch2D. Candera::DeepRenderNodeCloneStrategy resolves the sharing of effects by use of a map. Candera::DeepTreeCloner2D is a wrapper of Candera::DeepNode2DCloneStrategy that provides an interface similar to Candera::TreeCloner2D.

                                                                                                                                Refer to

                                                                                                                                as well as the example for cloning 3D nodes:

                                                                                                                                Back to the Chapter menu


                                                                                                                                Camera / Viewport 

                                                                                                                                The following example shows the interaction between scene and camera. The objects are placed relatively to the scene origin (which is the root node). The camera defines the view to that scene by defining also a position relative to the scene.

                                                                                                                                drawing-4-1676947701.png

                                                                                                                                The view port dimensions (width and height) relate to the area on the render target the camera is painting on.

                                                                                                                                drawing-4-1676947712.png



                                                                                                                                Back to the Chapter menu


                                                                                                                                2D Layout 
                                                                                                                                Description

                                                                                                                                In a typical user interface users need to distribute screen space to different elements. If the size of elements is dynamic, it's desired that the screen space distribution is done automatically based on the contents's natural size. To enable easy arrangement of elements, Candera2D supports layout functionalities.

                                                                                                                                Chapters
                                                                                                                                Example Solution
                                                                                                                                  Layout2DSolution in folder cgi_studio_player/content/Tutorials/Layout2DSolution.zip


                                                                                                                                  Candera::GridLayouter 
                                                                                                                                  Introduction

                                                                                                                                  Basically, in SceneComposer for each Candera::Group2D a Candera::Layouter can be attached. The attached layouter defines the arrangements of the group's children.

                                                                                                                                  Cell Spanning

                                                                                                                                  Candera::GridLayouter provides a feature that allows joining of adjacent columns and rows into a larger single cell.

                                                                                                                                  Cells can be joined horizontally, vertically or both. In order to achieve this, you must specify Row Span and Column Span properties for elements inside a Candera::GridLayouter:

                                                                                                                                    Row Span: Specifies the number of rows that the element should span across. Column Span: Specifies the number of columns that the element should span across.

                                                                                                                                    Default value for row and column span properties is 1.

                                                                                                                                    Example

                                                                                                                                    The Layout2DSolution provided in the content folder of cgi_studio_player gives an example how the 2D layout can be applied in SceneComposer. This section gives just a brief overview on layout features and shows how it looks like.

                                                                                                                                    In the example on the outermost group, a Candera::GridLayouter with 6 rows and 3 columns is defined.

                                                                                                                                    All child nodes, here a bunch of bitmap-, text- and solid-nodes, are arranged along the grid. Each inner grid element can set various dynamic properties which define its size and alignment inside a grid cell.

                                                                                                                                    Layouters can be nested. The outer grid contains a inner grid and two inner stack layouters (Candera::StackLayouter).

                                                                                                                                    drawing-4-1676947861.png

                                                                                                                                    The example consists of a grid layouter with fixed size 1280 x 756 px.

                                                                                                                                      The 3 column's width values are: 100 / 0,5 / 0,5.
                                                                                                                                        The first column has a absolute width of 100 px, the second and third column share the rest of the space (1180 px) relatively to each other (indicated by 0.0 <= value <= 1.0). In fact the effective width column 2 and 3 is calculated by the layouter as follows: (1180 * 0,5) / (0,5 + 0,5) = 590 px. The row heights are defined as 126 / 0,1 / 0,1 / 0,1 / 0,1 / 0,1..
                                                                                                                                          The first row has a absolute height of 126 px, and the remaining height (630 px) is partitioned relatively to the other rows. Row height = (630 * 0,1) / (0,1 + 0,1 + 0,1 + 0,1 + 0,1) = 126 px.

                                                                                                                                          If a size value is set to -1 the width or height is set to the preferred size of the inner elements.

                                                                                                                                          The bitmaps in the left column have different alignments (Top-Left, Centered, Bottom-Right). In the inner grid 9 bitmaps are scaled down (by the stretching property) to a fixed element size.

                                                                                                                                          The grey grid raster in the background is set up manually by solid nodes to illustrate the inner grid borders.

                                                                                                                                          Cell Spanning Example

                                                                                                                                          In the example, below a Candera::GridLayouter with 5 rows and 4 columns defined is used to exemplify how cell spanning is working:

                                                                                                                                            Horizontal Spanning: Element in Row(0) and Column(1) has a Column Span of 2. Vertical Spanning: Element in Row(1) and Column(3) has a Row Span of 3. Horizontal and Vertical Spanning: Element in Row(2) and Column(0) has a Row Span of 2 and Column Span of 2.
                                                                                                                                            drawing-4-1676947967.png

                                                                                                                                            Please note that single cells might still be used for other elements if needed, like in the following example:

                                                                                                                                            A Candera::GridLayouter with 2 rows and 2 columns is defined. Element in (0,0) has a row and column span of 2, but element at (1,1) is still accessible.

                                                                                                                                            drawing-4-1676948004.png



                                                                                                                                            See also:

                                                                                                                                              Grid Layouter in SceneComposer User Manual



                                                                                                                                              Candera::BaseLineLayouter 
                                                                                                                                              Introduction

                                                                                                                                              Candera::BaseLineLayouter behaves similar to a Horizontal StackLayouter but instead of aligning the objects to the client area of the Layouter, it aligns them to a line.

                                                                                                                                              The idea is to be able to align text with different sizes in different ways.

                                                                                                                                                For instance it can align all the text by the top of its bounding box (VTop). It can align the text by taking into consideration the bottom of the bounding box (VBottom). Or, the most interesting feature it can align the items with different size by their base line (VCenter).
                                                                                                                                                Example

                                                                                                                                                The Layout2DSolution provided in the content folder of cgi_studio_player gives an example how the 2D BaseLineLayouter can be applied in SceneComposer.

                                                                                                                                                  In the Scene2DBaseLineLayouter scene, on three groups, a Candera::BaseLineLayouter is defined. The base line offset configured on the groups is visualized by an orange line. The text parts of each group are defined with "VTop", "VBottom", or "VCenter", for the Vertical Alignment attribute.

                                                                                                                                                  The baseline can be either fixed or automatic. The automatic baseline is configured such that all the children fit from the top of the client area.

                                                                                                                                                  drawing-4-1676948049.png

                                                                                                                                                  See also:

                                                                                                                                                    Baseline Layouter in SceneComposer User Manual



                                                                                                                                                    Candera::OverlayLayouter 
                                                                                                                                                    Introduction

                                                                                                                                                    A Candera::OverlayLayouter is a container that layouts enfolded nodes by overlaying them in same place in a sorted sequence. With this layouter, elements can be arranged that they fulfill a given area and lay on top of one another.

                                                                                                                                                    Example

                                                                                                                                                    The Layout2DSolution provided in the content folder of cgi_studio_player gives an example how the OverlayLayouter can be applied in SceneComposer. Some important use cases are:

                                                                                                                                                      The outer group represents the given area, in which the nodes are arranged. You can set the size of the group to define the height and the width of the area. If you don't set any size, it will automatically be set to the size of the biggest inner child element. The sequence of the nodes in the overlay group is important. In the example the Inner_Overlay_Group is displayed in front of the Outer_Overlay_Group. Three very small images (mainBmp, gradient_verticalBmp, gradient_horizontalBmp, see in ExampleSolution) are stretched and blended to create a big image. They fulfill the given area. The text nodes are aligned to the center and in the corners. You can set several vertical and horizontal alignments for each node.
                                                                                                                                                      drawing-4-1676948095.png

                                                                                                                                                      See also:

                                                                                                                                                        Overlay Layouter in SceneComposer User Manual



                                                                                                                                                        Candera::DockPanelLayouter 
                                                                                                                                                        Introduction

                                                                                                                                                        The Candera::DockPanelLayouter provides an easy docking of elements to the left, right, top, bottom or center of the panel. To dock an element to the center of the panel, it must be the last child of the panel.

                                                                                                                                                        Example

                                                                                                                                                        The Layout2DSolution provided in the content folder of cgi_studio_player gives an example how the DockPanelLayouter can be applied in SceneComposer.

                                                                                                                                                        drawing-4-1676948156.png

                                                                                                                                                        See also:

                                                                                                                                                          Candera::DockPanelLayouter DockPanel Layouter in SceneComposer User Manual



                                                                                                                                                          Automatic Resize Depending on Content 
                                                                                                                                                          Introduction

                                                                                                                                                          This tutorial will show how to create resizable dialog popups using a hierarchy of groups and different kind of nodes (bitmap, solid color and text) arranged specifically using layouters.

                                                                                                                                                          Examples


                                                                                                                                                          Resizable Dialog Using Grid Layouter 
                                                                                                                                                          Example Using Grid Layouter

                                                                                                                                                          For this example the dialog elements are arranged using Grid and Overlay layouts.

                                                                                                                                                          Group Hierarchy

                                                                                                                                                          Create the parent group for the pop-up and name it GridDialog. Create another two groups (Background and Content) and add them as children of GridDialog group.

                                                                                                                                                          drawing-4-1676948340.png

                                                                                                                                                          Layout Configuration

                                                                                                                                                          Set the layout for each group as shown in the image below:

                                                                                                                                                          drawing-4-1676948359.png

                                                                                                                                                          Configure the column width and row height:

                                                                                                                                                          drawing-4-1676948390.png

                                                                                                                                                          In SceneComposer this can be achieved in the "Grid Layout Editor" (right click on the Background group and select "Configure Layout").

                                                                                                                                                          Adding Nodes

                                                                                                                                                          The Background group should be populated with bitmap or solid color nodes with the following settings:

                                                                                                                                                          drawing-4-1676948508.png

                                                                                                                                                          The Content group might be filled with one or more nodes of any type, as desired:

                                                                                                                                                          drawing-4-1676948531.png

                                                                                                                                                          Result

                                                                                                                                                          After putting everything together the dialog will look as above:

                                                                                                                                                          drawing-4-1676948555.png



                                                                                                                                                          Resizable Dialog Using DockPanel Layouter 
                                                                                                                                                          Example Using DockPanel Layouter

                                                                                                                                                          For this example the dialog elements are arranged using DockPanel and Overlay layouts.

                                                                                                                                                          Group Hierarchy

                                                                                                                                                          Create the following structure of groups:

                                                                                                                                                          drawing-4-1676948675.png

                                                                                                                                                          Layout Configuration

                                                                                                                                                          Set the layout for each group as shown in the image below:

                                                                                                                                                          drawing-4-1676948697.png


                                                                                                                                                          Be sure the order of adding the children groups in the Background group is Top - Bottom - Center otherwise the elements will not be arranged correctly.

                                                                                                                                                          Adding Nodes

                                                                                                                                                          The children groups of Background should be populated with bitmap or solid color nodes with the following settings:

                                                                                                                                                          drawing-4-1676948734.png

                                                                                                                                                          Be sure the order of nodes in the groups is Left - Right - Center otherwise the elements will not be arranged correctly.

                                                                                                                                                          The Content group should be configured as explained in the previous chapter for the dialog based on grid layout with the only difference that the text node will be replaced with a bitmap. Please see the Content group part from the Adding Nodes section.

                                                                                                                                                          Result

                                                                                                                                                          After putting everything together the dialog will look as above:

                                                                                                                                                          drawing-4-1676948769.png



                                                                                                                                                          Back to the Chapter menu


                                                                                                                                                          Candera 2D Listener 

                                                                                                                                                          Applications can receive notifications on scene graph events. Therefore implement a listener, which defines hooks to receive those notifications.
                                                                                                                                                          Following listener interfaces are provided in Candera 2D:

                                                                                                                                                            Candera::Camera2DListener defines hooks that are called before or after a Camera2D is rendered. In order to register a Camera2DListener to a Camera2D simply derive from Camera2DListener and override pure virtual functions with custom code. Candera::Renderer2DListener defines hooks that are called before or after a node is rendered. It supports events for OnNodePreRender and OnNodePostRender, so you are informed before and after a node is rendered.
                                                                                                                                                            Example Listener Implementation

                                                                                                                                                            Refer to Using Animation Callback Functions for an example how to implement and use an Animation listener.



                                                                                                                                                            Back to the Chapter menu