<commit_before>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Core/Context.h"
#include "../Resource/ResourceCache.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"
#include "../Urho2D/AnimatedSprite2D.h"
#include "../Urho2D/Animation2D.h"
#include "../Urho2D/AnimationSet2D.h"
#include "../Urho2D/Sprite2D.h"
#include "../Urho2D/StaticSprite2D.h"

#include "../DebugNew.h"

namespace Urho3D
{

extern const char* URHO2D_CATEGORY;
extern const char* blendModeNames[];

const char* loopModeNames[] =
{
    "Default",
    "ForceLooped",
    "ForceClamped",
    0
};

AnimatedSprite2D::AnimatedSprite2D(Context* context) :
    StaticSprite2D(context),
    speed_(1.0f),
    loopMode_(LM_DEFAULT),
    looped_(false),
    currentTime_(0.0f),
    numTracks_(0)
{
}

AnimatedSprite2D::~AnimatedSprite2D()
{
}

void AnimatedSprite2D::RegisterObject(Context* context)
{
    context->RegisterFactory<AnimatedSprite2D>(URHO2D_CATEGORY);

    COPY_BASE_ATTRIBUTES(StaticSprite2D);
    REMOVE_ATTRIBUTE("Sprite");
    ACCESSOR_ATTRIBUTE("Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
    MIXED_ACCESSOR_ATTRIBUTE("Animation Set", GetAnimationSetAttr, SetAnimationSetAttr, ResourceRef, ResourceRef(AnimatedSprite2D::GetTypeStatic()), AM_DEFAULT);
    ACCESSOR_ATTRIBUTE("Animation", GetAnimation, SetAnimationAttr, String, String::EMPTY, AM_DEFAULT);
    ENUM_ACCESSOR_ATTRIBUTE("Loop Mode", GetLoopMode, SetLoopMode, LoopMode2D, loopModeNames, LM_DEFAULT, AM_DEFAULT);
}

void AnimatedSprite2D::OnSetEnabled()
{
    StaticSprite2D::OnSetEnabled();

    bool enabled = IsEnabledEffective();

    Scene* scene = GetScene();
    if (scene)
    {
        if (enabled)
            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
        else
            UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
    }

    for (unsigned i = 0; i < trackNodes_.Size(); ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetEnabled(enabled);
    }
}

void AnimatedSprite2D::SetSpeed(float speed)
{
    speed_ = speed;
    MarkNetworkUpdate();
}

void AnimatedSprite2D::SetAnimation(AnimationSet2D* animationSet, const String& name, LoopMode2D loopMode)
{
    animationSet_ = animationSet;

    SetAnimation(name, loopMode);
}

void AnimatedSprite2D::SetAnimation(const String& name, LoopMode2D loopMode)
{
    animationName_ = name;

    if (animationSet_)
        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode);
}

void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
{
    if (animationSet == animationSet_)
        return;

    animationSet_ = animationSet;

    SetAnimation(animationName_, loopMode_);
}

void AnimatedSprite2D::SetLoopMode(LoopMode2D loopMode)
{
    if (!animation_)
        return;

    loopMode_ = loopMode;

    switch (loopMode_)
    {
    case LM_FORCE_LOOPED:
        looped_ = true;
        break;

    case LM_FORCE_CLAMPED:
        looped_ = false;
        break;

    default:
        looped_ = animation_->IsLooped();
        break;
    }
}

AnimationSet2D* AnimatedSprite2D::GetAnimationSet() const
{
    return animationSet_;
}

Node* AnimatedSprite2D::GetRootNode() const
{
    return rootNode_;
}

void AnimatedSprite2D::SetAnimationSetAttr(const ResourceRef& value)
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    SetAnimationSet(cache->GetResource<AnimationSet2D>(value.name_));
}

ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
{
    return GetResourceRef(animationSet_, AnimationSet2D::GetTypeStatic());
}

void AnimatedSprite2D::OnNodeSet(Node* node)
{
    StaticSprite2D::OnNodeSet(node);

    if (node)
    {
        Scene* scene = GetScene();
        if (scene && IsEnabledEffective())
            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
    }
    else
    {
        if (rootNode_)
            rootNode_->Remove();

        rootNode_ = 0;
        numTracks_ = 0;
        trackNodes_.Clear();
        trackNodeInfos_.Clear();
    }
}

void AnimatedSprite2D::SetAnimationAttr(const String& name)
{
    animationName_ = name;

    if (animationSet_)
        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode_);
}

void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
{
    boundingBox_.Clear();
    worldBoundingBox_.Clear();

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            worldBoundingBox_.Merge(staticSprite->GetWorldBoundingBox());
    }

    boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
}

void AnimatedSprite2D::OnDrawOrderChanged()
{
    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetLayer(layer_);
    }
}

void AnimatedSprite2D::OnFlipChanged()
{
    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetFlip(flipX_, flipY_);
    }

    // For editor paused mode
    UpdateAnimation(0.0f);
}

void AnimatedSprite2D::UpdateSourceBatches()
{
    sourceBatchesDirty_ = false;
}

void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
{
    if (animation == animation_)
    {
        SetLoopMode(loopMode_);

        currentTime_ = 0.0f;
        UpdateAnimation(0.0f);
        return;
    }

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (trackNodes_[i])
            trackNodes_[i]->SetEnabled(false);
    }

    numTracks_ = 0;
    trackNodes_.Clear();
    trackNodeInfos_.Clear();

    animation_ = animation;

    if (!animation_)
        return;

    currentTime_ = 0.0f;

    if (!rootNode_)
    {
        rootNode_ = GetNode()->CreateChild("_root_", LOCAL);
        rootNode_->SetTemporary(true);
    }

    numTracks_ = animation_->GetNumTracks();
    trackNodes_.Resize(numTracks_);
    trackNodeInfos_.Resize(numTracks_);

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        const AnimationTrack2D& track = animation->GetTrack(i);
        SharedPtr<Node> trackNode(rootNode_->GetChild(track.name_));

        StaticSprite2D* staticSprite = 0;
        if (trackNode)
        {
            // Enable track node
            trackNode->SetEnabled(true);

            // Get StaticSprite2D component
            if (track.hasSprite_)
                staticSprite = trackNode->GetComponent<StaticSprite2D>();
        }
        else
        {
            // Create new track node
            trackNode = rootNode_->CreateChild(track.name_, LOCAL);
            trackNode->SetTemporary(true);

            // Create StaticSprite2D component
            if (track.hasSprite_)
            {
                staticSprite = trackNode->CreateComponent<StaticSprite2D>();
                staticSprite->SetEnabled(IsEnabledEffective());
            }
        }

        if (staticSprite)
        {
            staticSprite->SetLayer(layer_);
            staticSprite->SetBlendMode(blendMode_);
            staticSprite->SetFlip(flipX_, flipY_);
            staticSprite->SetUseHotSpot(true);
        }

        trackNodes_[i] = trackNode;

        trackNodeInfos_[i].hasSprite = track.hasSprite_;
    }

    SetLoopMode(loopMode);
    UpdateAnimation(0.0f);

    MarkNetworkUpdate();
}

