<commit_before>#include <AnimationComponent.hpp>

#include <queue>
#include <iostream>

#include <assimp/scene.h>

#include <Core/Containers/AlignedStdVector.hpp>
#include <Core/Utils/Graph/AdjacencyListOperation.hpp>
#include <Core/Animation/Pose/Pose.hpp>
#include <Core/Animation/Handle/HandleWeightOperation.hpp>
#include <Core/Animation/Handle/SkeletonUtils.hpp>

#include <Engine/Assets/KeyFrame/KeyTransform.hpp>
#include <Engine/Assets/KeyFrame/KeyPose.hpp>
#include <Engine/Managers/ComponentMessenger/ComponentMessenger.hpp>

#include <Drawing/SkeletonBoneDrawable.hpp>
#include "Core/Mesh/TriangleMesh.hpp"

using Ra::Engine::ComponentMessenger;
using Ra::Core::Animation::RefPose;
using Ra::Core::Animation::Skeleton;
using Ra::Core::Animation::WeightMatrix;

namespace AnimationPlugin
{

    bool AnimationComponent::picked(uint drawableIdx)
    {
        for (const auto& dr: m_boneDrawables)
        {
            if ( dr->getRenderObjectIndex() == int( drawableIdx ) )
            {
                m_selectedBone = dr->getBoneIndex();
                return true;
            }
        }
        return false;
    }