void AnimatedSprite2D::UpdateAnimation(float timeStep)
{
    if (!animation_)
        return;

    currentTime_ += timeStep * speed_;

    float time;
    float animationLength = animation_->GetLength();

    if (looped_)
    {
        time = fmodf(currentTime_, animationLength);
        if (time < 0.0f)
            time += animation_->GetLength();
    }
    else
        time = Clamp(currentTime_, 0.0f, animationLength);

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        trackNodeInfos_[i].worldSpace = false;

        const AnimationTrack2D& track = animation_->GetTrack(i);
        const Vector<AnimationKeyFrame2D>& keyFrames = track.keyFrames_;

        // Time out of range
        if (time < keyFrames[0].time_ || time > keyFrames.Back().time_)
            trackNodeInfos_[i].value.enabled_ = false;
        else
        {
            unsigned index = keyFrames.Size() - 1;
            for (unsigned j = 0; j < keyFrames.Size() - 1; ++j)
            {
                if (time <= keyFrames[j + 1].time_)
                {
                    index = j;
                    break;
                }
            }

            const AnimationKeyFrame2D& currKey = keyFrames[index];
            AnimationKeyFrame2D& value = trackNodeInfos_[i].value;

            value.enabled_ = currKey.enabled_;
            value.parent_ = currKey.parent_;

            if (index < keyFrames.Size() - 1)
            {
                const AnimationKeyFrame2D& nextKey = keyFrames[index + 1];
                float t = (time - currKey.time_)  / (nextKey.time_ - currKey.time_);
                value.transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);

                if (trackNodeInfos_[i].hasSprite)
                    value.alpha_ = Urho3D::Lerp(currKey.alpha_, nextKey.alpha_, t);
            }
            else
            {
                value.transform_ = currKey.transform_;

                if (trackNodeInfos_[i].hasSprite)
                    value.alpha_ = currKey.alpha_;
            }

            if (trackNodeInfos_[i].hasSprite)
            {
                value.zIndex_ = currKey.zIndex_;
                value.sprite_ = currKey.sprite_;
                value.useHotSpot_ = currKey.useHotSpot_;
                value.hotSpot_ = currKey.hotSpot_;
            }
        }
    }

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        Node* node = trackNodes_[i];
        TrackNodeInfo& nodeInfo = trackNodeInfos_[i];

        if (!nodeInfo.value.enabled_)
            node->SetEnabled(false);
        else
        {
            node->SetEnabled(true);

            // Calculate world transform.
            CalculateTimelineWorldTransform(i);

            // Update node's transform
            Vector2 position = nodeInfo.value.transform_.position_ * PIXEL_SIZE;
            if (flipX_)
                position.x_ = -position.x_;
            if (flipY_)
                position.y_ = -position.y_;
            node->SetPosition(position);

            float angle = nodeInfo.value.transform_.angle_;
            if (flipX_ != flipY_)
                angle = -angle;
            node->SetRotation(angle);
            node->SetScale(nodeInfo.value.transform_.scale_);

            if (nodeInfo.hasSprite)
            {
                StaticSprite2D* staticSprite = node->GetComponent<StaticSprite2D>();
                if (staticSprite)
                {
                    staticSprite->SetOrderInLayer(orderInLayer_ + nodeInfo.value.zIndex_);
                    staticSprite->SetSprite(nodeInfo.value.sprite_);
                    staticSprite->SetAlpha(nodeInfo.value.alpha_);
                    staticSprite->SetUseHotSpot(nodeInfo.value.useHotSpot_);
                    staticSprite->SetHotSpot(nodeInfo.value.hotSpot_);
                }
            }
        }
    }
}

void AnimatedSprite2D::CalculateTimelineWorldTransform(unsigned index)
{
    TrackNodeInfo& info = trackNodeInfos_[index];
    if (info.worldSpace)
        return;

    info.worldSpace = true;

    int parent = info.value.parent_;
    if (parent != -1)
    {
        CalculateTimelineWorldTransform(parent);
        info.value.transform_ = trackNodeInfos_[parent].value.transform_ * info.value.transform_;
    }
}

void AnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace ScenePostUpdate;
    float timeStep = eventData[P_TIMESTEP].GetFloat();
    UpdateAnimation(timeStep);
}

}
<commit_msg>Added nullcheck to AnimatedSprite2D::UpdateAnimation(). Thanks to rku for noticing.<commit_after>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Core/Context.h"
#include "../Resource/ResourceCache.h"
#include "../Scene/Scene.h"
#include "../Scene/SceneEvents.h"
#include "../Urho2D/AnimatedSprite2D.h"
#include "../Urho2D/Animation2D.h"
#include "../Urho2D/AnimationSet2D.h"
#include "../Urho2D/Sprite2D.h"
#include "../Urho2D/StaticSprite2D.h"

#include "../DebugNew.h"

namespace Urho3D
{

extern const char* URHO2D_CATEGORY;
extern const char* blendModeNames[];

const char* loopModeNames[] =
{
    "Default",
    "ForceLooped",
    "ForceClamped",
    0
};

AnimatedSprite2D::AnimatedSprite2D(Context* context) :
    StaticSprite2D(context),
    speed_(1.0f),
    loopMode_(LM_DEFAULT),
    looped_(false),
    currentTime_(0.0f),
    numTracks_(0)
{
}

AnimatedSprite2D::~AnimatedSprite2D()
{
}

void AnimatedSprite2D::RegisterObject(Context* context)
{
    context->RegisterFactory<AnimatedSprite2D>(URHO2D_CATEGORY);

    COPY_BASE_ATTRIBUTES(StaticSprite2D);
    REMOVE_ATTRIBUTE("Sprite");
    ACCESSOR_ATTRIBUTE("Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
    MIXED_ACCESSOR_ATTRIBUTE("Animation Set", GetAnimationSetAttr, SetAnimationSetAttr, ResourceRef, ResourceRef(AnimatedSprite2D::GetTypeStatic()), AM_DEFAULT);
    ACCESSOR_ATTRIBUTE("Animation", GetAnimation, SetAnimationAttr, String, String::EMPTY, AM_DEFAULT);
    ENUM_ACCESSOR_ATTRIBUTE("Loop Mode", GetLoopMode, SetLoopMode, LoopMode2D, loopModeNames, LM_DEFAULT, AM_DEFAULT);
}

void AnimatedSprite2D::OnSetEnabled()
{
    StaticSprite2D::OnSetEnabled();

    bool enabled = IsEnabledEffective();

    Scene* scene = GetScene();
    if (scene)
    {
        if (enabled)
            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
        else
            UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
    }

    for (unsigned i = 0; i < trackNodes_.Size(); ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetEnabled(enabled);
    }
}

void AnimatedSprite2D::SetSpeed(float speed)
{
    speed_ = speed;
    MarkNetworkUpdate();
}

void AnimatedSprite2D::SetAnimation(AnimationSet2D* animationSet, const String& name, LoopMode2D loopMode)
{
    animationSet_ = animationSet;

    SetAnimation(name, loopMode);
}

void AnimatedSprite2D::SetAnimation(const String& name, LoopMode2D loopMode)
{
    animationName_ = name;

    if (animationSet_)
        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode);
}

void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
{
    if (animationSet == animationSet_)
        return;

    animationSet_ = animationSet;

    SetAnimation(animationName_, loopMode_);
}

void AnimatedSprite2D::SetLoopMode(LoopMode2D loopMode)
{
    if (!animation_)
        return;

    loopMode_ = loopMode;

    switch (loopMode_)
    {
    case LM_FORCE_LOOPED:
        looped_ = true;
        break;

    case LM_FORCE_CLAMPED:
        looped_ = false;
        break;

    default:
        looped_ = animation_->IsLooped();
        break;
    }
}

AnimationSet2D* AnimatedSprite2D::GetAnimationSet() const
{
    return animationSet_;
}

Node* AnimatedSprite2D::GetRootNode() const
{
    return rootNode_;
}

void AnimatedSprite2D::SetAnimationSetAttr(const ResourceRef& value)
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    SetAnimationSet(cache->GetResource<AnimationSet2D>(value.name_));
}

ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
{
    return GetResourceRef(animationSet_, AnimationSet2D::GetTypeStatic());
}

void AnimatedSprite2D::OnNodeSet(Node* node)
{
    StaticSprite2D::OnNodeSet(node);

    if (node)
    {
        Scene* scene = GetScene();
        if (scene && IsEnabledEffective())
            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
    }
    else
    {
        if (rootNode_)
            rootNode_->Remove();

        rootNode_ = 0;
        numTracks_ = 0;
        trackNodes_.Clear();
        trackNodeInfos_.Clear();
    }
}

void AnimatedSprite2D::SetAnimationAttr(const String& name)
{
    animationName_ = name;

    if (animationSet_)
        SetAnimation(animationSet_->GetAnimation(animationName_), loopMode_);
}

void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
{
    boundingBox_.Clear();
    worldBoundingBox_.Clear();

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            worldBoundingBox_.Merge(staticSprite->GetWorldBoundingBox());
    }

    boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
}

void AnimatedSprite2D::OnDrawOrderChanged()
{
    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetLayer(layer_);
    }
}

void AnimatedSprite2D::OnFlipChanged()
{
    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (!trackNodes_[i])
            continue;

        StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
        if (staticSprite)
            staticSprite->SetFlip(flipX_, flipY_);
    }

    // For editor paused mode
    UpdateAnimation(0.0f);
}

void AnimatedSprite2D::UpdateSourceBatches()
{
    sourceBatchesDirty_ = false;
}

void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
{
    if (animation == animation_)
    {
        SetLoopMode(loopMode_);

        currentTime_ = 0.0f;
        UpdateAnimation(0.0f);
        return;
    }

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        if (trackNodes_[i])
            trackNodes_[i]->SetEnabled(false);
    }

    numTracks_ = 0;
    trackNodes_.Clear();
    trackNodeInfos_.Clear();

    animation_ = animation;

    if (!animation_)
        return;

    currentTime_ = 0.0f;

    if (!rootNode_)
    {
        rootNode_ = GetNode()->CreateChild("_root_", LOCAL);
        rootNode_->SetTemporary(true);
    }

    numTracks_ = animation_->GetNumTracks();
    trackNodes_.Resize(numTracks_);
    trackNodeInfos_.Resize(numTracks_);

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        const AnimationTrack2D& track = animation->GetTrack(i);
        SharedPtr<Node> trackNode(rootNode_->GetChild(track.name_));

        StaticSprite2D* staticSprite = 0;
        if (trackNode)
        {
            // Enable track node
            trackNode->SetEnabled(true);

            // Get StaticSprite2D component
            if (track.hasSprite_)
                staticSprite = trackNode->GetComponent<StaticSprite2D>();
        }
        else
        {
            // Create new track node
            trackNode = rootNode_->CreateChild(track.name_, LOCAL);
            trackNode->SetTemporary(true);

            // Create StaticSprite2D component
            if (track.hasSprite_)
            {
                staticSprite = trackNode->CreateComponent<StaticSprite2D>();
                staticSprite->SetEnabled(IsEnabledEffective());
            }
        }

        if (staticSprite)
        {
            staticSprite->SetLayer(layer_);
            staticSprite->SetBlendMode(blendMode_);
            staticSprite->SetFlip(flipX_, flipY_);
            staticSprite->SetUseHotSpot(true);
        }

        trackNodes_[i] = trackNode;

        trackNodeInfos_[i].hasSprite = track.hasSprite_;
    }

    SetLoopMode(loopMode);
    UpdateAnimation(0.0f);

    MarkNetworkUpdate();
}

void AnimatedSprite2D::UpdateAnimation(float timeStep)
{
    if (!animation_)
        return;

    currentTime_ += timeStep * speed_;

    float time;
    float animationLength = animation_->GetLength();

    if (looped_)
    {
        time = fmodf(currentTime_, animationLength);
        if (time < 0.0f)
            time += animation_->GetLength();
    }
    else
        time = Clamp(currentTime_, 0.0f, animationLength);

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        trackNodeInfos_[i].worldSpace = false;

        const AnimationTrack2D& track = animation_->GetTrack(i);
        const Vector<AnimationKeyFrame2D>& keyFrames = track.keyFrames_;

        // Time out of range
        if (time < keyFrames[0].time_ || time > keyFrames.Back().time_)
            trackNodeInfos_[i].value.enabled_ = false;
        else
        {
            unsigned index = keyFrames.Size() - 1;
            for (unsigned j = 0; j < keyFrames.Size() - 1; ++j)
            {
                if (time <= keyFrames[j + 1].time_)
                {
                    index = j;
                    break;
                }
            }

            const AnimationKeyFrame2D& currKey = keyFrames[index];
            AnimationKeyFrame2D& value = trackNodeInfos_[i].value;

            value.enabled_ = currKey.enabled_;
            value.parent_ = currKey.parent_;

            if (index < keyFrames.Size() - 1)
            {
                const AnimationKeyFrame2D& nextKey = keyFrames[index + 1];
                float t = (time - currKey.time_)  / (nextKey.time_ - currKey.time_);
                value.transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);

                if (trackNodeInfos_[i].hasSprite)
                    value.alpha_ = Urho3D::Lerp(currKey.alpha_, nextKey.alpha_, t);
            }
            else
            {
                value.transform_ = currKey.transform_;

                if (trackNodeInfos_[i].hasSprite)
                    value.alpha_ = currKey.alpha_;
            }

            if (trackNodeInfos_[i].hasSprite)
            {
                value.zIndex_ = currKey.zIndex_;
                value.sprite_ = currKey.sprite_;
                value.useHotSpot_ = currKey.useHotSpot_;
                value.hotSpot_ = currKey.hotSpot_;
            }
        }
    }

    for (unsigned i = 0; i < numTracks_; ++i)
    {
        Node* node = trackNodes_[i];
        if (!node)
            continue;

        TrackNodeInfo& nodeInfo = trackNodeInfos_[i];

        if (!nodeInfo.value.enabled_)
            node->SetEnabled(false);
        else
        {
            node->SetEnabled(true);

            // Calculate world transform.
            CalculateTimelineWorldTransform(i);

            // Update node's transform
            Vector2 position = nodeInfo.value.transform_.position_ * PIXEL_SIZE;
            if (flipX_)
                position.x_ = -position.x_;
            if (flipY_)
                position.y_ = -position.y_;
            node->SetPosition(position);

            float angle = nodeInfo.value.transform_.angle_;
            if (flipX_ != flipY_)
                angle = -angle;
            node->SetRotation(angle);
            node->SetScale(nodeInfo.value.transform_.scale_);

            if (nodeInfo.hasSprite)
            {
                StaticSprite2D* staticSprite = node->GetComponent<StaticSprite2D>();
                if (staticSprite)
                {
                    staticSprite->SetOrderInLayer(orderInLayer_ + nodeInfo.value.zIndex_);
                    staticSprite->SetSprite(nodeInfo.value.sprite_);
                    staticSprite->SetAlpha(nodeInfo.value.alpha_);
                    staticSprite->SetUseHotSpot(nodeInfo.value.useHotSpot_);
                    staticSprite->SetHotSpot(nodeInfo.value.hotSpot_);
                }
            }
        }
    }
}

void AnimatedSprite2D::CalculateTimelineWorldTransform(unsigned index)
{
    TrackNodeInfo& info = trackNodeInfos_[index];
    if (info.worldSpace)
        return;

    info.worldSpace = true;

    int parent = info.value.parent_;
    if (parent != -1)
    {
        CalculateTimelineWorldTransform(parent);
        info.value.transform_ = trackNodeInfos_[parent].value.transform_ * info.value.transform_;
    }
}

void AnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace ScenePostUpdate;
    float timeStep = eventData[P_TIMESTEP].GetFloat();
    UpdateAnimation(timeStep);
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AUser.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 06:54:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_ADO_USER_HXX_
#define _CONNECTIVITY_ADO_USER_HXX_

#ifndef _CONNECTIVITY_SDBCX_USER_HXX_
#include "connectivity/sdbcx/VUser.hxx"
#endif
#ifndef _CONNECTIVITY_ADO_AWRAPADOX_HXX_
#include "ado/Awrapadox.hxx"
#endif

namespace connectivity
{
    namespace ado
    {
        class OCatalog;
        typedef connectivity::sdbcx::OUser OUser_TYPEDEF;

        class OAdoUser : public OUser_TYPEDEF
        {
        protected:
            WpADOUser   m_aUser;
            OCatalog*   m_pCatalog;

            virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
                            sal_Int32 nHandle,
                                    const ::com::sun::star::uno::Any& rValue
                         )
                         throw (::com::sun::star::uno::Exception);
            virtual void SAL_CALL getFastPropertyValue(
                                    ::com::sun::star::uno::Any& rValue,
                                    sal_Int32 nHandle
                                         ) const;
        public:
            virtual void refreshGroups();
        public:
            OAdoUser(OCatalog* _pParent,sal_Bool _bCase,    ADOUser* _pUser=NULL);
            OAdoUser(OCatalog* _pParent,sal_Bool _bCase,  const ::rtl::OUString& _Name);

            // com::sun::star::lang::XUnoTunnel
            virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException);
            static ::com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId();
            virtual void SAL_CALL acquire() throw();
            virtual void SAL_CALL release() throw();