    void AnimationComponent::getProperties(Ra::Core::AlignedStdVector<Ra::Engine::EditableProperty> &propsOut) const
    {
        if ( m_selectedBone < 0 || uint(m_selectedBone) >= m_skel.size() )
        {
            return;
        }

        CORE_ASSERT(m_selectedBone >= 0 && uint(m_selectedBone) < m_skel.size(), "Oops");
        uint i = m_selectedBone;
        {
             const Ra::Core::Transform& tr = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL)[i];
             propsOut.push_back(Ra::Engine::EditableProperty(tr, std::string("Transform ") + std::to_string(i) + "-" + m_skel.getLabel(i)));
        }
    }

    void AnimationComponent::setProperty(const Ra::Engine::EditableProperty &prop)
    {
        int boneIdx = -1;
        CORE_ASSERT(prop.type == Ra::Engine::EditableProperty::TRANSFORM, "Only bones transforms are editable");
        for (uint i =0; i < m_skel.size(); ++i)
        {
            if (prop.name == std::string("Transform ") + std::to_string(i) + "-" + m_skel.getLabel(i))
            {
                boneIdx = i;
                break;
            }
        }
        CORE_ASSERT(boneIdx >=0 , "Property not found in skeleton");

        Ra::Core::Transform tr = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL)[boneIdx];
        // TODO (val) this code is copied from entity.cpp and could be factored.
        for(const auto& entry: prop.primitives)
        {
            const Ra::Engine::EditablePrimitive& prim = entry.primitive;
            switch (prim.getType())
            {
                case Ra::Engine::EditablePrimitive::POSITION:
                {
                    CORE_ASSERT(prim.getName() == "Position", "Inconsistent primitive");

                    // Val : ignore translation for now  (todo : use the flags in primitive).
                    // tr.translation() = prim.asPosition();
                }
                break;

                case Ra::Engine::EditablePrimitive::ROTATION:
                {
                    CORE_ASSERT(prim.getName() == "Rotation", "Inconsistent primitive");
                    tr.linear() = prim.asRotation().toRotationMatrix();
                }
                break;

                default:
                {
                    CORE_ASSERT(false, "Wrong primitive type in property");
                }
                break;
            }
        }

        // Transforms are edited in model space but applied to local space.
        const Ra::Core::Transform& TBoneModel = m_skel.getTransform(boneIdx, Ra::Core::Animation::Handle::SpaceType::MODEL);
        const Ra::Core::Transform& TBoneLocal = m_skel.getTransform(boneIdx, Ra::Core::Animation::Handle::SpaceType::LOCAL);
        auto diff = TBoneModel.inverse() *  tr;

        m_skel.setTransform(boneIdx,TBoneLocal * diff,  Ra::Core::Animation::Handle::SpaceType::LOCAL);
    }

    void AnimationComponent::setSkeleton(const Ra::Core::Animation::Skeleton& skel)
    {
        m_skel = skel;
        m_refPose = skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL);
    }

    void AnimationComponent::update(Scalar dt)
    {
        if( dt != 0.0 ) {
            const Scalar factor = ( m_slowMo ? 0.1 : 1.0 ) * m_speed;
            dt = factor * ( ( m_animationTimeStep ) ? m_dt[m_animationID] : dt );
        }
        // Ignore large dt that appear when the engine is paused (while loading a file for instance)
        if( !m_animationTimeStep && ( dt > 0.5 ) )
        {
            dt = 0;
        }

        // Compute the elapsed time
        m_animationTime += dt;

        // get the current pose from the animation
        if ( dt > 0 && m_animations.size() > 0)
        {
            m_wasReset = false;
            Ra::Core::Animation::Pose currentPose = m_animations[m_animationID].getPose(m_animationTime);

            // update the pose of the skeleton
            m_skel.setPose(currentPose, Ra::Core::Animation::Handle::SpaceType::LOCAL);
        }

        // update the render objects
        for (SkeletonBoneRenderObject* bone : m_boneDrawables)
        {
            bone->update();
        }
    }

    void AnimationComponent::setupSkeletonDisplay()
    {

        for( uint i = 0; i < m_skel.size(); ++i ) {
            if( !m_skel.m_graph.isLeaf( i ) ) {
                SkeletonBoneRenderObject* boneRenderObject = new SkeletonBoneRenderObject( m_skel.getLabel( i ), this, i, getRoMgr());
                m_boneDrawables.push_back(boneRenderObject);
                m_renderObjects.push_back( boneRenderObject->getRenderObjectIndex());
            } else {
                LOG( logDEBUG ) << "Bone " << m_skel.getLabel( i ) << " not displayed.";
            }
        }
    }

    void AnimationComponent::printSkeleton(const Ra::Core::Animation::Skeleton& skeleton)
    {
        std::deque<int> queue;
        std::deque<int> levels;

        queue.push_back(0);
        levels.push_back(0);
        while (!queue.empty())
        {
            int i = queue.front();
            queue.pop_front();
            int level = levels.front();
            levels.pop_front();
            std::cout<<i<<" "<<skeleton.getLabel(i)<<"\t";
            for(auto c : skeleton.m_graph.m_child[i] )
            {
                queue.push_back(c);
                levels.push_back(level+1);
            }

            if( levels.front() != level)
            {
                std::cout<<std::endl;
            }
        }
    }

    void AnimationComponent::reset()
    {
        m_animationTime = 0;
        m_skel.setPose(m_refPose, Ra::Core::Animation::Handle::SpaceType::MODEL);
        for (SkeletonBoneRenderObject* bone : m_boneDrawables)
        {
            bone->update();
        }
        m_wasReset = true;
    }

    Ra::Core::Animation::Pose AnimationComponent::getRefPose() const
    {
        return m_refPose;
    }
    Ra::Core::Animation::WeightMatrix AnimationComponent::getWeights() const
    {
        return m_weights;
    }

    void AnimationComponent::handleSkeletonLoading( const Ra::Asset::HandleData* data, const std::map< uint, uint >& duplicateTable ) {
        std::string name( m_name );
        name.append( "_" + data->getName() );

        std::string skelName = name;
        skelName.append( "_SKEL" );

        m_skel.setName( name );

        m_contentName = data->getName();

        std::map< uint, uint > indexTable;
        createSkeleton( data, indexTable );

        createWeightMatrix( data, indexTable, duplicateTable );
        m_refPose = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL);

        setupSkeletonDisplay();
        setupIO(m_contentName);
    }

    void AnimationComponent::handleAnimationLoading( const std::vector< Ra::Asset::AnimationData* > data ) {
        m_animations.clear();
        CORE_ASSERT( ( m_skel.size() != 0 ), "At least a skeleton should be loaded first.");
        if( data.empty() ) return;
        std::map< uint, uint > table;
        std::set< Ra::Asset::Time > keyTime;

        for( uint n = 0; n < data.size(); ++n ) {
            auto handleAnim = data[n]->getFrames();
            for( uint i = 0; i < m_skel.size(); ++i ) {
                for( uint j = 0; j < handleAnim.size(); ++j ) {
                    if( m_skel.getLabel( i ) == handleAnim[j].m_name ) {
                        table[j] = i;
                        auto set = handleAnim[j].m_anim.timeSchedule();
                        keyTime.insert( set.begin(), set.end() );
                    }
                }
            }

            Ra::Asset::KeyPose keypose;
            Ra::Core::Animation::Pose pose = m_skel.m_pose;

            m_animations.push_back( Ra::Core::Animation::Animation() );
            for( const auto& t : keyTime ) {
                for( const auto& it : table ) {
                    pose[it.second] = ( m_skel.m_graph.isRoot( it.second ) ) ? m_skel.m_pose[it.second] : handleAnim[it.first].m_anim.at( t );
                }
                m_animations.back().addKeyPose( pose, t );
                keypose.insertKeyFrame( t, pose );
            }

            m_dt.push_back( data[n]->getTimeStep() );
        }
        m_animationID = 0;
        m_animationTime = 0.0;
    }

    void AnimationComponent::createSkeleton( const Ra::Asset::HandleData* data, std::map< uint, uint >& indexTable ) {
        const uint size = data->getComponentDataSize();
        auto component = data->getComponentData();

        std::set< uint > root;
        for( uint i = 0; i < size; ++i ) {
            root.insert( i );
        }

        auto edgeList = data->getEdgeData();
        for( const auto& edge : edgeList ) {
            root.erase( edge[1] );
        }

        std::vector< bool > processed( size, false );
        for( const auto& r : root ) {
            addBone( -1, r, component, edgeList, processed, indexTable );
        }
    }

    void AnimationComponent::addBone( const int parent,
                                      const uint dataID,
                                      const Ra::Core::AlignedStdVector< Ra::Asset::HandleComponentData >& data,
                                      const Ra::Core::AlignedStdVector< Ra::Core::Vector2i >& edgeList,
                                      std::vector< bool >& processed,
                                      std::map< uint, uint >& indexTable ) {
        if( !processed[dataID] ) {
            processed[dataID] = true;
            uint index = m_skel.addBone( parent, data.at( dataID ).m_frame, Ra::Core::Animation::Handle::SpaceType::MODEL, data.at( dataID ).m_name );
            indexTable[dataID] = index;
            for( const auto& edge : edgeList ) {
                if( edge[0] == dataID ) {
                    addBone( index, edge[1], data, edgeList, processed, indexTable );
                }
            }
        }
    }

    void AnimationComponent::createWeightMatrix( const Ra::Asset::HandleData* data, const std::map< uint, uint >& indexTable, const std::map< uint, uint >& duplicateTable ) {
        // Bad bad bad hack
        // Fails eventually with a 1 vertex mesh
        uint vertexSize = 0;
        for( const auto& item : duplicateTable ) {
            if( item.second > vertexSize ) {
                vertexSize = ( item.second > vertexSize ) ? item.second : vertexSize;
            }
        }
        vertexSize++;
        m_weights.resize( vertexSize, data->getComponentDataSize() );

        //m_weights.resize( data->getVertexSize(), data->getComponentDataSize() );
        //m_weights.setZero();
        for( const auto& it : indexTable ) {
            const uint idx = it.first;
            const uint col = it.second;
            const uint size = data->getComponent( idx ).m_weight.size();
            for( uint i = 0; i < size; ++i ) {
                const uint   row = duplicateTable.at( data->getComponent( idx ).m_weight[i].first );
                const Scalar w   = data->getComponent( idx ).m_weight[i].second;
                m_weights.coeffRef( row, col ) = w;
            }
        }

        Ra::Core::Animation::checkWeightMatrix( m_weights, false );
    }

    void AnimationComponent::setupIO(const std::string &id)
    {
        ComponentMessenger::CallbackTypes<Skeleton>::Getter skelOut = std::bind( &AnimationComponent::getSkeletonOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Skeleton>( getEntity(), this, id, skelOut);

        ComponentMessenger::CallbackTypes<RefPose>::Getter refpOut = std::bind( &AnimationComponent::getRefPoseOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Ra::Core::Animation::Pose>( getEntity(), this, id, refpOut);

        ComponentMessenger::CallbackTypes<WeightMatrix>::Getter wOut = std::bind( &AnimationComponent::getWeightsOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Ra::Core::Animation::WeightMatrix>( getEntity(), this, id, wOut);

        ComponentMessenger::CallbackTypes<bool>::Getter resetOut = std::bind( &AnimationComponent::getWasReset, this );
        ComponentMessenger::getInstance()->registerOutput<bool>( getEntity(), this, id, resetOut);
    }

    const Ra::Core::Animation::Skeleton* AnimationComponent::getSkeletonOutput() const
    {
        return &m_skel;
    }

    const Ra::Core::Animation::WeightMatrix* AnimationComponent::getWeightsOutput() const
    {
        return &m_weights;
    }

    const Ra::Core::Animation::RefPose* AnimationComponent::getRefPoseOutput() const
    {
        return &m_refPose;
    }

    const bool* AnimationComponent::getWasReset() const
    {
        return &m_wasReset;
    }

    void AnimationComponent::toggleXray(bool on) const
    {
        for (const auto& b : m_boneDrawables)
        {
            b->toggleXray(on);
        }
    }

    void AnimationComponent::toggleSkeleton( const bool status ) {
        for (const auto& b : m_boneDrawables)
        {
            const auto id = b->getRenderObjectIndex();
            getRoMgr()->getRenderObject( id )->setVisible( status );
        }
    }

    void AnimationComponent::toggleAnimationTimeStep( const bool status ) {
        m_animationTimeStep = status;
    }

    void AnimationComponent::setSpeed( const Scalar value ) {
        m_speed = value;
    }

    void AnimationComponent::toggleSlowMotion( const bool status ) {
        m_slowMo = status;
    }

    void AnimationComponent::setAnimation( const uint i ) {
        if( i < m_animations.size() ) {
            m_animationID = i;
        }
    }

}
<commit_msg>Enabled the animation of the root bone from the files<commit_after>#include <AnimationComponent.hpp>

#include <queue>
#include <iostream>

#include <assimp/scene.h>

#include <Core/Containers/AlignedStdVector.hpp>
#include <Core/Utils/Graph/AdjacencyListOperation.hpp>
#include <Core/Animation/Pose/Pose.hpp>
#include <Core/Animation/Handle/HandleWeightOperation.hpp>
#include <Core/Animation/Handle/SkeletonUtils.hpp>

#include <Engine/Assets/KeyFrame/KeyTransform.hpp>
#include <Engine/Assets/KeyFrame/KeyPose.hpp>
#include <Engine/Managers/ComponentMessenger/ComponentMessenger.hpp>

#include <Drawing/SkeletonBoneDrawable.hpp>
#include "Core/Mesh/TriangleMesh.hpp"

using Ra::Engine::ComponentMessenger;
using Ra::Core::Animation::RefPose;
using Ra::Core::Animation::Skeleton;
using Ra::Core::Animation::WeightMatrix;

namespace AnimationPlugin
{

    bool AnimationComponent::picked(uint drawableIdx)
    {
        for (const auto& dr: m_boneDrawables)
        {
            if ( dr->getRenderObjectIndex() == int( drawableIdx ) )
            {
                m_selectedBone = dr->getBoneIndex();
                return true;
            }
        }
        return false;
    }

    void AnimationComponent::getProperties(Ra::Core::AlignedStdVector<Ra::Engine::EditableProperty> &propsOut) const
    {
        if ( m_selectedBone < 0 || uint(m_selectedBone) >= m_skel.size() )
        {
            return;
        }

        CORE_ASSERT(m_selectedBone >= 0 && uint(m_selectedBone) < m_skel.size(), "Oops");
        uint i = m_selectedBone;
        {
             const Ra::Core::Transform& tr = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL)[i];
             propsOut.push_back(Ra::Engine::EditableProperty(tr, std::string("Transform ") + std::to_string(i) + "-" + m_skel.getLabel(i)));
        }
    }

    void AnimationComponent::setProperty(const Ra::Engine::EditableProperty &prop)
    {
        int boneIdx = -1;
        CORE_ASSERT(prop.type == Ra::Engine::EditableProperty::TRANSFORM, "Only bones transforms are editable");
        for (uint i =0; i < m_skel.size(); ++i)
        {
            if (prop.name == std::string("Transform ") + std::to_string(i) + "-" + m_skel.getLabel(i))
            {
                boneIdx = i;
                break;
            }
        }
        CORE_ASSERT(boneIdx >=0 , "Property not found in skeleton");

        Ra::Core::Transform tr = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL)[boneIdx];
        // TODO (val) this code is copied from entity.cpp and could be factored.
        for(const auto& entry: prop.primitives)
        {
            const Ra::Engine::EditablePrimitive& prim = entry.primitive;
            switch (prim.getType())
            {
                case Ra::Engine::EditablePrimitive::POSITION:
                {
                    CORE_ASSERT(prim.getName() == "Position", "Inconsistent primitive");

                    // Val : ignore translation for now  (todo : use the flags in primitive).
                    // tr.translation() = prim.asPosition();
                }
                break;

                case Ra::Engine::EditablePrimitive::ROTATION:
                {
                    CORE_ASSERT(prim.getName() == "Rotation", "Inconsistent primitive");
                    tr.linear() = prim.asRotation().toRotationMatrix();
                }
                break;

                default:
                {
                    CORE_ASSERT(false, "Wrong primitive type in property");
                }
                break;
            }
        }

        // Transforms are edited in model space but applied to local space.
        const Ra::Core::Transform& TBoneModel = m_skel.getTransform(boneIdx, Ra::Core::Animation::Handle::SpaceType::MODEL);
        const Ra::Core::Transform& TBoneLocal = m_skel.getTransform(boneIdx, Ra::Core::Animation::Handle::SpaceType::LOCAL);
        auto diff = TBoneModel.inverse() *  tr;

        m_skel.setTransform(boneIdx,TBoneLocal * diff,  Ra::Core::Animation::Handle::SpaceType::LOCAL);
    }

    void AnimationComponent::setSkeleton(const Ra::Core::Animation::Skeleton& skel)
    {
        m_skel = skel;
        m_refPose = skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL);
    }

    void AnimationComponent::update(Scalar dt)
    {
        if( dt != 0.0 ) {
            const Scalar factor = ( m_slowMo ? 0.1 : 1.0 ) * m_speed;
            dt = factor * ( ( m_animationTimeStep ) ? m_dt[m_animationID] : dt );
        }
        // Ignore large dt that appear when the engine is paused (while loading a file for instance)
        if( !m_animationTimeStep && ( dt > 0.5 ) )
        {
            dt = 0;
        }

        // Compute the elapsed time
        m_animationTime += dt;

        // get the current pose from the animation
        if ( dt > 0 && m_animations.size() > 0)
        {
            m_wasReset = false;
            Ra::Core::Animation::Pose currentPose = m_animations[m_animationID].getPose(m_animationTime);

            // update the pose of the skeleton
            m_skel.setPose(currentPose, Ra::Core::Animation::Handle::SpaceType::LOCAL);
        }

        // update the render objects
        for (SkeletonBoneRenderObject* bone : m_boneDrawables)
        {
            bone->update();
        }
    }

    void AnimationComponent::setupSkeletonDisplay()
    {

        for( uint i = 0; i < m_skel.size(); ++i ) {
            if( !m_skel.m_graph.isLeaf( i ) ) {
                SkeletonBoneRenderObject* boneRenderObject = new SkeletonBoneRenderObject( m_skel.getLabel( i ), this, i, getRoMgr());
                m_boneDrawables.push_back(boneRenderObject);
                m_renderObjects.push_back( boneRenderObject->getRenderObjectIndex());
            } else {
                LOG( logDEBUG ) << "Bone " << m_skel.getLabel( i ) << " not displayed.";
            }
        }
    }

    void AnimationComponent::printSkeleton(const Ra::Core::Animation::Skeleton& skeleton)
    {
        std::deque<int> queue;
        std::deque<int> levels;

        queue.push_back(0);
        levels.push_back(0);
        while (!queue.empty())
        {
            int i = queue.front();
            queue.pop_front();
            int level = levels.front();
            levels.pop_front();
            std::cout<<i<<" "<<skeleton.getLabel(i)<<"\t";
            for(auto c : skeleton.m_graph.m_child[i] )
            {
                queue.push_back(c);
                levels.push_back(level+1);
            }

            if( levels.front() != level)
            {
                std::cout<<std::endl;
            }
        }
    }

    void AnimationComponent::reset()
    {
        m_animationTime = 0;
        m_skel.setPose(m_refPose, Ra::Core::Animation::Handle::SpaceType::MODEL);
        for (SkeletonBoneRenderObject* bone : m_boneDrawables)
        {
            bone->update();
        }
        m_wasReset = true;
    }

    Ra::Core::Animation::Pose AnimationComponent::getRefPose() const
    {
        return m_refPose;
    }
    Ra::Core::Animation::WeightMatrix AnimationComponent::getWeights() const
    {
        return m_weights;
    }

    void AnimationComponent::handleSkeletonLoading( const Ra::Asset::HandleData* data, const std::map< uint, uint >& duplicateTable ) {
        std::string name( m_name );
        name.append( "_" + data->getName() );

        std::string skelName = name;
        skelName.append( "_SKEL" );

        m_skel.setName( name );

        m_contentName = data->getName();

        std::map< uint, uint > indexTable;
        createSkeleton( data, indexTable );

        createWeightMatrix( data, indexTable, duplicateTable );
        m_refPose = m_skel.getPose( Ra::Core::Animation::Handle::SpaceType::MODEL);

        setupSkeletonDisplay();
        setupIO(m_contentName);
    }

    void AnimationComponent::handleAnimationLoading( const std::vector< Ra::Asset::AnimationData* > data ) {
        m_animations.clear();
        CORE_ASSERT( ( m_skel.size() != 0 ), "At least a skeleton should be loaded first.");
        if( data.empty() ) return;
        std::map< uint, uint > table;
        std::set< Ra::Asset::Time > keyTime;

        for( uint n = 0; n < data.size(); ++n ) {
            auto handleAnim = data[n]->getFrames();
            for( uint i = 0; i < m_skel.size(); ++i ) {
                for( uint j = 0; j < handleAnim.size(); ++j ) {
                    if( m_skel.getLabel( i ) == handleAnim[j].m_name ) {
                        table[j] = i;
                        auto set = handleAnim[j].m_anim.timeSchedule();
                        keyTime.insert( set.begin(), set.end() );
                    }
                }
            }

            Ra::Asset::KeyPose keypose;
            Ra::Core::Animation::Pose pose = m_skel.m_pose;

            m_animations.push_back( Ra::Core::Animation::Animation() );
            for( const auto& t : keyTime ) {
                for( const auto& it : table ) {
                    //pose[it.second] = ( m_skel.m_graph.isRoot( it.second ) ) ? m_skel.m_pose[it.second] : handleAnim[it.first].m_anim.at( t );
                    pose[it.second] = handleAnim[it.first].m_anim.at( t );
                }
                m_animations.back().addKeyPose( pose, t );
                keypose.insertKeyFrame( t, pose );
            }

            m_dt.push_back( data[n]->getTimeStep() );
        }
        m_animationID = 0;
        m_animationTime = 0.0;
    }

    void AnimationComponent::createSkeleton( const Ra::Asset::HandleData* data, std::map< uint, uint >& indexTable ) {
        const uint size = data->getComponentDataSize();
        auto component = data->getComponentData();

        std::set< uint > root;
        for( uint i = 0; i < size; ++i ) {
            root.insert( i );
        }

        auto edgeList = data->getEdgeData();
        for( const auto& edge : edgeList ) {
            root.erase( edge[1] );
        }

        std::vector< bool > processed( size, false );
        for( const auto& r : root ) {
            addBone( -1, r, component, edgeList, processed, indexTable );
        }
    }

    void AnimationComponent::addBone( const int parent,
                                      const uint dataID,
                                      const Ra::Core::AlignedStdVector< Ra::Asset::HandleComponentData >& data,
                                      const Ra::Core::AlignedStdVector< Ra::Core::Vector2i >& edgeList,
                                      std::vector< bool >& processed,
                                      std::map< uint, uint >& indexTable ) {
        if( !processed[dataID] ) {
            processed[dataID] = true;
            uint index = m_skel.addBone( parent, data.at( dataID ).m_frame, Ra::Core::Animation::Handle::SpaceType::MODEL, data.at( dataID ).m_name );
            indexTable[dataID] = index;
            for( const auto& edge : edgeList ) {
                if( edge[0] == dataID ) {
                    addBone( index, edge[1], data, edgeList, processed, indexTable );
                }
            }
        }
    }

    void AnimationComponent::createWeightMatrix( const Ra::Asset::HandleData* data, const std::map< uint, uint >& indexTable, const std::map< uint, uint >& duplicateTable ) {
        // Bad bad bad hack
        // Fails eventually with a 1 vertex mesh
        uint vertexSize = 0;
        for( const auto& item : duplicateTable ) {
            if( item.second > vertexSize ) {
                vertexSize = ( item.second > vertexSize ) ? item.second : vertexSize;
            }
        }
        vertexSize++;
        m_weights.resize( vertexSize, data->getComponentDataSize() );

        //m_weights.resize( data->getVertexSize(), data->getComponentDataSize() );
        //m_weights.setZero();
        for( const auto& it : indexTable ) {
            const uint idx = it.first;
            const uint col = it.second;
            const uint size = data->getComponent( idx ).m_weight.size();
            for( uint i = 0; i < size; ++i ) {
                const uint   row = duplicateTable.at( data->getComponent( idx ).m_weight[i].first );
                const Scalar w   = data->getComponent( idx ).m_weight[i].second;
                m_weights.coeffRef( row, col ) = w;
            }
        }

        Ra::Core::Animation::checkWeightMatrix( m_weights, false );
    }

    void AnimationComponent::setupIO(const std::string &id)
    {
        ComponentMessenger::CallbackTypes<Skeleton>::Getter skelOut = std::bind( &AnimationComponent::getSkeletonOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Skeleton>( getEntity(), this, id, skelOut);

        ComponentMessenger::CallbackTypes<RefPose>::Getter refpOut = std::bind( &AnimationComponent::getRefPoseOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Ra::Core::Animation::Pose>( getEntity(), this, id, refpOut);

        ComponentMessenger::CallbackTypes<WeightMatrix>::Getter wOut = std::bind( &AnimationComponent::getWeightsOutput, this );
        ComponentMessenger::getInstance()->registerOutput<Ra::Core::Animation::WeightMatrix>( getEntity(), this, id, wOut);

        ComponentMessenger::CallbackTypes<bool>::Getter resetOut = std::bind( &AnimationComponent::getWasReset, this );
        ComponentMessenger::getInstance()->registerOutput<bool>( getEntity(), this, id, resetOut);
    }

    const Ra::Core::Animation::Skeleton* AnimationComponent::getSkeletonOutput() const
    {
        return &m_skel;
    }

    const Ra::Core::Animation::WeightMatrix* AnimationComponent::getWeightsOutput() const
    {
        return &m_weights;
    }

    const Ra::Core::Animation::RefPose* AnimationComponent::getRefPoseOutput() const
    {
        return &m_refPose;
    }

    const bool* AnimationComponent::getWasReset() const
    {
        return &m_wasReset;
    }

    void AnimationComponent::toggleXray(bool on) const
    {
        for (const auto& b : m_boneDrawables)
        {
            b->toggleXray(on);
        }
    }

    void AnimationComponent::toggleSkeleton( const bool status ) {
        for (const auto& b : m_boneDrawables)
        {
            const auto id = b->getRenderObjectIndex();
            getRoMgr()->getRenderObject( id )->setVisible( status );
        }
    }

    void AnimationComponent::toggleAnimationTimeStep( const bool status ) {
        m_animationTimeStep = status;
    }

    void AnimationComponent::setSpeed( const Scalar value ) {
        m_speed = value;
    }

    void AnimationComponent::toggleSlowMotion( const bool status ) {
        m_slowMo = status;
    }

    void AnimationComponent::setAnimation( const uint i ) {
        if( i < m_animations.size() ) {
            m_animationID = i;
        }
    }

}
<|endoftext|>


<commit_before>#ifndef ANIMPLUGIN_ANIMATION_COMPONENT_HPP_
#define ANIMPLUGIN_ANIMATION_COMPONENT_HPP_

#include <AnimationPluginMacros.hpp>

#include <Core/Animation/Animation.hpp>
#include <Core/Animation/Handle/Skeleton.hpp>
#include <Core/Animation/Handle/HandleWeight.hpp>
#include <Core/Animation/Pose/Pose.hpp>
#include <Core/File/AnimationData.hpp>
#include <Core/File/HandleData.hpp>

#include <Engine/Component/Component.hpp>

#include <memory>

namespace AnimationPlugin
{

    class SkeletonBoneRenderObject;

    class AnimationComponent : public Ra::Engine::Component
    {
    public:
        AnimationComponent(const std::string& name);
        virtual ~AnimationComponent();

        virtual void initialize() override{}

        void setSkeleton(const Ra::Core::Animation::Skeleton& skel);

        inline Ra::Core::Animation::Skeleton& getSkeleton() { return m_skel; }
        ANIM_PLUGIN_API Ra::Core::Animation::WeightMatrix getWeights() const;
        ANIM_PLUGIN_API Ra::Core::Animation::Pose getRefPose() const;

        /// Update the skeleton with an animation.
        void update(Scalar dt);
        void reset();
        ANIM_PLUGIN_API void setXray(bool on) const;

        void toggleSkeleton( const bool status );
        void toggleAnimationTimeStep( const bool status );
        void setSpeed( const Scalar value );
        void toggleSlowMotion( const bool status );
        void setAnimation( const uint i );

        uint getBoneIdx(Ra::Core::Index index) const ;
        Scalar getTime() const;

        void handleSkeletonLoading( const Ra::Asset::HandleData* data, const std::vector<uint>& duplicateTable, uint nbMeshVertices );
        void handleAnimationLoading( const std::vector< Ra::Asset::AnimationData* > data );

        //
        // Editable interface
        //

        virtual bool canEdit(Ra::Core::Index roIdx) const override;

        virtual Ra::Core::Transform getTransform(Ra::Core::Index roIdx) const override;

        virtual void setTransform(Ra::Core::Index roIdx, const Ra::Core::Transform& transform) override;

    public:
        // debug function to display the hierarchy
        void printSkeleton(const Ra::Core::Animation::Skeleton& skeleton);

        //
        // Loading data functions
        //

        void setWeights (Ra::Core::Animation::WeightMatrix m);

        // Component communication
        void setContentName (const std::string name);
        void setupIO( const std::string& id );

        const Ra::Core::Animation::Skeleton*     getSkeletonOutput() const;
        const Ra::Core::Animation::RefPose*      getRefPoseOutput() const;
        const Ra::Core::Animation::WeightMatrix* getWeightsOutput() const;
        const bool*                              getWasReset() const;
        const Ra::Core::Animation::Animation*    getAnimation() const;
        const Scalar* getTimeOutput() const;

    private:
        // Internal function to create the skinning weights.
        void createWeightMatrix( const Ra::Asset::HandleData* data, const std::map< uint, uint >& indexTable,
                                 const std::vector<uint>& duplicateTable, uint nbMeshVertices );

        // Internal function to create the bone display objects.
        void setupSkeletonDisplay();

    private:
        std::string m_contentName;

        Ra::Core::Animation::Skeleton m_skel; // Skeleton
        Ra::Core::Animation::RefPose m_refPose; // Ref pose in model space.
        std::vector<Ra::Core::Animation::Animation> m_animations;
        Ra::Core::Animation::WeightMatrix m_weights; // Skinning weights ( should go in skinning )
        std::vector< std::unique_ptr<SkeletonBoneRenderObject> > m_boneDrawables ; // Vector of bone display objects
        uint   m_animationID;
        bool   m_animationTimeStep;
        Scalar m_animationTime;
        std::vector< Scalar > m_dt;
        Scalar m_speed;
        bool   m_slowMo;

        bool m_wasReset;
        bool m_resetDone;
    };

}

#endif //ANIMPLUGIN_ANIMATION_COMPONENT_HPP_
<commit_msg>Add missing ANIM_PLUGIN_API macro on AnimationComponent class<commit_after>#ifndef ANIMPLUGIN_ANIMATION_COMPONENT_HPP_
#define ANIMPLUGIN_ANIMATION_COMPONENT_HPP_

#include <AnimationPluginMacros.hpp>

#include <Core/Animation/Animation.hpp>
#include <Core/Animation/Handle/Skeleton.hpp>
#include <Core/Animation/Handle/HandleWeight.hpp>
#include <Core/Animation/Pose/Pose.hpp>
#include <Core/File/AnimationData.hpp>
#include <Core/File/HandleData.hpp>

#include <Engine/Component/Component.hpp>

#include <memory>

namespace AnimationPlugin
{

    class SkeletonBoneRenderObject;

    class ANIM_PLUGIN_API AnimationComponent : public Ra::Engine::Component
    {
    public:
        AnimationComponent(const std::string& name);
        virtual ~AnimationComponent();

        virtual void initialize() override{}

        void setSkeleton(const Ra::Core::Animation::Skeleton& skel);

        inline Ra::Core::Animation::Skeleton& getSkeleton() { return m_skel; }
        Ra::Core::Animation::WeightMatrix getWeights() const;
        Ra::Core::Animation::Pose getRefPose() const;

        /// Update the skeleton with an animation.
        void update(Scalar dt);
        void reset();
        void setXray(bool on) const;

        void toggleSkeleton( const bool status );
        void toggleAnimationTimeStep( const bool status );
        void setSpeed( const Scalar value );
        void toggleSlowMotion( const bool status );
        void setAnimation( const uint i );

        uint getBoneIdx(Ra::Core::Index index) const ;
        Scalar getTime() const;

        void handleSkeletonLoading( const Ra::Asset::HandleData* data, const std::vector<uint>& duplicateTable, uint nbMeshVertices );
        void handleAnimationLoading( const std::vector< Ra::Asset::AnimationData* > data );

        //
        // Editable interface
        //

        virtual bool canEdit(Ra::Core::Index roIdx) const override;

        virtual Ra::Core::Transform getTransform(Ra::Core::Index roIdx) const override;

        virtual void setTransform(Ra::Core::Index roIdx, const Ra::Core::Transform& transform) override;

    public:
        // debug function to display the hierarchy
        void printSkeleton(const Ra::Core::Animation::Skeleton& skeleton);

        //
        // Loading data functions
        //

        void setWeights (Ra::Core::Animation::WeightMatrix m);

        // Component communication
        void setContentName (const std::string name);
        void setupIO( const std::string& id );

        const Ra::Core::Animation::Skeleton*     getSkeletonOutput() const;
        const Ra::Core::Animation::RefPose*      getRefPoseOutput() const;
        const Ra::Core::Animation::WeightMatrix* getWeightsOutput() const;
        const bool*                              getWasReset() const;
        const Ra::Core::Animation::Animation*    getAnimation() const;
        const Scalar* getTimeOutput() const;

    private:
        // Internal function to create the skinning weights.
        void createWeightMatrix( const Ra::Asset::HandleData* data, const std::map< uint, uint >& indexTable,
                                 const std::vector<uint>& duplicateTable, uint nbMeshVertices );

        // Internal function to create the bone display objects.
        void setupSkeletonDisplay();

    private:
        std::string m_contentName;

        Ra::Core::Animation::Skeleton m_skel; // Skeleton
        Ra::Core::Animation::RefPose m_refPose; // Ref pose in model space.
        std::vector<Ra::Core::Animation::Animation> m_animations;
        Ra::Core::Animation::WeightMatrix m_weights; // Skinning weights ( should go in skinning )
        std::vector< std::unique_ptr<SkeletonBoneRenderObject> > m_boneDrawables ; // Vector of bone display objects
        uint   m_animationID;
        bool   m_animationTimeStep;
        Scalar m_animationTime;
        std::vector< Scalar > m_dt;
        Scalar m_speed;
        bool   m_slowMo;

        bool m_wasReset;
        bool m_resetDone;
    };

}

#endif //ANIMPLUGIN_ANIMATION_COMPONENT_HPP_
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 * Copyright (c) 2019 Google LLC
 * Copyright (c) 2019 The Khronos Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Functional tests using amber
 *//*--------------------------------------------------------------------*/

#include <amber/amber.h>

#include <iostream>

#include "deDefs.hpp"
#include "deUniquePtr.hpp"
#include "deFilePath.hpp"
#include "vktTestCaseUtil.hpp"
#include "tcuTestLog.hpp"
#include "vktAmberTestCase.hpp"
#include "vktAmberHelper.hpp"
#include "tcuResource.hpp"
#include "tcuTestLog.hpp"

namespace vkt
{
namespace cts_amber
{

AmberTestCase::AmberTestCase (tcu::TestContext& testCtx,
							  const char*		name,
							  const char*		description)
	: TestCase(testCtx, name, description),
	  m_recipe(DE_NULL)
{
}

AmberTestCase::~AmberTestCase (void)
{
	delete m_recipe;
}

TestInstance* AmberTestCase::createInstance(Context& ctx) const
{
	return new AmberTestInstance(ctx, m_recipe);
}

static amber::EngineConfig* createEngineConfig(Context& ctx)
{
	amber::EngineConfig*	vkConfig = GetVulkanConfig(ctx.getInstance(),
			ctx.getPhysicalDevice(), ctx.getDevice(), &ctx.getDeviceFeatures(),
			&ctx.getDeviceFeatures2(), ctx.getInstanceExtensions(),
			ctx.getDeviceExtensions(), ctx.getUniversalQueueFamilyIndex(),
			ctx.getUniversalQueue(), ctx.getInstanceProcAddr());

	return vkConfig;
}

// Returns true if the given feature is supported by the device.
// Throws an internal error If the feature is not recognized at all.
static bool isFeatureSupported(const vkt::Context& ctx, const std::string& feature)
{
	if (feature == "Features.shaderInt16")
		return ctx.getDeviceFeatures().shaderInt16;
	if (feature == "Features.shaderInt64")
		return ctx.getDeviceFeatures().shaderInt64;
	if (feature == "Features.tessellationShader")
		return ctx.getDeviceFeatures().tessellationShader;
	if (feature == "Features.geometryShader")
		return ctx.getDeviceFeatures().tessellationShader;
	if (feature == "Features.vertexPipelineStoresAndAtomics")
		return ctx.getDeviceFeatures().vertexPipelineStoresAndAtomics;
	if (feature == "VariablePointerFeatures.variablePointersStorageBuffer")
		return ctx.getVariablePointersFeatures().variablePointersStorageBuffer;
	if (feature == "VariablePointerFeatures.variablePointers")
		return ctx.getVariablePointersFeatures().variablePointers;

	std::string message = std::string("Unexpected feature name: ") + feature;
	TCU_THROW(InternalError, message.c_str());
}

void AmberTestCase::checkSupport(Context& ctx) const
{
	// Check for instance and device extensions as declared by the test code.
	if (m_required_extensions.size())
	{
		std::set<std::string> device_extensions(ctx.getDeviceExtensions().begin(),
												ctx.getDeviceExtensions().end());
		std::set<std::string> instance_extensions(ctx.getInstanceExtensions().begin(),
												  ctx.getInstanceExtensions().end());
		std::string missing;
		for (std::set<std::string>::iterator iter = m_required_extensions.begin();
			 iter != m_required_extensions.end();
			 ++iter)
		{
			const std::string extension = *iter;
			if ((device_extensions.count(extension) == 0) &&
				(instance_extensions.count(extension) == 0))
			{
				missing += " " + extension;
			}
		}
		if (missing.size() > 0)
		{
			std::string message("Test requires unsupported extensions:");
			message += missing;
			TCU_THROW(NotSupportedError, message.c_str());
		}
	}

	// Check for required features.  Do this after extensions are checked because
	// some feature checks are only valid when corresponding extensions are enabled.
	if (m_required_features.size())
	{
		std::string missing;
		for (std::set<std::string>::iterator iter = m_required_features.begin();
			 iter != m_required_features.end();
			 ++iter)
		{
			const std::string feature = *iter;
			if (!isFeatureSupported(ctx, feature))
			{
				missing += " " + feature;
			}
		}
		if (missing.size() > 0)
		{
			std::string message("Test requires unsupported features:");
			message += missing;
			TCU_THROW(NotSupportedError, message.c_str());
		}
	}

	// Check for extensions as declared by the Amber script itself.  Throw an internal
	// error if that's more demanding.
	amber::Amber			am;
	amber::Options			amber_options;
	amber_options.engine	= amber::kEngineTypeVulkan;
	amber_options.config	= createEngineConfig(ctx);
	amber_options.delegate	= DE_NULL;

	amber::Result r = am.AreAllRequirementsSupported(m_recipe, &amber_options);
	if (!r.IsSuccess())
	{
		// dEQP does not to rely on external code to determine whether
		// a test is supported.  So throw an internal error here instead
		// of a NotSupportedError.  If an Amber test is not supported, then
		// you must override this method and throw a NotSupported exception
		// before reach here.
		TCU_THROW(InternalError, r.Error().c_str());
	}

	delete amber_options.config;
}

bool AmberTestCase::parse(const char* category, const std::string& filename)
{
	std::string readFilename("vulkan/amber/");
	readFilename.append(category);
	readFilename.append("/");
	readFilename.append(filename);

	std::string script = ShaderSourceProvider::getSource(m_testCtx.getArchive(), readFilename.c_str());
	if (script.empty())
		return false;

	m_recipe = new amber::Recipe();

	amber::Amber am;
	amber::Result r = am.Parse(script, m_recipe);
	if (!r.IsSuccess())
	{
		getTestContext().getLog()
			<< tcu::TestLog::Message
			<< "Failed to parse Amber test "
			<< readFilename
			<< ": "
			<< r.Error()
			<< "\n"
			<< tcu::TestLog::EndMessage;
		// TODO(dneto): Enhance Amber to not require this.
		m_recipe->SetImpl(DE_NULL);
		return false;
	}
	return true;
}

void AmberTestCase::initPrograms(vk::SourceCollections& programCollection) const
{
	std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
	for (size_t i = 0; i < shaders.size(); ++i)
	{
		const amber::ShaderInfo& shader = shaders[i];

		/* Hex encoded shaders do not need to be pre-compiled */
		if (shader.format == amber::kShaderFormatSpirvHex)
			continue;

		if (shader.format == amber::kShaderFormatSpirvAsm)
		{
			programCollection.spirvAsmSources.add(shader.shader_name) << shader.shader_source;
		}
		else if (shader.format == amber::kShaderFormatGlsl)
		{
			switch (shader.type)
			{
				case amber::kShaderTypeCompute:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::ComputeSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeGeometry:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::GeometrySource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeFragment:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::FragmentSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeVertex:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::VertexSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeTessellationControl:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::TessellationControlSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeTessellationEvaluation:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::TessellationEvaluationSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeMulti:
					DE_ASSERT(false && "Multi shaders not supported");
					break;
			}
		}
		else
		{
			DE_ASSERT(false && "Shader format not supported");
		}
	}
}

tcu::TestStatus AmberTestInstance::iterate (void)
{
	amber::ShaderMap shaderMap;

	std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
	for (size_t i = 0; i < shaders.size(); ++i)
	{
		const amber::ShaderInfo& shader = shaders[i];

		if (!m_context.getBinaryCollection().contains(shader.shader_name))
			continue;

		size_t len = m_context.getBinaryCollection().get(shader.shader_name).getSize();
		/* This is a compiled spir-v binary which must be made of 4-byte words. We
		 * are moving into a word sized vector so divide by 4
		 */
		std::vector<deUint32> data;
		data.resize(len >> 2);
		deMemcpy(data.data(), m_context.getBinaryCollection().get(shader.shader_name).getBinary(), len);

		shaderMap[shader.shader_name] = data;
	}

	amber::Amber						am;
	amber::Options						amber_options;
	amber_options.engine				= amber::kEngineTypeVulkan;
	amber_options.config				= createEngineConfig(m_context);
	amber_options.delegate				= DE_NULL;
	amber_options.pipeline_create_only	= false;

	amber::Result r = am.ExecuteWithShaderData(m_recipe, &amber_options, shaderMap);
	if (!r.IsSuccess()) {
		m_context.getTestContext().getLog()
			<< tcu::TestLog::Message
			<< r.Error()
			<< "\n"
			<< tcu::TestLog::EndMessage;
	}

	delete amber_options.config;

	return r.IsSuccess() ? tcu::TestStatus::pass("Pass") :tcu::TestStatus::fail("Fail");
}

void AmberTestCase::addRequirement(const std::string& requirement)
{
	if (requirement.find(".") != std::string::npos)
		m_required_features.insert(requirement);
	else
		m_required_extensions.insert(requirement);
}

} // cts_amber
} // vkt
<commit_msg>Fix AmberTestCase feature mapping for geometryShader<commit_after>/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 * Copyright (c) 2019 Google LLC
 * Copyright (c) 2019 The Khronos Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Functional tests using amber
 *//*--------------------------------------------------------------------*/

#include <amber/amber.h>

#include <iostream>

#include "deDefs.hpp"
#include "deUniquePtr.hpp"
#include "deFilePath.hpp"
#include "vktTestCaseUtil.hpp"
#include "tcuTestLog.hpp"
#include "vktAmberTestCase.hpp"
#include "vktAmberHelper.hpp"
#include "tcuResource.hpp"
#include "tcuTestLog.hpp"

namespace vkt
{
namespace cts_amber
{

AmberTestCase::AmberTestCase (tcu::TestContext& testCtx,
							  const char*		name,
							  const char*		description)
	: TestCase(testCtx, name, description),
	  m_recipe(DE_NULL)
{
}

AmberTestCase::~AmberTestCase (void)
{
	delete m_recipe;
}

TestInstance* AmberTestCase::createInstance(Context& ctx) const
{
	return new AmberTestInstance(ctx, m_recipe);
}

static amber::EngineConfig* createEngineConfig(Context& ctx)
{
	amber::EngineConfig*	vkConfig = GetVulkanConfig(ctx.getInstance(),
			ctx.getPhysicalDevice(), ctx.getDevice(), &ctx.getDeviceFeatures(),
			&ctx.getDeviceFeatures2(), ctx.getInstanceExtensions(),
			ctx.getDeviceExtensions(), ctx.getUniversalQueueFamilyIndex(),
			ctx.getUniversalQueue(), ctx.getInstanceProcAddr());

	return vkConfig;
}

// Returns true if the given feature is supported by the device.
// Throws an internal error If the feature is not recognized at all.
static bool isFeatureSupported(const vkt::Context& ctx, const std::string& feature)
{
	if (feature == "Features.shaderInt16")
		return ctx.getDeviceFeatures().shaderInt16;
	if (feature == "Features.shaderInt64")
		return ctx.getDeviceFeatures().shaderInt64;
	if (feature == "Features.tessellationShader")
		return ctx.getDeviceFeatures().tessellationShader;
	if (feature == "Features.geometryShader")
		return ctx.getDeviceFeatures().geometryShader;
	if (feature == "Features.vertexPipelineStoresAndAtomics")
		return ctx.getDeviceFeatures().vertexPipelineStoresAndAtomics;
	if (feature == "VariablePointerFeatures.variablePointersStorageBuffer")
		return ctx.getVariablePointersFeatures().variablePointersStorageBuffer;
	if (feature == "VariablePointerFeatures.variablePointers")
		return ctx.getVariablePointersFeatures().variablePointers;

	std::string message = std::string("Unexpected feature name: ") + feature;
	TCU_THROW(InternalError, message.c_str());
}

void AmberTestCase::checkSupport(Context& ctx) const
{
	// Check for instance and device extensions as declared by the test code.
	if (m_required_extensions.size())
	{
		std::set<std::string> device_extensions(ctx.getDeviceExtensions().begin(),
												ctx.getDeviceExtensions().end());
		std::set<std::string> instance_extensions(ctx.getInstanceExtensions().begin(),
												  ctx.getInstanceExtensions().end());
		std::string missing;
		for (std::set<std::string>::iterator iter = m_required_extensions.begin();
			 iter != m_required_extensions.end();
			 ++iter)
		{
			const std::string extension = *iter;
			if ((device_extensions.count(extension) == 0) &&
				(instance_extensions.count(extension) == 0))
			{
				missing += " " + extension;
			}
		}
		if (missing.size() > 0)
		{
			std::string message("Test requires unsupported extensions:");
			message += missing;
			TCU_THROW(NotSupportedError, message.c_str());
		}
	}

	// Check for required features.  Do this after extensions are checked because
	// some feature checks are only valid when corresponding extensions are enabled.
	if (m_required_features.size())
	{
		std::string missing;
		for (std::set<std::string>::iterator iter = m_required_features.begin();
			 iter != m_required_features.end();
			 ++iter)
		{
			const std::string feature = *iter;
			if (!isFeatureSupported(ctx, feature))
			{
				missing += " " + feature;
			}
		}
		if (missing.size() > 0)
		{
			std::string message("Test requires unsupported features:");
			message += missing;
			TCU_THROW(NotSupportedError, message.c_str());
		}
	}

	// Check for extensions as declared by the Amber script itself.  Throw an internal
	// error if that's more demanding.
	amber::Amber			am;
	amber::Options			amber_options;
	amber_options.engine	= amber::kEngineTypeVulkan;
	amber_options.config	= createEngineConfig(ctx);
	amber_options.delegate	= DE_NULL;

	amber::Result r = am.AreAllRequirementsSupported(m_recipe, &amber_options);
	if (!r.IsSuccess())
	{
		// dEQP does not to rely on external code to determine whether
		// a test is supported.  So throw an internal error here instead
		// of a NotSupportedError.  If an Amber test is not supported, then
		// you must override this method and throw a NotSupported exception
		// before reach here.
		TCU_THROW(InternalError, r.Error().c_str());
	}

	delete amber_options.config;
}

bool AmberTestCase::parse(const char* category, const std::string& filename)
{
	std::string readFilename("vulkan/amber/");
	readFilename.append(category);
	readFilename.append("/");
	readFilename.append(filename);

	std::string script = ShaderSourceProvider::getSource(m_testCtx.getArchive(), readFilename.c_str());
	if (script.empty())
		return false;

	m_recipe = new amber::Recipe();

	amber::Amber am;
	amber::Result r = am.Parse(script, m_recipe);
	if (!r.IsSuccess())
	{
		getTestContext().getLog()
			<< tcu::TestLog::Message
			<< "Failed to parse Amber test "
			<< readFilename
			<< ": "
			<< r.Error()
			<< "\n"
			<< tcu::TestLog::EndMessage;
		// TODO(dneto): Enhance Amber to not require this.
		m_recipe->SetImpl(DE_NULL);
		return false;
	}
	return true;
}

void AmberTestCase::initPrograms(vk::SourceCollections& programCollection) const
{
	std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
	for (size_t i = 0; i < shaders.size(); ++i)
	{
		const amber::ShaderInfo& shader = shaders[i];

		/* Hex encoded shaders do not need to be pre-compiled */
		if (shader.format == amber::kShaderFormatSpirvHex)
			continue;

		if (shader.format == amber::kShaderFormatSpirvAsm)
		{
			programCollection.spirvAsmSources.add(shader.shader_name) << shader.shader_source;
		}
		else if (shader.format == amber::kShaderFormatGlsl)
		{
			switch (shader.type)
			{
				case amber::kShaderTypeCompute:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::ComputeSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeGeometry:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::GeometrySource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeFragment:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::FragmentSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeVertex:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::VertexSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeTessellationControl:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::TessellationControlSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeTessellationEvaluation:
					programCollection.glslSources.add(shader.shader_name)
						<< glu::TessellationEvaluationSource(shader.shader_source)
						<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_0, 0u);
					break;
				case amber::kShaderTypeMulti:
					DE_ASSERT(false && "Multi shaders not supported");
					break;
			}
		}
		else
		{
			DE_ASSERT(false && "Shader format not supported");
		}
	}
}

tcu::TestStatus AmberTestInstance::iterate (void)
{
	amber::ShaderMap shaderMap;

	std::vector<amber::ShaderInfo> shaders = m_recipe->GetShaderInfo();
	for (size_t i = 0; i < shaders.size(); ++i)
	{
		const amber::ShaderInfo& shader = shaders[i];

		if (!m_context.getBinaryCollection().contains(shader.shader_name))
			continue;

		size_t len = m_context.getBinaryCollection().get(shader.shader_name).getSize();
		/* This is a compiled spir-v binary which must be made of 4-byte words. We
		 * are moving into a word sized vector so divide by 4
		 */
		std::vector<deUint32> data;
		data.resize(len >> 2);
		deMemcpy(data.data(), m_context.getBinaryCollection().get(shader.shader_name).getBinary(), len);

		shaderMap[shader.shader_name] = data;
	}

	amber::Amber						am;
	amber::Options						amber_options;
	amber_options.engine				= amber::kEngineTypeVulkan;
	amber_options.config				= createEngineConfig(m_context);
	amber_options.delegate				= DE_NULL;
	amber_options.pipeline_create_only	= false;

	amber::Result r = am.ExecuteWithShaderData(m_recipe, &amber_options, shaderMap);
	if (!r.IsSuccess()) {
		m_context.getTestContext().getLog()
			<< tcu::TestLog::Message
			<< r.Error()
			<< "\n"
			<< tcu::TestLog::EndMessage;
	}

	delete amber_options.config;

	return r.IsSuccess() ? tcu::TestStatus::pass("Pass") :tcu::TestStatus::fail("Fail");
}

void AmberTestCase::addRequirement(const std::string& requirement)
{
	if (requirement.find(".") != std::string::npos)
		m_required_features.insert(requirement);
	else
		m_required_extensions.insert(requirement);
}

} // cts_amber
} // vkt
<|endoftext|>


<commit_before>#include "KAI/KAI.h"

#include <iostream>
#include <strstream>
#include <stdarg.h>

#include "KAI/Translator/Lexer.h"

using namespace std;

KAI_BEGIN

Lexer::Lexer(const char *in)
	: input(in)
{
	CreateLines();
	AddKeywords();
	Run();
}

void Lexer::AddKeywords()
{
	keyWords["if"] = Token::If;
	keyWords["else"] = Token::Else;
	keyWords["for"] = Token::For;
	keyWords["true"] = Token::True;
	keyWords["false"] = Token::False;
	keyWords["return"] = Token::Return;
	keyWords["self"] = Token::Self;
	keyWords["fun"] = Token::Fun;
	keyWords["yield"] = Token::Yield;
	keyWords["in"] = Token::In;
	keyWords["while"] = Token::While;
	keyWords["assert"] = Token::Assert;
}

bool Lexer::Run()
{
	offset = 0;
	lineNumber = 0;

	while (!Failed && NextToken())
		;

	return Add(Token::None, 0);
}

void Lexer::Print() const
{
	for (auto tok : tokens)
		std::cout << tok << " ";
	std::cout << std::endl;
}

Slice Lexer::Gather(int (*filt)(int))
{
	int start = offset;
	while (filt(Next()))
		;
	return Slice(start, offset);
}