            // XUser
            virtual void SAL_CALL changePassword( const ::rtl::OUString& objPassword, const ::rtl::OUString& newPassword ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            // XAuthorizable
            virtual sal_Int32 SAL_CALL getPrivileges( const ::rtl::OUString& objName, sal_Int32 objType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Int32 SAL_CALL getGrantablePrivileges( const ::rtl::OUString& objName, sal_Int32 objType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL grantPrivileges( const ::rtl::OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL revokePrivileges( const ::rtl::OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            WpADOUser getImpl() const { return m_aUser;}
        };

        class OUserExtend;
        typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;

        class OUserExtend : public OAdoUser,
                            public OUserExtend_PROP
        {
        protected:
            ::rtl::OUString m_Password;
            // OPropertyArrayUsageHelper
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const;
            // OPropertySetHelper
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();
        public:
            OUserExtend(OCatalog* _pParent,sal_Bool _bCase,ADOUser* _pUser=NULL);
            OUserExtend(OCatalog* _pParent,sal_Bool _bCase,const ::rtl::OUString& _Name);

            virtual void construct();
            ::rtl::OUString getPassword() const { return m_Password;}
        };
    }
}
#endif // _CONNECTIVITY_ADO_USER_HXX_

<commit_msg>INTEGRATION: CWS mingwport03 (1.7.168); FILE MERGED 2006/09/07 10:22:10 vg 1.7.168.1: #i53572# MinGW port<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: AUser.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2007-03-26 14:01:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_ADO_USER_HXX_
#define _CONNECTIVITY_ADO_USER_HXX_

#ifndef _CONNECTIVITY_SDBCX_USER_HXX_
#include "connectivity/sdbcx/VUser.hxx"
#endif
#ifndef _CONNECTIVITY_ADO_AWRAPADOX_HXX_
#include "ado/Awrapadox.hxx"
#endif

namespace connectivity
{
    namespace ado
    {
        class OCatalog;
        typedef connectivity::sdbcx::OUser OUser_TYPEDEF;
        typedef connectivity::sdbcx::OUser_BASE OUser_BASE_TYPEDEF;

        class OAdoUser : public OUser_TYPEDEF
        {
        protected:
            WpADOUser   m_aUser;
            OCatalog*   m_pCatalog;

            virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
                            sal_Int32 nHandle,
                                    const ::com::sun::star::uno::Any& rValue
                         )
                         throw (::com::sun::star::uno::Exception);
            virtual void SAL_CALL getFastPropertyValue(
                                    ::com::sun::star::uno::Any& rValue,
                                    sal_Int32 nHandle
                                         ) const;
        public:
            virtual void refreshGroups();
        public:
            OAdoUser(OCatalog* _pParent,sal_Bool _bCase,    ADOUser* _pUser=NULL);
            OAdoUser(OCatalog* _pParent,sal_Bool _bCase,  const ::rtl::OUString& _Name);

            // com::sun::star::lang::XUnoTunnel
            virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException);
            static ::com::sun::star::uno::Sequence< sal_Int8 > getUnoTunnelImplementationId();
            virtual void SAL_CALL acquire() throw();
            virtual void SAL_CALL release() throw();

            // XUser
            virtual void SAL_CALL changePassword( const ::rtl::OUString& objPassword, const ::rtl::OUString& newPassword ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            // XAuthorizable
            virtual sal_Int32 SAL_CALL getPrivileges( const ::rtl::OUString& objName, sal_Int32 objType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual sal_Int32 SAL_CALL getGrantablePrivileges( const ::rtl::OUString& objName, sal_Int32 objType ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL grantPrivileges( const ::rtl::OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
            virtual void SAL_CALL revokePrivileges( const ::rtl::OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);

            WpADOUser getImpl() const { return m_aUser;}
        };

        class OUserExtend;
        typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP;

        class OUserExtend : public OAdoUser,
                            public OUserExtend_PROP
        {
        protected:
            ::rtl::OUString m_Password;
            // OPropertyArrayUsageHelper
            virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const;
            // OPropertySetHelper
            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper();
        public:
            OUserExtend(OCatalog* _pParent,sal_Bool _bCase,ADOUser* _pUser=NULL);
            OUserExtend(OCatalog* _pParent,sal_Bool _bCase,const ::rtl::OUString& _Name);

            virtual void construct();
            ::rtl::OUString getPassword() const { return m_Password;}
        };
    }
}
#endif // _CONNECTIVITY_ADO_USER_HXX_

<|endoftext|>


<commit_before>// maze.cpp
// 2D maze data & routines

// Copyright 2015 Matthew Chandler

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <string>
#include <stdexcept>

#include <gtkmm/button.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/grid.h>
#include <gtkmm/label.h>
#include <gtkmm/separator.h>

#include "maze.hpp"

Maze::Maze(const unsigned int width, const unsigned int height):
    _grid_width(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _grid_height(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _room_attempts(Gtk::Adjustment::create(25, 0.0, 10000.0, 1.0)),
    _wall_rm_attempts(Gtk::Adjustment::create(100, 0.0, 10000.0, 1.0))
{
    set_title("MazeGen 2D"); // TODO: get from config file
    set_default_size(800, 600);

    Gtk::Grid * layout = Gtk::manage(new Gtk::Grid);
    layout->set_border_width(3);
    layout->set_row_spacing(3);
    layout->set_column_spacing(5);
    add(*layout);

    layout->attach(_draw_area, 0, 0, 1, 10);
    _draw_area.set_hexpand();
    _draw_area.set_vexpand();
    _draw_area.signal_draw().connect(sigc::bind(sigc::mem_fun(*this, &Maze::draw), 0, 0));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid width")), 1, 0, 1, 1);
    layout->attach(_grid_width, 2, 0, 1, 1);
    _grid_width.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid height")), 1, 1, 1, 1);
    layout->attach(_grid_height, 2, 1, 1, 1);
    _grid_height.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 2, 2, 1);

    layout->attach(*Gtk::manage(new Gtk::Label("Maze algorithm")), 1, 3, 1, 1);
    layout->attach(_mazegen, 2, 3, 1, 1);
    _mazegen.append("Depth First Search");
    _mazegen.append("Prim's Algorithm");
    _mazegen.append("Kruskal's Algorithm");
    _mazegen.set_active_text("Depth First Search");
    _mazegen.signal_changed().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Room attempts")), 1, 4, 1, 1);
    layout->attach(_room_attempts, 2, 4, 1, 1);
    _room_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Wall removal attempts")), 1, 5, 1, 1);
    layout->attach(_wall_rm_attempts, 2, 5, 1, 1);
    _wall_rm_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 6, 2, 1);

    Gtk::Button * regen_butt = Gtk::manage(new Gtk::Button("Regenerate"));
    layout->attach(*regen_butt, 1, 7, 2, 1);
    regen_butt->set_hexpand(false);
    regen_butt->set_halign(Gtk::ALIGN_CENTER);
    regen_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::regen));

    Gtk::Label * spacer = Gtk::manage(new Gtk::Label);
    spacer->set_vexpand(true);
    layout->attach(*spacer, 1, 8, 2, 1);

    Gtk::Button * save_butt = Gtk::manage(new Gtk::Button("Save image to disk"));
    layout->attach(*save_butt, 1, 9, 1, 1);
    save_butt->set_hexpand(false);
    save_butt->set_halign(Gtk::ALIGN_END);
    save_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::save));

    Gtk::Button * close_butt = Gtk::manage(new Gtk::Button("Close"));
    layout->attach(*close_butt, 2, 9, 1, 1);
    close_butt->set_hexpand(false);
    close_butt->set_halign(Gtk::ALIGN_START);
    close_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::hide));

    show_all_children();
    regen();
}

bool Maze::draw(const Cairo::RefPtr<Cairo::Context> & cr, const unsigned int width, const unsigned int height)
{
    double width_d, height_d;

    if(width == 0)
        width_d = (double)_draw_area.get_allocated_width();
    else
        width_d = (double)width;

    if(height == 0)
        height_d = (double)_draw_area.get_allocated_height();
    else
        height_d = (double)height;

    // set background
    cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
    cr->rectangle(0.0, 0.0, width_d, height_d);
    cr->fill_preserve();

    // set line properties
    cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
    cr->set_line_width(2.0);

    cr->stroke();

    double cell_scale_x = width_d / (double)_grid.grid[0].size();
    double cell_scale_y = height_d / (double)_grid.grid.size();

    // draw maze cells
    for(size_t row = 0; row < _grid.grid.size(); ++row)
    {
        for(size_t col = 0; col < _grid.grid[row].size(); ++col)
        {
            sf::Vector2f ul(cell_scale_x * (double)col, cell_scale_y * (double)row);

            if(_grid.grid[row][col].walls[UP])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x + cell_scale_x, ul.y);
            }
            if(_grid.grid[row][col].walls[LEFT])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x, ul.y + cell_scale_y);
            }
        }
    }

    cr->stroke();

    return true;
};