bool Lexer::Add(Token::Type type, Slice slice)
{
	tokens.push_back(Token(type, *this, lineNumber, slice));
	return true;
}

bool Lexer::Add(Token::Type type, int len)
{
	Add(type, Slice(offset, offset + len));
	while (len--)
		Next();
	return true;
}

bool Lexer::LexAlpha()
{
	Token tok(Token::Ident, *this, lineNumber, Gather(isalnum));

	auto kw = keyWords.find(tok.Text());
	if (kw != keyWords.end())
		tok.type = kw->second;

	tokens.push_back(tok);

	return true;
}

int IsSpaceChar(int ch)
{
	return ch == ' ';
}

bool Lexer::NextToken()
{
	auto current = Current();
	if (current == 0)
		return false;

	if (isalpha(current))
		return LexAlpha();

	if (isdigit(current))
		return Add(Token::Int, Gather(isdigit));

	switch (current)
	{
	case ':': return Add(Token::Colon);
	case '\t': return Add(Token::Tab);
	case '\n': return Add(Token::NewLine);
	case ' ': return Add(Token::Whitespace, Gather(IsSpaceChar));
	case '@': return Add(Token::Lookup);
	case '\'': return LexAlpha();
	case '-':
	{
		if (Peek() == '-')
		{
			Next();
			return Add(Token::Decrement);
		}
		if (Peek() == '=')
		{
			Next();
			return Add(Token::MinusAssign);
		}
		return Add(Token::Minus);
	}

	case '.':
	{
		if (Peek() == '.')
		{
			Next();
			if (Peek() == '.')
			{
				Next();
				return Add(Token::Replace, 3);
			}
			else
			{
				return Fail("Two dots");
			}
		}
		return Add(Token::Dot);
	}

	case ',': return Add(Token::Comma);
	case '+':
	{
		if (Peek() == '+')
		{
			Next();
			return Add(Token::Increment);
		}
		if (Peek() == '=')
		{
			Next();
			return Add(Token::PlusAssign);
		}
		return Add(Token::Plus);
	}
	case '*': return Add(Token::Mul);
	case '/':
	{
		if (Peek() == '/')
		{
			Next();
			int start = offset;
			while (Next() != '\n')
				;
			return Add(Token::Comment, offset - start);
		}
		return Add(Token::Divide);
	}
	case ';': return Add(Token::Semi);
	case '{': return Add(Token::OpenBrace);
	case '}': return Add(Token::CloseBrace);
	case '(': return Add(Token::OpenParan);
	case ')': return Add(Token::CloseParan);
	case '=': return AddIfNext('=', Token::Equiv, Token::Assign);
	case '[': return Add(Token::OpenSquareBracket);
	case ']': return Add(Token::CloseSquareBracket);
	case '!': return AddIfNext('=', Token::NotEquiv, Token::Not);
	case '&': return AddIfNext('&', Token::And, Token::BitAnd);
	case '|': return AddIfNext('|', Token::Or, Token::BitOr);
	case '"': return LexString();
	}

	if (current == '<')
	{
		if (Peek() == '=')
		{
			return AddTwoCharOp(Token::LessEquiv);
		}
		return Add(Token::Less);
	}

	if (current == '>')
	{
		if (Peek() == '=')
		{
			return AddTwoCharOp(Token::GreaterEqiv);
		}
		return Add(Token::Greater);
	}

	LexError("Unrecognised %c");

	return false;
}

std::string Lexer::CreateError(Token tok, const char *fmt, ...)
{
	char buff0[2000];
	va_list ap;
	va_start(ap, fmt);
	vsprintf_s(buff0, fmt, ap);

	const char *fmt1 = "%s(%d):[%d]: %s\n";
	char buff[2000];
	sprintf_s(buff, fmt1, "", tok.lineNumber, tok.slice.Start, buff0);
	int beforeContext = 1;
	int afterContext = 0;

	const Lexer &lex = *tok.lexer;
	int start = std::max(0, tok.lineNumber - beforeContext);
	int end = std::min((int)lex.lines.size() - 1, tok.lineNumber + afterContext);

	strstream err;
	err << buff << endl;
	for (int n = start; n <= end; ++n)
	{
		for (auto ch : lex.lines[n])
		{
			if (ch == '\t')
				err << "    ";
			else
				err << ch;
		}
		if (n == tok.lineNumber)
		{
			for (int ch = 0; ch < (int)lex.lines[n].size(); ++ch)
			{
				if (lex.lines[tok.lineNumber][ch] == '\t')
					err << "    ";
				else if (ch == tok.slice.Start)
				{
					err << '^';
					break;
				}
			}
			err << endl;
		}
	}
	err << ends;

	return err.str();
}

bool Process::Fail(const std::string &err)
{
	Failed = true;
	Error = err;
	return false;
}