void Maze::regen()
{
    unsigned int grid_width = _grid_width.get_value_as_int();
    unsigned int grid_height = _grid_height.get_value_as_int();
    unsigned int room_attempts = _room_attempts.get_value_as_int();
    unsigned int wall_rm_attempts = _wall_rm_attempts.get_value_as_int();

    Grid::Mazegen_alg mazegen;
    std::string mazegen_txt = _mazegen.get_active_text();
    if(mazegen_txt == "Depth First Search")
        mazegen = Grid::MAZEGEN_DFS;
    else if(mazegen_txt == "Prim's Algorithm")
        mazegen = Grid::MAZEGEN_PRIM;
    else if(mazegen_txt == "Kruskal's Algorithm")
        mazegen = Grid::MAZEGEN_KRUSKAL;
    else
        throw std::invalid_argument(std::string("Unknown maze algorithm: ") + mazegen_txt);

    _grid.init(grid_width, grid_height, mazegen, room_attempts, wall_rm_attempts);

    _draw_area.queue_draw();
}

void Maze::save()
{
    // get image size from user
    Gtk::Dialog size_dialog("Image Size", *this, true);
    size_dialog.add_button("OK", Gtk::RESPONSE_OK);
    size_dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);

    Gtk::Grid size_layout;
    size_layout.set_border_width(3);
    size_layout.set_row_spacing(3);
    size_layout.set_column_spacing(3);
    size_dialog.get_content_area()->add(size_layout);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Width:")), 0, 0, 1, 1);
    Gtk::SpinButton width_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(width_spin, 1, 0, 1, 1);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Height:")), 0, 1, 1, 1);
    Gtk::SpinButton height_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(height_spin, 1, 1, 1, 1);

    size_dialog.show_all_children();

    if(size_dialog.run() != Gtk::RESPONSE_OK)
        return;

    size_dialog.hide();

    Gtk::FileChooserDialog chooser(*this, "Save to", Gtk::FILE_CHOOSER_ACTION_SAVE);
    chooser.set_modal(true);
    chooser.set_current_folder(".");
    chooser.set_select_multiple(false);
    chooser.set_do_overwrite_confirmation(true);
    chooser.add_button("Cancel", Gtk::RESPONSE_CANCEL);
    chooser.add_button("Save", Gtk::RESPONSE_OK);

    for(const auto & format: Gdk::Pixbuf::get_formats())
    {
        if(!format.is_writable())
            continue;

        Glib::RefPtr<Gtk::FileFilter> image_type = Gtk::FileFilter::create();
        image_type->set_name(format.get_name());

        for(const auto & mimetype: format.get_mime_types())
            image_type->add_mime_type(mimetype);

        chooser.add_filter(image_type);

        if(format.get_name() == "png")
            chooser.set_filter(image_type);
    }

    if(chooser.run() != Gtk::RESPONSE_OK)
        return;

    chooser.hide();

    unsigned int width = width_spin.get_value_as_int();
    unsigned int height = height_spin.get_value_as_int();

    Cairo::RefPtr<Cairo::ImageSurface> render_target = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
    draw(Cairo::Context::create(render_target), width, height);
    Gdk::Pixbuf::create(render_target, 0, 0, width, height)->save(chooser.get_filename(), chooser.get_filter()->get_name());
}
<commit_msg>add error checking to save function<commit_after>// maze.cpp
// 2D maze data & routines

// Copyright 2015 Matthew Chandler

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <string>
#include <stdexcept>

#include <gtkmm/button.h>
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/grid.h>
#include <gtkmm/label.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/separator.h>

#include "maze.hpp"

Maze::Maze(const unsigned int width, const unsigned int height):
    _grid_width(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _grid_height(Gtk::Adjustment::create(32, 1.0, 100.0, 1.0)),
    _room_attempts(Gtk::Adjustment::create(25, 0.0, 10000.0, 1.0)),
    _wall_rm_attempts(Gtk::Adjustment::create(100, 0.0, 10000.0, 1.0))
{
    set_title("MazeGen 2D"); // TODO: get from config file
    set_default_size(800, 600);

    Gtk::Grid * layout = Gtk::manage(new Gtk::Grid);
    layout->set_border_width(3);
    layout->set_row_spacing(3);
    layout->set_column_spacing(5);
    add(*layout);

    layout->attach(_draw_area, 0, 0, 1, 10);
    _draw_area.set_hexpand();
    _draw_area.set_vexpand();
    _draw_area.signal_draw().connect(sigc::bind(sigc::mem_fun(*this, &Maze::draw), 0, 0));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid width")), 1, 0, 1, 1);
    layout->attach(_grid_width, 2, 0, 1, 1);
    _grid_width.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Grid height")), 1, 1, 1, 1);
    layout->attach(_grid_height, 2, 1, 1, 1);
    _grid_height.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 2, 2, 1);

    layout->attach(*Gtk::manage(new Gtk::Label("Maze algorithm")), 1, 3, 1, 1);
    layout->attach(_mazegen, 2, 3, 1, 1);
    _mazegen.append("Depth First Search");
    _mazegen.append("Prim's Algorithm");
    _mazegen.append("Kruskal's Algorithm");
    _mazegen.set_active_text("Depth First Search");
    _mazegen.signal_changed().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Room attempts")), 1, 4, 1, 1);
    layout->attach(_room_attempts, 2, 4, 1, 1);
    _room_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Label("Wall removal attempts")), 1, 5, 1, 1);
    layout->attach(_wall_rm_attempts, 2, 5, 1, 1);
    _wall_rm_attempts.signal_activate().connect(sigc::mem_fun(*this, &Maze::regen));

    layout->attach(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), 1, 6, 2, 1);

    Gtk::Button * regen_butt = Gtk::manage(new Gtk::Button("Regenerate"));
    layout->attach(*regen_butt, 1, 7, 2, 1);
    regen_butt->set_hexpand(false);
    regen_butt->set_halign(Gtk::ALIGN_CENTER);
    regen_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::regen));

    Gtk::Label * spacer = Gtk::manage(new Gtk::Label);
    spacer->set_vexpand(true);
    layout->attach(*spacer, 1, 8, 2, 1);

    Gtk::Button * save_butt = Gtk::manage(new Gtk::Button("Save image to disk"));
    layout->attach(*save_butt, 1, 9, 1, 1);
    save_butt->set_hexpand(false);
    save_butt->set_halign(Gtk::ALIGN_END);
    save_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::save));

    Gtk::Button * close_butt = Gtk::manage(new Gtk::Button("Close"));
    layout->attach(*close_butt, 2, 9, 1, 1);
    close_butt->set_hexpand(false);
    close_butt->set_halign(Gtk::ALIGN_START);
    close_butt->signal_clicked().connect(sigc::mem_fun(*this, &Maze::hide));

    show_all_children();
    regen();
}

bool Maze::draw(const Cairo::RefPtr<Cairo::Context> & cr, const unsigned int width, const unsigned int height)
{
    double width_d, height_d;

    if(width == 0)
        width_d = (double)_draw_area.get_allocated_width();
    else
        width_d = (double)width;

    if(height == 0)
        height_d = (double)_draw_area.get_allocated_height();
    else
        height_d = (double)height;

    // set background
    cr->set_source_rgba(1.0, 1.0, 1.0, 1.0);
    cr->rectangle(0.0, 0.0, width_d, height_d);
    cr->fill_preserve();

    // set line properties
    cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
    cr->set_line_width(2.0);

    cr->stroke();

    double cell_scale_x = width_d / (double)_grid.grid[0].size();
    double cell_scale_y = height_d / (double)_grid.grid.size();

    // draw maze cells
    for(size_t row = 0; row < _grid.grid.size(); ++row)
    {
        for(size_t col = 0; col < _grid.grid[row].size(); ++col)
        {
            sf::Vector2f ul(cell_scale_x * (double)col, cell_scale_y * (double)row);

            if(_grid.grid[row][col].walls[UP])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x + cell_scale_x, ul.y);
            }
            if(_grid.grid[row][col].walls[LEFT])
            {
                cr->move_to(ul.x, ul.y);
                cr->line_to(ul.x, ul.y + cell_scale_y);
            }
        }
    }

    cr->stroke();

    return true;
};

void Maze::regen()
{
    unsigned int grid_width = _grid_width.get_value_as_int();
    unsigned int grid_height = _grid_height.get_value_as_int();
    unsigned int room_attempts = _room_attempts.get_value_as_int();
    unsigned int wall_rm_attempts = _wall_rm_attempts.get_value_as_int();

    Grid::Mazegen_alg mazegen;
    std::string mazegen_txt = _mazegen.get_active_text();
    if(mazegen_txt == "Depth First Search")
        mazegen = Grid::MAZEGEN_DFS;
    else if(mazegen_txt == "Prim's Algorithm")
        mazegen = Grid::MAZEGEN_PRIM;
    else if(mazegen_txt == "Kruskal's Algorithm")
        mazegen = Grid::MAZEGEN_KRUSKAL;
    else
        throw std::invalid_argument(std::string("Unknown maze algorithm: ") + mazegen_txt);

    _grid.init(grid_width, grid_height, mazegen, room_attempts, wall_rm_attempts);

    _draw_area.queue_draw();
}

void Maze::save()
{
    // get image size from user
    Gtk::Dialog size_dialog("Image Size", *this, true);
    size_dialog.add_button("OK", Gtk::RESPONSE_OK);
    size_dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);

    Gtk::Grid size_layout;
    size_layout.set_border_width(3);
    size_layout.set_row_spacing(3);
    size_layout.set_column_spacing(3);
    size_dialog.get_content_area()->add(size_layout);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Width:")), 0, 0, 1, 1);
    Gtk::SpinButton width_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(width_spin, 1, 0, 1, 1);

    size_layout.attach(*Gtk::manage(new Gtk::Label("Height:")), 0, 1, 1, 1);
    Gtk::SpinButton height_spin(Gtk::Adjustment::create(512.0, 1.0, 10000.0));
    size_layout.attach(height_spin, 1, 1, 1, 1);

    size_dialog.show_all_children();

    if(size_dialog.run() != Gtk::RESPONSE_OK)
        return;

    size_dialog.hide();

    Gtk::FileChooserDialog chooser(*this, "Save to", Gtk::FILE_CHOOSER_ACTION_SAVE);
    chooser.set_modal(true);
    chooser.set_current_folder(".");
    chooser.set_select_multiple(false);
    chooser.set_do_overwrite_confirmation(true);
    chooser.add_button("Cancel", Gtk::RESPONSE_CANCEL);
    chooser.add_button("Save", Gtk::RESPONSE_OK);

    for(const auto & format: Gdk::Pixbuf::get_formats())
    {
        if(!format.is_writable())
            continue;

        Glib::RefPtr<Gtk::FileFilter> image_type = Gtk::FileFilter::create();
        image_type->set_name(format.get_name());

        for(const auto & mimetype: format.get_mime_types())
            image_type->add_mime_type(mimetype);

        chooser.add_filter(image_type);

        if(format.get_name() == "png")
            chooser.set_filter(image_type);
    }

    if(chooser.run() != Gtk::RESPONSE_OK)
        return;

    chooser.hide();

    unsigned int width = width_spin.get_value_as_int();
    unsigned int height = height_spin.get_value_as_int();

    Cairo::RefPtr<Cairo::ImageSurface> render_target = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height);
    draw(Cairo::Context::create(render_target), width, height);

    try
    {
        Gdk::Pixbuf::create(render_target, 0, 0, width, height)->
            save(chooser.get_filename(), chooser.get_filter()->get_name());
    }
    catch(const Glib::Error & e)
    {
        Gtk::MessageDialog error_box(*this, std::string("Error saving to ") + chooser.get_filename(),
            false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_box.set_secondary_text(e.what());
        error_box.run();
    }
}
<|endoftext|>


<commit_before>#include <agge/platform/bitmap.h>

#include <CoreGraphics/CoreGraphics.h>
#include <new>

namespace agge
{
	namespace platform
	{
		namespace
		{
			template <typename T>
			void swap(T &lhs, T &rhs)
			{	T t = lhs; lhs = rhs, rhs = t;	}
		}

		raw_bitmap::~raw_bitmap()
		{
			delete []_memory;
		}

		void raw_bitmap::resize(count_t width, count_t height)
		{
			count_t stride = calculate_stride(width + _extra_pixels);
			count_t size = stride * height;

			if (size > _allocated_width /*size, actually*/)
			{
				uint8_t *memory = new uint8_t[size];

				_allocated_width = size;
				swap(_memory, memory);
				delete []memory;
			}
			_width = width;
			_height = height;
			_stride = stride;
		}

		void raw_bitmap::blit(CGContextRef context, int x, int y, count_t width, count_t height) const
		{
			count_t stride = calculate_stride(_width + _extra_pixels);
			count_t size = stride * height;
			size_t component_bits = _bpp == bpp32 ? 8 : _bpp == bpp16 ? 5 : 8;
			int format = _bpp == bpp32 ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaNone;

			CGColorSpaceRef cs = _bpp == bpp8 ? ::CGColorSpaceCreateDeviceGray() : ::CGColorSpaceCreateDeviceRGB();
			CGDataProviderRef provider = ::CGDataProviderCreateWithData(0, _memory, size, 0);
			CGImageRef image = ::CGImageCreate(width, height, component_bits, _bpp, stride, cs, format, provider, NULL,
				FALSE, kCGRenderingIntentDefault);
			::CGDataProviderRelease(provider);
			::CGColorSpaceRelease(cs);

			CGRect destination = { { CGFloat(x), CGFloat(y) }, { CGFloat(width), CGFloat(height) } };

			::CGContextDrawImage(context, destination, image);
			::CGImageRelease(image);
		}
	}
}
<commit_msg>Faster blitting under macos due to temporary bitmap getting created in CGContext's native colorspace<commit_after>#include <agge/platform/bitmap.h>

#include <CoreGraphics/CoreGraphics.h>
#include <new>

namespace agge
{
	namespace platform
	{
		namespace
		{
			template <typename T>
			void swap(T &lhs, T &rhs)
			{	T t = lhs; lhs = rhs, rhs = t;	}
		}

		raw_bitmap::~raw_bitmap()
		{
			delete []_memory;
		}

		void raw_bitmap::resize(count_t width, count_t height)
		{
			count_t stride = calculate_stride(width + _extra_pixels);
			count_t size = stride * height;

			if (size > _allocated_width /*size, actually*/)
			{
				uint8_t *memory = new uint8_t[size];

				_allocated_width = size;
				swap(_memory, memory);
				delete []memory;
			}
			_width = width;
			_height = height;
			_stride = stride;
		}

		void raw_bitmap::blit(CGContextRef context, int x, int y, count_t width, count_t height) const
		{
			count_t stride = calculate_stride(_width + _extra_pixels);
			count_t size = stride * height;
			size_t component_bits = _bpp == bpp32 ? 8 : _bpp == bpp16 ? 5 : 8;
			int format = _bpp == bpp32 ? kCGImageAlphaNoneSkipFirst : kCGImageAlphaNone;

			CGDataProviderRef provider = ::CGDataProviderCreateWithData(0, _memory, size, 0);
			CGImageRef image = ::CGImageCreate(width, height, component_bits, _bpp, stride,
				CGBitmapContextGetColorSpace(context), format, provider, NULL, FALSE, kCGRenderingIntentDefault);
			::CGDataProviderRelease(provider);

			CGRect destination = { { CGFloat(x), CGFloat(y) }, { CGFloat(width), CGFloat(height) } };

			::CGContextDrawImage(context, destination, image);
			::CGImageRelease(image);
		}
	}
}
<|endoftext|>