bool Process::Fail(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	char buffer[1000];
	vsprintf_s(buffer, fmt, ap);
	return Fail(std::string(buffer));
}

char Lexer::Current() const
{
	if (lineNumber == (int)lines.size())
		return 0;
	return Line()[offset];
}

const std::string &Lexer::Line() const
{
	return lines[lineNumber];
}

char Lexer::Next()
{
	if (EndOfLine())
	{
		offset = 0;
		++lineNumber;
	}
	else
		++offset;

	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

char Lexer::Peek() const
{
	if (EndOfLine())
		return 0;
	return Line()[offset + 1];
}

void Lexer::CreateLines()
{
	input.push_back('\n');
	size_t lineStart = 0;
	for (size_t n = 0; n < input.size(); ++n)
	{
		if (input[n] == '\n')
		{
			lines.push_back(input.substr(lineStart, n - lineStart + 1));
			lineStart = n + 1;
		}
	}
}

bool Lexer::EndOfLine() const
{
	return offset == (int)Line().size() - 1;
}

bool Lexer::AddIfNext(char ch, Token::Type thenType, Token::Type elseType)
{
	if (Peek() == ch)
	{
		Next();
		return Add(thenType, 2);
	}
	return Add(elseType, 1);
}

bool Lexer::AddTwoCharOp(Token::Type ty)
{
	Add(ty, 2);
	Next();
	return true;
}

bool Lexer::LexString()
{
	int start = offset;
	Next();
	while (!Failed && Current() != '"')
	{
		if (Current() == '\\')
		{
			switch (Next())
			{
			case '"':
			case 'n':
			case 't':
				break;

			default:
				LexError("Bad escape sequence %c");
				return false;
			}
		}
		Next();
	}
	Next();
	tokens.push_back(Token(Token::String, *this, lineNumber, Slice(start, offset)));
	return true;
}

void Lexer::LexError(const char *text)
{
	Fail(CreateError(Token(Token::None, *this, lineNumber, Slice(offset, offset)), text, Current()));
}

KAI_END
<commit_msg>Fix crash bug in LexString() with input of "<commit_after>#include "KAI/KAI.h"

#include <iostream>
#include <strstream>
#include <stdarg.h>

#include "KAI/Translator/Lexer.h"

using namespace std;

KAI_BEGIN

Lexer::Lexer(const char *in)
	: input(in)
{
	CreateLines();
	AddKeywords();
	Run();
}

void Lexer::AddKeywords()
{
	keyWords["if"] = Token::If;
	keyWords["else"] = Token::Else;
	keyWords["for"] = Token::For;
	keyWords["true"] = Token::True;
	keyWords["false"] = Token::False;
	keyWords["return"] = Token::Return;
	keyWords["self"] = Token::Self;
	keyWords["fun"] = Token::Fun;
	keyWords["yield"] = Token::Yield;
	keyWords["in"] = Token::In;
	keyWords["while"] = Token::While;
	keyWords["assert"] = Token::Assert;
}

bool Lexer::Run()
{
	offset = 0;
	lineNumber = 0;

	while (!Failed && NextToken())
		;

	return Add(Token::None, 0);
}

void Lexer::Print() const
{
	for (auto tok : tokens)
		std::cout << tok << " ";
	std::cout << std::endl;
}

Slice Lexer::Gather(int (*filt)(int))
{
	int start = offset;
	while (filt(Next()))
		;
	return Slice(start, offset);
}

bool Lexer::Add(Token::Type type, Slice slice)
{
	tokens.push_back(Token(type, *this, lineNumber, slice));
	return true;
}

bool Lexer::Add(Token::Type type, int len)
{
	Add(type, Slice(offset, offset + len));
	while (len--)
		Next();
	return true;
}

bool Lexer::LexAlpha()
{
	Token tok(Token::Ident, *this, lineNumber, Gather(isalnum));

	auto kw = keyWords.find(tok.Text());
	if (kw != keyWords.end())
		tok.type = kw->second;

	tokens.push_back(tok);

	return true;
}

int IsSpaceChar(int ch)
{
	return ch == ' ';
}

bool Lexer::NextToken()
{
	auto current = Current();
	if (current == 0)
		return false;

	if (isalpha(current))
		return LexAlpha();

	if (isdigit(current))
		return Add(Token::Int, Gather(isdigit));

	switch (current)
	{
	case ':': return Add(Token::Colon);
	case '\t': return Add(Token::Tab);
	case '\n': return Add(Token::NewLine);
	case ' ': return Add(Token::Whitespace, Gather(IsSpaceChar));
	case '@': return Add(Token::Lookup);
	case '\'': return LexAlpha();
	case '-':
	{
		if (Peek() == '-')
		{
			Next();
			return Add(Token::Decrement);
		}
		if (Peek() == '=')
		{
			Next();
			return Add(Token::MinusAssign);
		}
		return Add(Token::Minus);
	}

	case '.':
	{
		if (Peek() == '.')
		{
			Next();
			if (Peek() == '.')
			{
				Next();
				return Add(Token::Replace, 3);
			}
			else
			{
				return Fail("Two dots");
			}
		}
		return Add(Token::Dot);
	}

	case ',': return Add(Token::Comma);
	case '+':
	{
		if (Peek() == '+')
		{
			Next();
			return Add(Token::Increment);
		}
		if (Peek() == '=')
		{
			Next();
			return Add(Token::PlusAssign);
		}
		return Add(Token::Plus);
	}
	case '*': return Add(Token::Mul);
	case '/':
	{
		if (Peek() == '/')
		{
			Next();
			int start = offset;
			while (Next() != '\n')
				;
			return Add(Token::Comment, offset - start);
		}
		return Add(Token::Divide);
	}
	case ';': return Add(Token::Semi);
	case '{': return Add(Token::OpenBrace);
	case '}': return Add(Token::CloseBrace);
	case '(': return Add(Token::OpenParan);
	case ')': return Add(Token::CloseParan);
	case '=': return AddIfNext('=', Token::Equiv, Token::Assign);
	case '[': return Add(Token::OpenSquareBracket);
	case ']': return Add(Token::CloseSquareBracket);
	case '!': return AddIfNext('=', Token::NotEquiv, Token::Not);
	case '&': return AddIfNext('&', Token::And, Token::BitAnd);
	case '|': return AddIfNext('|', Token::Or, Token::BitOr);
	case '"': return LexString();
	}

	if (current == '<')
	{
		if (Peek() == '=')
		{
			return AddTwoCharOp(Token::LessEquiv);
		}
		return Add(Token::Less);
	}

	if (current == '>')
	{
		if (Peek() == '=')
		{
			return AddTwoCharOp(Token::GreaterEqiv);
		}
		return Add(Token::Greater);
	}

	LexError("Unrecognised %c");

	return false;
}

std::string Lexer::CreateError(Token tok, const char *fmt, ...)
{
	char buff0[2000];
	va_list ap;
	va_start(ap, fmt);
	vsprintf_s(buff0, fmt, ap);

	const char *fmt1 = "%s(%d):[%d]: %s\n";
	char buff[2000];
	sprintf_s(buff, fmt1, "", tok.lineNumber, tok.slice.Start, buff0);
	int beforeContext = 1;
	int afterContext = 0;

	const Lexer &lex = *tok.lexer;
	int start = std::max(0, tok.lineNumber - beforeContext);
	int end = std::min((int)lex.lines.size() - 1, tok.lineNumber + afterContext);

	strstream err;
	err << buff << endl;
	for (int n = start; n <= end; ++n)
	{
		for (auto ch : lex.lines[n])
		{
			if (ch == '\t')
				err << "    ";
			else
				err << ch;
		}
		if (n == tok.lineNumber)
		{
			for (int ch = 0; ch < (int)lex.lines[n].size(); ++ch)
			{
				if (lex.lines[tok.lineNumber][ch] == '\t')
					err << "    ";
				else if (ch == tok.slice.Start)
				{
					err << '^';
					break;
				}
			}
			err << endl;
		}
	}
	err << ends;

	return err.str();
}

bool Process::Fail(const std::string &err)
{
	Failed = true;
	Error = err;
	return false;
}

bool Process::Fail(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	char buffer[1000];
	vsprintf_s(buffer, fmt, ap);
	return Fail(std::string(buffer));
}

char Lexer::Current() const
{
	if (lineNumber == (int)lines.size())
		return 0;
	return Line()[offset];
}

const std::string &Lexer::Line() const
{
	return lines[lineNumber];
}

char Lexer::Next()
{
	if (EndOfLine())
	{
		offset = 0;
		++lineNumber;
	}
	else
		++offset;

	if (lineNumber == (int)lines.size())
		return 0;

	return Line()[offset];
}

char Lexer::Peek() const
{
	if (EndOfLine())
		return 0;
	return Line()[offset + 1];
}

void Lexer::CreateLines()
{
	input.push_back('\n');
	size_t lineStart = 0;
	for (size_t n = 0; n < input.size(); ++n)
	{
		if (input[n] == '\n')
		{
			lines.push_back(input.substr(lineStart, n - lineStart + 1));
			lineStart = n + 1;
		}
	}
}

bool Lexer::EndOfLine() const
{
	return offset == (int)Line().size() - 1;
}

bool Lexer::AddIfNext(char ch, Token::Type thenType, Token::Type elseType)
{
	if (Peek() == ch)
	{
		Next();
		return Add(thenType, 2);
	}
	return Add(elseType, 1);
}

bool Lexer::AddTwoCharOp(Token::Type ty)
{
	Add(ty, 2);
	Next();
	return true;
}

bool Lexer::LexString()
{
	int start = offset;
	Next();
	while (!Failed && Current() != '"')
	{
		if (Current() == '\\')
		{

			switch (Next())
			{
			case '"':
			case 'n':
			case 't':
				break;

			default:
				LexError("Bad escape sequence %c");
				return false;
			}
		}
		if (Peek() == 0)
		{
			Fail("Bad string literal");
			return false;
		}
		Next();
	}
	Next();
	tokens.push_back(Token(Token::String, *this, lineNumber, Slice(start, offset)));
	return true;
}

void Lexer::LexError(const char *text)
{
	Fail(CreateError(Token(Token::None, *this, lineNumber, Slice(offset, offset)), text, Current()));
}

KAI_END
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <unordered_map>

#include "Type.hpp"

#include "ltac/stack_offsets.hpp"
#include "ltac/Address.hpp"
#include "ltac/Register.hpp"
#include "ltac/Statement.hpp"

using namespace eddic;

namespace {

template<typename Type, typename Variant>
bool opt_variant_equals(Variant& opt_variant, Type& value){
    if(opt_variant){
        if(auto* ptr = boost::get<Type>(&*opt_variant)){
            if(*ptr == value){
                return true;
            }
        }
    }

    return false;
}

template<typename Arg>
void change_address(Arg& arg, int bp_offset){
    if(arg){
        if(auto* ptr = boost::get<ltac::Address>(&*arg)){
            auto& address = *ptr;

            if(opt_variant_equals(address.base_register, ltac::BP)){
                address.base_register = ltac::SP;

                if(address.displacement){
                    *address.displacement += bp_offset;
                } else {
                    address.displacement = bp_offset;
                }
            }
        }
    }
}

}

void ltac::fix_stack_offsets(std::shared_ptr<mtac::Program> program, Platform platform){
    int bp_offset = 0;

    std::unordered_map<std::string, int> offset_labels;

    for(auto& function : program->functions){
        for(auto& bb : function){
            for(auto& statement : bb->l_statements){
                if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                    auto instruction = *ptr;

                    change_address(instruction->arg1, bp_offset);
                    change_address(instruction->arg2, bp_offset);
                    change_address(instruction->arg3, bp_offset);

                    if(opt_variant_equals(instruction->arg1, ltac::BP)){
                        if(instruction->op == ltac::Operator::ADD){
                            bp_offset -= boost::get<int>(*instruction->arg2);
                        }

                        if(instruction->op == ltac::Operator::SUB){
                            bp_offset += boost::get<int>(*instruction->arg2);
                        }
                    }

                    if(instruction->op == ltac::Operator::PUSH){
                        bp_offset += INT->size(platform);
                    }

                    if(instruction->op == ltac::Operator::POP){
                        bp_offset -= INT->size(platform);
                    }
                } else if(auto* ptr = boost::get<std::string>(&statement)){
                    if(offset_labels.count(*ptr)){
                        bp_offset = offset_labels[*ptr];
                        offset_labels.erase(*ptr);
                    }
                } else if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                    auto jump = *ptr;
                    if(jump->type != ltac::JumpType::CALL && jump->type != ltac::JumpType::ALWAYS){
                        offset_labels[jump->label] = bp_offset;
                    }
                }
            }
        }
    }
}
<commit_msg>Fix calculation of the stack offset<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <unordered_map>