<commit_before>/*
 *The MIT License (MIT)
 *
 * Copyright (c) <2016> <Stephan Gatzka>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE websocket_tests

#include <boost/test/unit_test.hpp>
#include <errno.h>

#include "buffered_socket.h"
#include "eventloop.h"
#include "http_connection.h"
#include "socket.h"

extern "C" {
	ssize_t socket_writev(socket_type sock, struct buffered_socket_io_vector *io_vec, unsigned int count)
	{
		(void)sock;
		(void)io_vec;
		(void)count;
		errno = EWOULDBLOCK;
		return -1;
	}

	ssize_t socket_send(socket_type sock, const void *buf, size_t len)
	{
		(void)sock;
		(void)buf;
		return len;
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)sock;
		(void)buf;
		(void)count;
		errno = EWOULDBLOCK;
		return -1;
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		return 0;
	}
}

static enum callback_return eventloop_fake_add(struct io_event *ev)
{
	(void)ev;
	return CONTINUE_LOOP;
}

static void eventloop_fake_remove(struct io_event *ev)
{
	(void)ev;
}

struct F {
	F()
	{
		loop.create = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = eventloop_fake_add;
		loop.remove = eventloop_fake_remove;
	}

	~F()
	{
	}

	struct eventloop loop;
};

BOOST_AUTO_TEST_CASE(test_websocket_alloc)
{
	F f;
	struct http_connection *connection = alloc_http_connection(NULL, &f.loop, 1);
	BOOST_CHECK(connection != NULL);

	free_connection(connection);
}
<commit_msg>Add test for closing an http_connection after migration of the underlying buffered_socket.<commit_after>/*
 *The MIT License (MIT)
 *
 * Copyright (c) <2016> <Stephan Gatzka>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#define BOOST_TEST_MODULE websocket_tests

#include <boost/test/unit_test.hpp>
#include <errno.h>

#include "buffered_socket.h"
#include "eventloop.h"
#include "http_connection.h"
#include "socket.h"

static bool close_called = false;

extern "C" {
	ssize_t socket_writev(socket_type sock, struct buffered_socket_io_vector *io_vec, unsigned int count)
	{
		(void)sock;
		(void)io_vec;
		(void)count;
		errno = EWOULDBLOCK;
		return -1;
	}

	ssize_t socket_send(socket_type sock, const void *buf, size_t len)
	{
		(void)sock;
		(void)buf;
		return len;
	}

	ssize_t socket_read(socket_type sock, void *buf, size_t count)
	{
		(void)sock;
		(void)buf;
		(void)count;
		errno = EWOULDBLOCK;
		return -1;
	}

	int socket_close(socket_type sock)
	{
		(void)sock;
		close_called = true;
		return 0;
	}
}

static enum callback_return eventloop_fake_add(struct io_event *ev)
{
	(void)ev;
	return CONTINUE_LOOP;
}

static void eventloop_fake_remove(struct io_event *ev)
{
	(void)ev;
}

struct F {
	F()
	{
		close_called = false;

		loop.create = NULL;
		loop.destroy = NULL;
		loop.run = NULL;
		loop.add = eventloop_fake_add;
		loop.remove = eventloop_fake_remove;
	}

	~F()
	{
	}

	struct eventloop loop;
};

BOOST_AUTO_TEST_CASE(test_websocket_alloc)
{
	F f;
	struct http_connection *connection = alloc_http_connection(NULL, &f.loop, 1);
	BOOST_CHECK_MESSAGE(connection != NULL, "Connection allocation failed!");

	free_connection(connection);
}

BOOST_AUTO_TEST_CASE(test_buffered_socket_migration)
{
	F f;
	struct http_connection *connection = alloc_http_connection(NULL, &f.loop, 1);
	BOOST_CHECK(connection != NULL);

	struct buffered_socket *bs = connection->bs;
	connection->bs = NULL;
	free_connection(connection);
	BOOST_CHECK_MESSAGE(!close_called, "Close was called after buffered_socket migration!");
	buffered_socket_close(bs);
	free(bs);
	BOOST_CHECK_MESSAGE(close_called, "Close was not called after buffered_socket_close!");
}
<|endoftext|>


<commit_before>#include "GecodeSpace.hh"
#include "bo/MachineBO.hh"
#include "bo/ProcessBO.hh"
#include "bo/RessourceBO.hh"
#include "tools/Log.hh"

#include <gecode/minimodel.hh>

using namespace Gecode;

GecodeSpace::GecodeSpace(const ContextBO *pContext_p) :
    machine_m(*this, pContext_p->getNbProcesses(),
              0, pContext_p->getNbMachines() - 1)
{
    int nbProc_l = pContext_p->getNbProcesses();
    int nbMach_l = pContext_p->getNbMachines();

    /*
     * Capacity
     */
    for (int res_l = 0; res_l < pContext_p->getNbRessources(); ++res_l) {
        RessourceBO *pRes_l = pContext_p->getRessource(res_l);

        // facultative
        if (pRes_l->isTransient())
            continue;

        IntVarArgs load_l(*this, nbMach_l, 0, Int::Limits::max);
        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l) {
            MachineBO *pMach_l = pContext_p->getMachine(mach_l);
            int capa_l = pMach_l->getCapa(res_l);
            rel(*this, load_l[mach_l], IRT_LQ, capa_l);
        }

        IntArgs sizes_l(nbProc_l);
        int totalSize_l = 0;
        for (int proc_l = 0; proc_l < nbProc_l; ++proc_l) {
            ProcessBO *pProc_l = pContext_p->getProcess(proc_l);
            int req_l = pProc_l->getRequirement(res_l);
            sizes_l[proc_l] = req_l;
            totalSize_l += req_l;
        }

        /*
         * This is _the_ constraint for non transient resources, but seems too
         * slow for our needs
         */
        //binpacking(*this, load_l, machine_m, sizes_l);

        /*
         * So naive implementation from Gecode example of bin packing
         */
        // All loads must add up to all item sizes
        linear(*this, load_l, IRT_EQ, totalSize_l);

        // Load must be equal to packed items
        BoolVarArgs tmpX_l(*this, nbProc_l * nbMach_l, 0, 1);
        Matrix<BoolVarArgs> x_l(tmpX_l, nbProc_l, nbMach_l);

        for (int proc_l = 0; proc_l < nbProc_l; ++proc_l)
            channel(*this, x_l.col(proc_l), machine_m[proc_l]);

        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l)
            linear(*this, sizes_l, x_l.row(mach_l), IRT_EQ, load_l[mach_l]);
    }

    /*
     * Transient
     */
    for (int res_l = 0; res_l < pContext_p->getNbRessources(); ++res_l) {
        RessourceBO *pRes_l = pContext_p->getRessource(res_l);
        if (! pRes_l->isTransient())
            continue;

        /*
         * Inspired by the naive imprementation of bin packing in Gecode example
         */

        // Load must be equal to packed items
        IntVarArgs load_l(*this, nbMach_l, 0, Int::Limits::max);
        BoolVarArgs tmpX_l(*this, nbProc_l * nbMach_l, 0, 1);
        Matrix<BoolVarArgs> x_l(tmpX_l, nbProc_l, nbMach_l);

        for (int proc_l = 0; proc_l < nbProc_l; ++proc_l)
            channel(*this, x_l.col(proc_l), machine_m[proc_l]);

        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l) {
            MachineBO *pMach_l = pContext_p->getMachine(mach_l);
            int capa_l = pMach_l->getCapa(res_l);
            IntArgs sizes_l;
            BoolVarArgs otherProc_l;
            int unremovableCapa_l = 0;
            std::vector<int> solInit_l = pContext_p->getSolInit();

            for (int proc_l = 0; proc_l < nbProc_l; ++proc_l) {
                ProcessBO *pProc_l = pContext_p->getProcess(proc_l);
                int req_l = pProc_l->getRequirement(res_l);
                if (solInit_l[proc_l] == mach_l)
                    unremovableCapa_l += req_l;
                else {
                    otherProc_l << x_l(proc_l, mach_l);
                    sizes_l << req_l;
                }
            }

            rel(*this, load_l[mach_l], IRT_LQ, capa_l - unremovableCapa_l);
            linear(*this, sizes_l, otherProc_l, IRT_EQ, load_l[mach_l]);
        }
    }

    // random branching to do a Monte Carlo generation
    branch(*this, machine_m, INT_VAR_SIZE_MIN, INT_VAL_RND);
}

GecodeSpace::GecodeSpace(bool share_p, GecodeSpace &that) :
    Space(share_p, that)
{
    machine_m.update(*this, share_p, that.machine_m);
}

Gecode::Space *GecodeSpace::copy(bool share_p)
{
    return new GecodeSpace(share_p, *this);
}

std::vector<int> GecodeSpace::solution()
{
    SpaceStatus status_l = status();
    assert(status_l == SS_SOLVED && machine_m.assigned());
    std::vector<int> res_l;

    for (IntVarArray::const_iterator it_l = machine_m.begin();
         it_l != machine_m.end(); ++it_l) {
        res_l.push_back(it_l->val());
    }

    return res_l;
}

void GecodeSpace::addDecision(const CPDecisionALG *pDecision_p)
{
    dom(*this, machine_m[pDecision_p->target_m], pDecision_p->min_m, pDecision_p->max_m);
}

GecodeSpace::DecisionPool GecodeSpace::generateDecisions()
{
    DecisionPool res_l;

    if (status() != SS_BRANCH)
        return res_l;

    // find the bigest var
    int target_l = 0;
    IntVar toBranch_l = machine_m[0];
    for (int i_l = 1; i_l < machine_m.size(); ++i_l)
        if (machine_m[i_l].size() > toBranch_l.size()) {
            toBranch_l = machine_m[i_l];
            target_l = i_l;
        }

    // for the moment, simple median branching
    res_l.push_back(new CPDecisionALG(target_l, toBranch_l.min(), toBranch_l.med()));
    res_l.push_back(new CPDecisionALG(target_l, toBranch_l.med() + 1, toBranch_l.max()));

    return res_l;
}
<commit_msg>conflict constraint + mutualisation de la matrice de bool<commit_after>#include "GecodeSpace.hh"
#include "bo/MachineBO.hh"
#include "bo/ProcessBO.hh"
#include "bo/RessourceBO.hh"
#include "bo/ServiceBO.hh"
#include "tools/Log.hh"

#include <gecode/minimodel.hh>

using namespace Gecode;

GecodeSpace::GecodeSpace(const ContextBO *pContext_p) :
    machine_m(*this, pContext_p->getNbProcesses(),
              0, pContext_p->getNbMachines() - 1)
{
    int nbProc_l = pContext_p->getNbProcesses();
    int nbMach_l = pContext_p->getNbMachines();

    // matrix proc x mach
    BoolVarArgs tmpX_l(*this, nbProc_l * nbMach_l, 0, 1);
    Matrix<BoolVarArgs> x_l(tmpX_l, nbProc_l, nbMach_l);

    for (int proc_l = 0; proc_l < nbProc_l; ++proc_l)
        channel(*this, x_l.col(proc_l), machine_m[proc_l]);

    /*
     * Capacity
     */
    for (int res_l = 0; res_l < pContext_p->getNbRessources(); ++res_l) {
        RessourceBO *pRes_l = pContext_p->getRessource(res_l);

        // facultative
        if (pRes_l->isTransient())
            continue;

        IntVarArgs load_l(*this, nbMach_l, 0, Int::Limits::max);
        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l) {
            MachineBO *pMach_l = pContext_p->getMachine(mach_l);
            int capa_l = pMach_l->getCapa(res_l);
            rel(*this, load_l[mach_l], IRT_LQ, capa_l);
        }

        IntArgs sizes_l(nbProc_l);
        int totalSize_l = 0;
        for (int proc_l = 0; proc_l < nbProc_l; ++proc_l) {
            ProcessBO *pProc_l = pContext_p->getProcess(proc_l);
            int req_l = pProc_l->getRequirement(res_l);
            sizes_l[proc_l] = req_l;
            totalSize_l += req_l;
        }

        /*
         * This is _the_ constraint for non transient resources, but seems too
         * slow for our needs
         */
        //binpacking(*this, load_l, machine_m, sizes_l);

        /*
         * So naive implementation from Gecode example of bin packing
         */
        // All loads must add up to all item sizes
        linear(*this, load_l, IRT_EQ, totalSize_l);

        // Load must be equal to packed items
        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l)
            linear(*this, sizes_l, x_l.row(mach_l), IRT_EQ, load_l[mach_l]);
    }

    /*
     * Conflict
     */
    int nbServ_l = pContext_p->getNbServices();
    for (int serv_l = 0; serv_l < nbServ_l; ++serv_l) {
        ServiceBO *pServ_l = pContext_p->getService(serv_l);
        typedef unordered_set<int> IntSet;
        IntSet s_l = pServ_l->getProcesses();
        IntVarArgs machine_l;

        for (IntSet::const_iterator it_l = s_l.begin(); it_l != s_l.end(); ++it_l)
            machine_l << machine_m[*it_l];

        distinct(*this, machine_l);
    }

    /*
     * Transient
     */
    for (int res_l = 0; res_l < pContext_p->getNbRessources(); ++res_l) {
        RessourceBO *pRes_l = pContext_p->getRessource(res_l);
        if (! pRes_l->isTransient())
            continue;

        /*
         * Inspired by the naive imprementation of bin packing in Gecode example
         */

        // Load must be equal to packed items
        IntVarArgs load_l(*this, nbMach_l, 0, Int::Limits::max);

        for (int mach_l = 0; mach_l < nbMach_l; ++mach_l) {
            MachineBO *pMach_l = pContext_p->getMachine(mach_l);
            int capa_l = pMach_l->getCapa(res_l);
            IntArgs sizes_l;
            BoolVarArgs otherProc_l;
            int unremovableCapa_l = 0;
            std::vector<int> solInit_l = pContext_p->getSolInit();

            for (int proc_l = 0; proc_l < nbProc_l; ++proc_l) {
                ProcessBO *pProc_l = pContext_p->getProcess(proc_l);
                int req_l = pProc_l->getRequirement(res_l);
                if (solInit_l[proc_l] == mach_l)
                    unremovableCapa_l += req_l;
                else {
                    otherProc_l << x_l(proc_l, mach_l);
                    sizes_l << req_l;
                }
            }

            rel(*this, load_l[mach_l], IRT_LQ, capa_l - unremovableCapa_l);
            linear(*this, sizes_l, otherProc_l, IRT_EQ, load_l[mach_l]);
        }
    }

    // random branching to do a Monte Carlo generation
    branch(*this, machine_m, INT_VAR_SIZE_MIN, INT_VAL_RND);
}

GecodeSpace::GecodeSpace(bool share_p, GecodeSpace &that) :
    Space(share_p, that)
{
    machine_m.update(*this, share_p, that.machine_m);
}

Gecode::Space *GecodeSpace::copy(bool share_p)
{
    return new GecodeSpace(share_p, *this);
}

std::vector<int> GecodeSpace::solution()
{
    SpaceStatus status_l = status();
    assert(status_l == SS_SOLVED && machine_m.assigned());
    std::vector<int> res_l;

    for (IntVarArray::const_iterator it_l = machine_m.begin();
         it_l != machine_m.end(); ++it_l) {
        res_l.push_back(it_l->val());
    }

    return res_l;
}

void GecodeSpace::addDecision(const CPDecisionALG *pDecision_p)
{
    dom(*this, machine_m[pDecision_p->target_m], pDecision_p->min_m, pDecision_p->max_m);
}

GecodeSpace::DecisionPool GecodeSpace::generateDecisions()
{
    DecisionPool res_l;

    if (status() != SS_BRANCH)
        return res_l;

    // find the bigest var
    int target_l = 0;
    IntVar toBranch_l = machine_m[0];
    for (int i_l = 1; i_l < machine_m.size(); ++i_l)
        if (machine_m[i_l].size() > toBranch_l.size()) {
            toBranch_l = machine_m[i_l];
            target_l = i_l;
        }

    // for the moment, simple median branching
    res_l.push_back(new CPDecisionALG(target_l, toBranch_l.min(), toBranch_l.med()));
    res_l.push_back(new CPDecisionALG(target_l, toBranch_l.med() + 1, toBranch_l.max()));

    return res_l;
}
<|endoftext|>