#include "Type.hpp"

#include "ltac/stack_offsets.hpp"
#include "ltac/Address.hpp"
#include "ltac/Register.hpp"
#include "ltac/Statement.hpp"

using namespace eddic;

namespace {

template<typename Type, typename Variant>
bool opt_variant_equals(Variant& opt_variant, Type& value){
    if(opt_variant){
        if(auto* ptr = boost::get<Type>(&*opt_variant)){
            if(*ptr == value){
                return true;
            }
        }
    }

    return false;
}

template<typename Arg>
void change_address(Arg& arg, int bp_offset){
    if(arg){
        if(auto* ptr = boost::get<ltac::Address>(&*arg)){
            auto& address = *ptr;

            if(opt_variant_equals(address.base_register, ltac::BP)){
                address.base_register = ltac::SP;

                if(address.displacement){
                    *address.displacement += bp_offset;
                } else {
                    address.displacement = bp_offset;
                }
            }
        }
    }
}

}

void ltac::fix_stack_offsets(std::shared_ptr<mtac::Program> program, Platform platform){
    int bp_offset = 0;

    std::unordered_map<std::string, int> offset_labels;

    for(auto& function : program->functions){
        for(auto& bb : function){
            for(auto& statement : bb->l_statements){
                if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                    auto instruction = *ptr;

                    change_address(instruction->arg1, bp_offset);
                    change_address(instruction->arg2, bp_offset);
                    change_address(instruction->arg3, bp_offset);

                    if(opt_variant_equals(instruction->arg1, ltac::SP)){
                        if(instruction->op == ltac::Operator::ADD){
                            bp_offset -= boost::get<int>(*instruction->arg2);
                        }

                        if(instruction->op == ltac::Operator::SUB){
                            bp_offset += boost::get<int>(*instruction->arg2);
                        }
                    }

                    if(instruction->op == ltac::Operator::PUSH){
                        bp_offset += INT->size(platform);
                    }

                    if(instruction->op == ltac::Operator::POP){
                        bp_offset -= INT->size(platform);
                    }
                } else if(auto* ptr = boost::get<std::string>(&statement)){
                    if(offset_labels.count(*ptr)){
                        bp_offset = offset_labels[*ptr];
                        offset_labels.erase(*ptr);
                    }
                } else if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                    auto jump = *ptr;
                    if(jump->type != ltac::JumpType::CALL && jump->type != ltac::JumpType::ALWAYS){
                        offset_labels[jump->label] = bp_offset;
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "fuprlout.hxx"
#include <vcl/wrkwin.hxx>
#include <sfx2/dispatch.hxx>
#include <svl/smplhint.hxx>
#include <svl/itempool.hxx>
#include <sot/storage.hxx>
#include <vcl/msgbox.hxx>
#include <svx/svdundo.hxx>

#include <sfx2/viewfrm.hxx>
#include <sfx2/request.hxx>

#include "drawdoc.hxx"
#include "sdpage.hxx"
#include "pres.hxx"
#include "DrawViewShell.hxx"
#include "FrameView.hxx"
#include "stlpool.hxx"
#include "View.hxx"
#include "glob.hrc"
#include "glob.hxx"
#include "strings.hrc"
#include "strmname.h"
#include "app.hrc"
#include "DrawDocShell.hxx"
#include "unprlout.hxx"
#include "unchss.hxx"
#include "unmovss.hxx"
#include "sdattr.hxx"
#include "sdresid.hxx"
#include "drawview.hxx"
#include <editeng/outliner.hxx>
#include <editeng/editdata.hxx>
#include "sdabstdlg.hxx"
#include <boost/scoped_ptr.hpp>

namespace sd
{

TYPEINIT1( FuPresentationLayout, FuPoor );

#define DOCUMENT_TOKEN '#'

FuPresentationLayout::FuPresentationLayout (
    ViewShell* pViewSh,
    ::sd::Window* pWin,
    ::sd::View* pView,
    SdDrawDocument* pDoc,
    SfxRequest& rReq)
    : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
{
}

rtl::Reference<FuPoor> FuPresentationLayout::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
{
    rtl::Reference<FuPoor> xFunc( new FuPresentationLayout( pViewSh, pWin, pView, pDoc, rReq ) );
    xFunc->DoExecute(rReq);
    return xFunc;
}

void FuPresentationLayout::DoExecute( SfxRequest& rReq )
{
    // prevent selected objects or objects which are under editing from disappearing
    mpView->SdrEndTextEdit();

    if(mpView->GetSdrPageView())
    {
        mpView->UnmarkAll();
    }

    bool bError = false;

    // determine the active page
    sal_uInt16 nSelectedPage = SDRPAGE_NOTFOUND;
    for (sal_uInt16 nPage = 0; nPage < mpDoc->GetSdPageCount(PK_STANDARD); nPage++)
    {
        if (mpDoc->GetSdPage(nPage, PK_STANDARD)->IsSelected())
        {
            nSelectedPage = nPage;
            break;
        }
    }

    DBG_ASSERT(nSelectedPage != SDRPAGE_NOTFOUND, "no selected page");
    SdPage* pSelectedPage = mpDoc->GetSdPage(nSelectedPage, PK_STANDARD);
    OUString aOldLayoutName(pSelectedPage->GetLayoutName());
    sal_Int32 nPos = aOldLayoutName.indexOf(SD_LT_SEPARATOR);
    if (nPos != -1)
        aOldLayoutName = aOldLayoutName.copy(0, nPos);

    /* if we are on a master page, the changes apply for all pages and notes-
       pages who are using the relevant layout */
    bool bOnMaster = false;
    if( mpViewShell && mpViewShell->ISA(DrawViewShell))
    {
        EditMode eEditMode =
            static_cast<DrawViewShell*>(mpViewShell)->GetEditMode();
        if (eEditMode == EM_MASTERPAGE)
            bOnMaster = true;
    }
    bool bMasterPage = bOnMaster;
    bool bCheckMasters = false;

    // call dialog
    bool   bLoad = false;           // appear the new master pages?
    OUString aFile;

    SfxItemSet aSet(mpDoc->GetPool(), ATTR_PRESLAYOUT_START, ATTR_PRESLAYOUT_END);

    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_LOAD, bLoad));
    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_MASTER_PAGE, bMasterPage ) );
    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_CHECK_MASTERS, bCheckMasters ) );
    aSet.Put( SfxStringItem( ATTR_PRESLAYOUT_NAME, aOldLayoutName));

    const SfxItemSet *pArgs = rReq.GetArgs ();

    if (pArgs)
    {
        if (pArgs->GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
            bLoad = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
        if( pArgs->GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
            bMasterPage = static_cast<const SfxBoolItem&>( pArgs->Get( ATTR_PRESLAYOUT_MASTER_PAGE ) ).GetValue();
        if( pArgs->GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
            bCheckMasters = static_cast<const SfxBoolItem&>( pArgs->Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
        if (pArgs->GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
            aFile = static_cast<const SfxStringItem&>(pArgs->Get(ATTR_PRESLAYOUT_NAME)).GetValue();
    }
    else
    {
        SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
        boost::scoped_ptr<AbstractSdPresLayoutDlg> pDlg(pFact ? pFact->CreateSdPresLayoutDlg(mpDocSh, NULL, aSet ) : 0);

        sal_uInt16 nResult = pDlg ? pDlg->Execute() : static_cast<short>(RET_CANCEL);

        switch (nResult)
        {
            case RET_OK:
            {
                pDlg->GetAttr(aSet);
                if (aSet.GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
                    bLoad = static_cast<const SfxBoolItem&>(aSet.Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
                if( aSet.GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
                    bMasterPage = static_cast<const SfxBoolItem&>(aSet.Get( ATTR_PRESLAYOUT_MASTER_PAGE ) ).GetValue();
                if( aSet.GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
                    bCheckMasters = static_cast<const SfxBoolItem&>(aSet.Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
                if (aSet.GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
                    aFile = static_cast<const SfxStringItem&>(aSet.Get(ATTR_PRESLAYOUT_NAME)).GetValue();
            }
            break;

            default:
                bError = true;
        }
    }

    if (!bError)
    {
        mpDocSh->SetWaitCursor( true );

        /* Here, we only exchange masterpages, therefore the current page
           remains the current page. To prevent calling PageOrderChangedHint
           during insertion and extraction of the masterpages, we block. */
        /* That isn't quitely right. If the masterpageview is active and you are
           removing a masterpage, it's possible that you are removing the
           current masterpage. So you have to call ResetActualPage ! */
        if( mpViewShell->ISA(DrawViewShell) && !bCheckMasters )
            static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(true);

        if (bLoad)
        {
            OUString aFileName = aFile.getToken(0, DOCUMENT_TOKEN);
            SdDrawDocument* pTempDoc = mpDoc->OpenBookmarkDoc( aFileName );

            // #69581: If I chose the standard-template I got no filename and so I get no
            //         SdDrawDocument-Pointer. But the method SetMasterPage is able to handle
            //         a NULL-pointer as a Standard-template ( look at SdDrawDocument::SetMasterPage )
            OUString aLayoutName;
            if( pTempDoc )
                aLayoutName = aFile.getToken(1, DOCUMENT_TOKEN);

            mpDoc->SetMasterPage(nSelectedPage, aLayoutName, pTempDoc, bMasterPage, bCheckMasters);
            mpDoc->CloseBookmarkDoc();
        }
        else
        {
            // use master page with the layout name aFile from current Doc
            mpDoc->SetMasterPage(nSelectedPage, aFile, mpDoc, bMasterPage, bCheckMasters);
        }

        // remove blocking
        if (mpViewShell->ISA(DrawViewShell) && !bCheckMasters )
            static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(false);

        // if the master page was visible, show it again
        if (!bError && nSelectedPage != SDRPAGE_NOTFOUND)
        {
            if (bOnMaster)
            {
                if (mpViewShell->ISA(DrawViewShell))
                {
                    ::sd::View* pView =
                          static_cast<DrawViewShell*>(mpViewShell)->GetView();
                    sal_uInt16 nPgNum = pSelectedPage->TRG_GetMasterPage().GetPageNum();

                    if (static_cast<DrawViewShell*>(mpViewShell)->GetPageKind() == PK_NOTES)
                        nPgNum++;

                    pView->HideSdrPage();
                    pView->ShowSdrPage(pView->GetModel()->GetMasterPage(nPgNum));
                }

                // force update of TabBar
                mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_MASTERPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
            }
            else
            {
                pSelectedPage->SetAutoLayout(pSelectedPage->GetAutoLayout());
            }
        }

        // fake a mode change to repaint the page tab bar
        if( mpViewShell && mpViewShell->ISA( DrawViewShell ) )
        {
            DrawViewShell* pDrawViewSh =
                static_cast<DrawViewShell*>(mpViewShell);
            EditMode eMode = pDrawViewSh->GetEditMode();
            bool bLayer = pDrawViewSh->IsLayerModeActive();
            pDrawViewSh->ChangeEditMode( eMode, !bLayer );
            pDrawViewSh->ChangeEditMode( eMode, bLayer );
        }

        mpDocSh->SetWaitCursor( false );
    }
}

} // end of namespace sd

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>allow slide design to affect multiple standard pages<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "fuprlout.hxx"
#include <vcl/wrkwin.hxx>
#include <sfx2/dispatch.hxx>
#include <svl/smplhint.hxx>
#include <svl/itempool.hxx>
#include <sot/storage.hxx>
#include <vcl/msgbox.hxx>
#include <svx/svdundo.hxx>

#include <sfx2/viewfrm.hxx>
#include <sfx2/request.hxx>

#include "drawdoc.hxx"
#include "sdpage.hxx"
#include "pres.hxx"
#include "DrawViewShell.hxx"
#include "FrameView.hxx"
#include "stlpool.hxx"
#include "View.hxx"
#include "glob.hrc"
#include "glob.hxx"
#include "strings.hrc"
#include "strmname.h"
#include "app.hrc"
#include "DrawDocShell.hxx"
#include "SlideSorterViewShell.hxx"
#include "unprlout.hxx"
#include "unchss.hxx"
#include "unmovss.hxx"
#include "sdattr.hxx"
#include "sdresid.hxx"
#include "drawview.hxx"
#include <editeng/outliner.hxx>
#include <editeng/editdata.hxx>
#include "sdabstdlg.hxx"
#include <boost/scoped_ptr.hpp>

namespace sd
{

TYPEINIT1( FuPresentationLayout, FuPoor );

#define DOCUMENT_TOKEN '#'

FuPresentationLayout::FuPresentationLayout (
    ViewShell* pViewSh,
    ::sd::Window* pWin,
    ::sd::View* pView,
    SdDrawDocument* pDoc,
    SfxRequest& rReq)
    : FuPoor(pViewSh, pWin, pView, pDoc, rReq)
{
}

rtl::Reference<FuPoor> FuPresentationLayout::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
{
    rtl::Reference<FuPoor> xFunc( new FuPresentationLayout( pViewSh, pWin, pView, pDoc, rReq ) );
    xFunc->DoExecute(rReq);
    return xFunc;
}

void FuPresentationLayout::DoExecute( SfxRequest& rReq )
{
    // prevent selected objects or objects which are under editing from disappearing
    mpView->SdrEndTextEdit();

    if(mpView->GetSdrPageView())
    {
        mpView->UnmarkAll();
    }

    bool bError = false;

    /* if we are on a master page, the changes apply for all pages and notes-
       pages who are using the relevant layout */
    bool bOnMaster = false;
    if( mpViewShell && mpViewShell->ISA(DrawViewShell))
    {
        EditMode eEditMode =
            static_cast<DrawViewShell*>(mpViewShell)->GetEditMode();
        if (eEditMode == EM_MASTERPAGE)
            bOnMaster = true;
    }

    std::vector<SdPage*> aUnselect;
    if (!bOnMaster)
    {
        //We later rely on IsSelected, so transfer the selection here
        //into the document
        slidesorter::SlideSorterViewShell* pSlideSorterViewShell
            = slidesorter::SlideSorterViewShell::GetSlideSorter(mpViewShell->GetViewShellBase());
        if (pSlideSorterViewShell)
        {
            boost::shared_ptr<slidesorter::SlideSorterViewShell::PageSelection> xSelection(
                pSlideSorterViewShell->GetPageSelection());
            if (xSelection)
            {
                for (auto it = xSelection->begin(); it != xSelection->end(); ++it)
                {
                    SdPage *pPage = *it;
                    if (pPage->IsSelected() || pPage->GetPageKind() != PK_STANDARD)
                        continue;
                    mpDoc->SetSelected(pPage, true);
                    aUnselect.push_back(pPage);
                }
            }
        }
    }

    std::vector<SdPage*> aSelectedPages;
    std::vector<sal_uInt16> aSelectedPageNums;
    // determine the active pages
    for (sal_uInt16 nPage = 0; nPage < mpDoc->GetSdPageCount(PK_STANDARD); nPage++)
    {
        SdPage* pPage = mpDoc->GetSdPage(nPage, PK_STANDARD);
        if (pPage->IsSelected())
        {
            aSelectedPages.push_back(pPage);
            aSelectedPageNums.push_back(nPage);
        }
    }

    assert(!aSelectedPages.empty() && "no selected page");
    OUString aOldLayoutName(aSelectedPages.back()->GetLayoutName());
    sal_Int32 nPos = aOldLayoutName.indexOf(SD_LT_SEPARATOR);
    if (nPos != -1)
        aOldLayoutName = aOldLayoutName.copy(0, nPos);

    bool bMasterPage = bOnMaster;
    bool bCheckMasters = false;

    // call dialog
    bool   bLoad = false;           // appear the new master pages?
    OUString aFile;

    SfxItemSet aSet(mpDoc->GetPool(), ATTR_PRESLAYOUT_START, ATTR_PRESLAYOUT_END);

    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_LOAD, bLoad));
    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_MASTER_PAGE, bMasterPage ) );
    aSet.Put( SfxBoolItem( ATTR_PRESLAYOUT_CHECK_MASTERS, bCheckMasters ) );
    aSet.Put( SfxStringItem( ATTR_PRESLAYOUT_NAME, aOldLayoutName));

    const SfxItemSet *pArgs = rReq.GetArgs ();

    if (pArgs)
    {
        if (pArgs->GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
            bLoad = static_cast<const SfxBoolItem&>(pArgs->Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
        if( pArgs->GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
            bMasterPage = static_cast<const SfxBoolItem&>( pArgs->Get( ATTR_PRESLAYOUT_MASTER_PAGE ) ).GetValue();
        if( pArgs->GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
            bCheckMasters = static_cast<const SfxBoolItem&>( pArgs->Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
        if (pArgs->GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
            aFile = static_cast<const SfxStringItem&>(pArgs->Get(ATTR_PRESLAYOUT_NAME)).GetValue();
    }
    else
    {
        SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
        boost::scoped_ptr<AbstractSdPresLayoutDlg> pDlg(pFact ? pFact->CreateSdPresLayoutDlg(mpDocSh, NULL, aSet ) : 0);

        sal_uInt16 nResult = pDlg ? pDlg->Execute() : static_cast<short>(RET_CANCEL);

        switch (nResult)
        {
            case RET_OK:
            {
                pDlg->GetAttr(aSet);
                if (aSet.GetItemState(ATTR_PRESLAYOUT_LOAD) == SfxItemState::SET)
                    bLoad = static_cast<const SfxBoolItem&>(aSet.Get(ATTR_PRESLAYOUT_LOAD)).GetValue();
                if( aSet.GetItemState( ATTR_PRESLAYOUT_MASTER_PAGE ) == SfxItemState::SET )
                    bMasterPage = static_cast<const SfxBoolItem&>(aSet.Get( ATTR_PRESLAYOUT_MASTER_PAGE ) ).GetValue();
                if( aSet.GetItemState( ATTR_PRESLAYOUT_CHECK_MASTERS ) == SfxItemState::SET )
                    bCheckMasters = static_cast<const SfxBoolItem&>(aSet.Get( ATTR_PRESLAYOUT_CHECK_MASTERS ) ).GetValue();
                if (aSet.GetItemState(ATTR_PRESLAYOUT_NAME) == SfxItemState::SET)
                    aFile = static_cast<const SfxStringItem&>(aSet.Get(ATTR_PRESLAYOUT_NAME)).GetValue();
            }
            break;

            default:
                bError = true;
        }
    }

    if (!bError)
    {
        mpDocSh->SetWaitCursor( true );

        /* Here, we only exchange masterpages, therefore the current page
           remains the current page. To prevent calling PageOrderChangedHint
           during insertion and extraction of the masterpages, we block. */
        /* That isn't quitely right. If the masterpageview is active and you are
           removing a masterpage, it's possible that you are removing the
           current masterpage. So you have to call ResetActualPage ! */
        if( mpViewShell->ISA(DrawViewShell) && !bCheckMasters )
            static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(true);

        if (bLoad)
        {
            OUString aFileName = aFile.getToken(0, DOCUMENT_TOKEN);
            SdDrawDocument* pTempDoc = mpDoc->OpenBookmarkDoc( aFileName );

            // #69581: If I chose the standard-template I got no filename and so I get no
            //         SdDrawDocument-Pointer. But the method SetMasterPage is able to handle
            //         a NULL-pointer as a Standard-template ( look at SdDrawDocument::SetMasterPage )
            OUString aLayoutName;
            if( pTempDoc )
                aLayoutName = aFile.getToken(1, DOCUMENT_TOKEN);
            for (auto nSelectedPage : aSelectedPageNums)
                mpDoc->SetMasterPage(nSelectedPage, aLayoutName, pTempDoc, bMasterPage, bCheckMasters);
            mpDoc->CloseBookmarkDoc();
        }
        else
        {
            // use master page with the layout name aFile from current Doc
            for (auto nSelectedPage : aSelectedPageNums)
                mpDoc->SetMasterPage(nSelectedPage, aFile, mpDoc, bMasterPage, bCheckMasters);
        }

        // remove blocking
        if (mpViewShell->ISA(DrawViewShell) && !bCheckMasters )
            static_cast<DrawView*>(mpView)->BlockPageOrderChangedHint(false);

        // if the master page was visible, show it again
        if (!bError)
        {
            if (bOnMaster)
            {
                if (mpViewShell->ISA(DrawViewShell))
                {
                    ::sd::View* pView =
                          static_cast<DrawViewShell*>(mpViewShell)->GetView();
                    for (auto pSelectedPage : aSelectedPages)
                    {
                        sal_uInt16 nPgNum = pSelectedPage->TRG_GetMasterPage().GetPageNum();

                        if (static_cast<DrawViewShell*>(mpViewShell)->GetPageKind() == PK_NOTES)
                            nPgNum++;

                        pView->HideSdrPage();
                        pView->ShowSdrPage(pView->GetModel()->GetMasterPage(nPgNum));
                    }
                }

                // force update of TabBar
                mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_MASTERPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
            }
            else
            {
                for (auto pSelectedPage : aSelectedPages)
                    pSelectedPage->SetAutoLayout(pSelectedPage->GetAutoLayout());
            }
        }

        //Undo transfer to document selection
        for (auto pPage : aUnselect)
            mpDoc->SetSelected(pPage, false);

        // fake a mode change to repaint the page tab bar
        if( mpViewShell && mpViewShell->ISA( DrawViewShell ) )
        {
            DrawViewShell* pDrawViewSh =
                static_cast<DrawViewShell*>(mpViewShell);
            EditMode eMode = pDrawViewSh->GetEditMode();
            bool bLayer = pDrawViewSh->IsLayerModeActive();
            pDrawViewSh->ChangeEditMode( eMode, !bLayer );
            pDrawViewSh->ChangeEditMode( eMode, bLayer );
        }

        mpDocSh->SetWaitCursor( false );
    }
}

} // end of namespace sd

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>