コード例 #1
0
ファイル: RagDoll.cpp プロジェクト: ghidra/urho_framework
void RagDoll::Activate()
{
	//turn the whole thing on
	//pawn_->GetNode()->RemoveComponent<RigidBody>();
    //pawn_->GetNode()->RemoveComponent<CollisionShape>();
	//pawn_->GetNode()->RemoveComponent(pawn_->GetBody());//remove the main components
    //pawn_->GetNode()->RemoveComponent(pawn_->GetShape());//remove the main components
    //if(node_->HasComponent<RigidBody>())
    //{
    
    //GetSubsystem<DebugHud>()->SetAppStats("state:", name_ );
    node_->RemoveComponent<RigidBody>();
    node_->RemoveComponent<CollisionShape>();
    
    //}

    AnimatedModel* model = node_->GetComponent<AnimatedModel>();
    Skeleton& skeleton = model->GetSkeleton();
    for (unsigned i = 0; i < skeleton.GetNumBones(); ++i)
    	skeleton.GetBone(i)->animated_ = false;

   	for (unsigned i = 0; i < boneNode_.Size(); ++i)
   	{
        //URHO3D_LOGINFO(String(i));
   		RigidBody* rb = boneNode_[i]->GetComponent<RigidBody>();
   		rb->SetTrigger(false);
        rb->SetMass(1.0f);
   	}
}
コード例 #2
0
const PODVector<unsigned char>& AnimationController::GetNetAnimationsAttr() const
{
    attrBuffer_.Clear();

    AnimatedModel* model = GetComponent<AnimatedModel>();

    unsigned validAnimations = 0;
    for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i)
    {
        if (GetAnimationState(i->hash_))
            ++validAnimations;
    }

    attrBuffer_.WriteVLE(validAnimations);
    for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i)
    {
        AnimationState* state = GetAnimationState(i->hash_);
        if (!state)
            continue;

        unsigned char ctrl = 0;
        Bone* startBone = state->GetStartBone();
        if (state->IsLooped())
            ctrl |= CTRL_LOOPED;
        if (startBone && model && startBone != model->GetSkeleton().GetRootBone())
            ctrl |= CTRL_STARTBONE;
        if (i->autoFadeTime_ > 0.0f)
            ctrl |= CTRL_AUTOFADE;
        if (i->removeOnCompletion_)
            ctrl |= CTRL_REMOVEONCOMPLETION;
        if (i->setTimeTtl_ > 0.0f)
            ctrl |= CTRL_SETTIME;
        if (i->setWeightTtl_ > 0.0f)
            ctrl |= CTRL_SETWEIGHT;

        attrBuffer_.WriteString(i->name_);
        attrBuffer_.WriteUByte(ctrl);
        attrBuffer_.WriteUByte(state->GetLayer());
        attrBuffer_.WriteShort((short)Clamp(i->speed_ * 2048.0f, -32767.0f, 32767.0f));
        attrBuffer_.WriteUByte((unsigned char)(i->targetWeight_ * 255.0f));
        attrBuffer_.WriteUByte((unsigned char)Clamp(i->fadeTime_ * 64.0f, 0.0f, 255.0f));
        if (ctrl & CTRL_STARTBONE)
            attrBuffer_.WriteStringHash(startBone->nameHash_);
        if (ctrl & CTRL_AUTOFADE)
            attrBuffer_.WriteUByte((unsigned char)Clamp(i->autoFadeTime_ * 64.0f, 0.0f, 255.0f));
        if (ctrl & CTRL_SETTIME)
        {
            attrBuffer_.WriteUByte(i->setTimeRev_);
            attrBuffer_.WriteUShort(i->setTime_);
        }
        if (ctrl & CTRL_SETWEIGHT)
        {
            attrBuffer_.WriteUByte(i->setWeightRev_);
            attrBuffer_.WriteUByte(i->setWeight_);
        }
    }

    return attrBuffer_.GetBuffer();
}
コード例 #3
0
bool AnimationController::SetStartBone(const String& name, const String& startBoneName)
{
    AnimationState* state = FindAnimationState(name);
    if (!state)
        return false;
    
    AnimatedModel* model = GetComponent<AnimatedModel>();
    Bone* bone = model->GetSkeleton().GetBone(startBoneName);
    state->SetStartBone(bone);
    MarkNetworkUpdate();
    return true;
}
コード例 #4
0
ファイル: CharacterDemo.cpp プロジェクト: evolarium/Urho3D
void CharacterDemo::CreateCharacter()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();

    Node* objectNode = scene_->CreateChild("Jack");
    objectNode->SetPosition(Vector3(0.0f, 1.0f, 0.0f));

    // spin node
    Node* adjustNode = objectNode->CreateChild("AdjNode");
    adjustNode->SetRotation( Quaternion(180, Vector3(0,1,0) ) );
    
    // Create the rendering component + animation controller
    AnimatedModel* object = adjustNode->CreateComponent<AnimatedModel>();
    object->SetModel(cache->GetResource<Model>("Models/Mutant/Mutant.mdl"));
    object->SetMaterial(cache->GetResource<Material>("Models/Mutant/Materials/mutant_M.xml"));
    object->SetCastShadows(true);
    adjustNode->CreateComponent<AnimationController>();

    // Set the head bone for manual control
    object->GetSkeleton().GetBone("Mutant:Head")->animated_ = false;

    // Create rigidbody, and set non-zero mass so that the body becomes dynamic
    RigidBody* body = objectNode->CreateComponent<RigidBody>();
    body->SetCollisionLayer(1);
    body->SetMass(1.0f);

    // Set zero angular factor so that physics doesn't turn the character on its own.
    // Instead we will control the character yaw manually
    body->SetAngularFactor(Vector3::ZERO);

    // Set the rigidbody to signal collision also when in rest, so that we get ground collisions properly
    body->SetCollisionEventMode(COLLISION_ALWAYS);

    // Set a capsule shape for collision
    CollisionShape* shape = objectNode->CreateComponent<CollisionShape>();
    shape->SetCapsule(0.7f, 1.8f, Vector3(0.0f, 0.9f, 0.0f));

    // Create the character logic component, which takes care of steering the rigidbody
    // Remember it so that we can set the controls. Use a WeakPtr because the scene hierarchy already owns it
    // and keeps it alive as long as it's not removed from the hierarchy
    character_ = objectNode->CreateComponent<Character>();
}
コード例 #5
0
ファイル: DecalSet.cpp プロジェクト: TheComet93/Urho3D
bool DecalSet::GetBones(Drawable* target, unsigned batchIndex, const float* blendWeights, const unsigned char* blendIndices,
    unsigned char* newBlendIndices)
{
    AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target);
    if (!animatedModel)
        return false;

    // Check whether target is using global or per-geometry skinning
    const Vector<PODVector<Matrix3x4> >& geometrySkinMatrices = animatedModel->GetGeometrySkinMatrices();
    const Vector<PODVector<unsigned> >& geometryBoneMappings = animatedModel->GetGeometryBoneMappings();

    for (unsigned i = 0; i < 4; ++i)
    {
        if (blendWeights[i] > 0.0f)
        {
            Bone* bone = 0;
            if (geometrySkinMatrices.Empty())
                bone = animatedModel->GetSkeleton().GetBone(blendIndices[i]);
            else if (blendIndices[i] < geometryBoneMappings[batchIndex].Size())
                bone = animatedModel->GetSkeleton().GetBone(geometryBoneMappings[batchIndex][blendIndices[i]]);

            if (!bone)
            {
                URHO3D_LOGWARNING("Out of range bone index for skinned decal");
                return false;
            }

            bool found = false;
            unsigned index;

            for (index = 0; index < bones_.Size(); ++index)
            {
                if (bones_[index].node_ == bone->node_)
                {
                    // Check also that the offset matrix matches, in case we for example have a separate attachment AnimatedModel
                    // with a different bind pose
                    if (bones_[index].offsetMatrix_.Equals(bone->offsetMatrix_))
                    {
                        found = true;
                        break;
                    }
                }
            }

            if (!found)
            {
                if (bones_.Size() >= Graphics::GetMaxBones())
                {
                    URHO3D_LOGWARNING("Maximum skinned decal bone count reached");
                    return false;
                }
                else
                {
                    // Copy the bone from the model to the decal
                    index = bones_.Size();
                    bones_.Resize(bones_.Size() + 1);
                    bones_[index] = *bone;
                    skinMatrices_.Resize(skinMatrices_.Size() + 1);
                    skinningDirty_ = true;

                    // Start listening to bone transform changes to update skinning
                    bone->node_->AddListener(this);
                }
            }

            newBlendIndices[i] = (unsigned char)index;
        }
        else
            newBlendIndices[i] = 0;
    }

    // Update amount of shader data in the decal batch
    UpdateBatch();
    return true;
}
コード例 #6
0
ファイル: DecalSet.cpp プロジェクト: TheComet93/Urho3D
bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size,
    float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff,
    unsigned subGeometry)
{
    URHO3D_PROFILE(AddDecal);

    // Do not add decals in headless mode
    if (!node_ || !GetSubsystem<Graphics>())
        return false;

    if (!target || !target->GetNode())
    {
        URHO3D_LOGERROR("Null target drawable for decal");
        return false;
    }

    // Check for animated target and switch into skinned/static mode if necessary
    AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target);
    if ((animatedModel && !skinned_) || (!animatedModel && skinned_))
    {
        RemoveAllDecals();
        skinned_ = animatedModel != 0;
        bufferDirty_ = true;
    }

    // Center the decal frustum on the world position
    Vector3 adjustedWorldPosition = worldPosition - 0.5f * depth * (worldRotation * Vector3::FORWARD);
    /// \todo target transform is not right if adding a decal to StaticModelGroup
    Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();

    // For an animated model, adjust the decal position back to the bind pose
    // To do this, need to find the bone the decal is colliding with
    if (animatedModel)
    {
        Skeleton& skeleton = animatedModel->GetSkeleton();
        unsigned numBones = skeleton.GetNumBones();
        Bone* bestBone = 0;
        float bestSize = 0.0f;

        for (unsigned i = 0; i < numBones; ++i)
        {
            Bone* bone = skeleton.GetBone(i);
            if (!bone->node_ || !bone->collisionMask_)
                continue;

            // Represent the decal as a sphere, try to find the biggest colliding bone
            Sphere decalSphere
                (bone->node_->GetWorldTransform().Inverse() * worldPosition, 0.5f * size / bone->node_->GetWorldScale().Length());

            if (bone->collisionMask_ & BONECOLLISION_BOX)
            {
                float size = bone->boundingBox_.HalfSize().Length();
                if (bone->boundingBox_.IsInside(decalSphere) && size > bestSize)
                {
                    bestBone = bone;
                    bestSize = size;
                }
            }
            else if (bone->collisionMask_ & BONECOLLISION_SPHERE)
            {
                Sphere boneSphere(Vector3::ZERO, bone->radius_);
                float size = bone->radius_;
                if (boneSphere.IsInside(decalSphere) && size > bestSize)
                {
                    bestBone = bone;
                    bestSize = size;
                }
            }
        }

        if (bestBone)
            targetTransform = (bestBone->node_->GetWorldTransform() * bestBone->offsetMatrix_).Inverse();
    }

    // Build the decal frustum
    Frustum decalFrustum;
    Matrix3x4 frustumTransform = targetTransform * Matrix3x4(adjustedWorldPosition, worldRotation, 1.0f);
    decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform);

    Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized();

    decals_.Resize(decals_.Size() + 1);
    Decal& newDecal = decals_.Back();
    newDecal.timeToLive_ = timeToLive;

    Vector<PODVector<DecalVertex> > faces;
    PODVector<DecalVertex> tempFace;

    unsigned numBatches = target->GetBatches().Size();

    // Use either a specified subgeometry in the target, or all
    if (subGeometry < numBatches)
        GetFaces(faces, target, subGeometry, decalFrustum, decalNormal, normalCutoff);
    else
    {
        for (unsigned i = 0; i < numBatches; ++i)
            GetFaces(faces, target, i, decalFrustum, decalNormal, normalCutoff);
    }

    // Clip the acquired faces against all frustum planes
    for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i)
    {
        for (unsigned j = 0; j < faces.Size(); ++j)
        {
            PODVector<DecalVertex>& face = faces[j];
            if (face.Empty())
                continue;

            ClipPolygon(tempFace, face, decalFrustum.planes_[i], skinned_);
            face = tempFace;
        }
    }

    // Now triangulate the resulting faces into decal vertices
    for (unsigned i = 0; i < faces.Size(); ++i)
    {
        PODVector<DecalVertex>& face = faces[i];
        if (face.Size() < 3)
            continue;

        for (unsigned j = 2; j < face.Size(); ++j)
        {
            newDecal.AddVertex(face[0]);
            newDecal.AddVertex(face[j - 1]);
            newDecal.AddVertex(face[j]);
        }
    }

    // Check if resulted in no triangles
    if (newDecal.vertices_.Empty())
    {
        decals_.Pop();
        return true;
    }

    if (newDecal.vertices_.Size() > maxVertices_)
    {
        URHO3D_LOGWARNING("Can not add decal, vertex count " + String(newDecal.vertices_.Size()) + " exceeds maximum " +
                   String(maxVertices_));
        decals_.Pop();
        return false;
    }
    if (newDecal.indices_.Size() > maxIndices_)
    {
        URHO3D_LOGWARNING("Can not add decal, index count " + String(newDecal.indices_.Size()) + " exceeds maximum " +
                   String(maxIndices_));
        decals_.Pop();
        return false;
    }

    // Calculate UVs
    Matrix4 projection(Matrix4::ZERO);
    projection.m11_ = (1.0f / (size * 0.5f));
    projection.m00_ = projection.m11_ / aspectRatio;
    projection.m22_ = 1.0f / depth;
    projection.m33_ = 1.0f;

    CalculateUVs(newDecal, frustumTransform.Inverse(), projection, topLeftUV, bottomRightUV);

    // Transform vertices to this node's local space and generate tangents
    Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform();
    TransformVertices(newDecal, skinned_ ? Matrix3x4::IDENTITY : decalTransform);
    GenerateTangents(&newDecal.vertices_[0], sizeof(DecalVertex), &newDecal.indices_[0], sizeof(unsigned short), 0,
        newDecal.indices_.Size(), offsetof(DecalVertex, normal_), offsetof(DecalVertex, texCoord_), offsetof(DecalVertex,
        tangent_));

    newDecal.CalculateBoundingBox();
    numVertices_ += newDecal.vertices_.Size();
    numIndices_ += newDecal.indices_.Size();

    // Remove oldest decals if total vertices exceeded
    while (decals_.Size() && (numVertices_ > maxVertices_ || numIndices_ > maxIndices_))
        RemoveDecals(1);

    URHO3D_LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices");

    // If new decal is time limited, subscribe to scene post-update
    if (newDecal.timeToLive_ > 0.0f && !subscribed_)
        UpdateEventSubscription(false);

    MarkDecalsDirty();
    return true;
}
コード例 #7
0
ファイル: CreateRagdoll.cpp プロジェクト: ClockTeam/Clockwork
void CreateRagdoll::HandleNodeCollision(StringHash eventType, VariantMap& eventData)
{
    using namespace NodeCollision;

    // Get the other colliding body, make sure it is moving (has nonzero mass)
    RigidBody* otherBody = static_cast<RigidBody*>(eventData[P_OTHERBODY].GetPtr());

    if (otherBody->GetMass() > 0.0f)
    {
        // We do not need the physics components in the AnimatedModel's root scene node anymore
        node_->RemoveComponent<RigidBody>();
        node_->RemoveComponent<CollisionShape>();

        // Create RigidBody & CollisionShape components to bones
        CreateRagdollBone("Bip01_Pelvis", SHAPE_BOX, Vector3(0.3f, 0.2f, 0.25f), Vector3(0.0f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 0.0f));
        CreateRagdollBone("Bip01_Spine1", SHAPE_BOX, Vector3(0.35f, 0.2f, 0.3f), Vector3(0.15f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 0.0f));
        CreateRagdollBone("Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_Head", SHAPE_BOX, Vector3(0.2f, 0.2f, 0.2f), Vector3(0.1f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 0.0f));
        CreateRagdollBone("Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));
        CreateRagdollBone("Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
            Quaternion(0.0f, 0.0f, 90.0f));

        // Create Constraints between bones
        CreateRagdollConstraint("Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
            Vector2(45.0f, 45.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
            Vector2(45.0f, 45.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
            Vector2(90.0f, 0.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
            Vector2(90.0f, 0.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3::FORWARD, Vector3::FORWARD,
            Vector2(45.0f, 0.0f), Vector2(-10.0f, 0.0f));
        CreateRagdollConstraint("Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::LEFT, Vector3::LEFT,
            Vector2(0.0f, 30.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
            Vector2(45.0f, 45.0f), Vector2::ZERO, false);
        CreateRagdollConstraint("Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
            Vector2(45.0f, 45.0f), Vector2::ZERO, false);
        CreateRagdollConstraint("Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
            Vector2(90.0f, 0.0f), Vector2::ZERO);
        CreateRagdollConstraint("Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
            Vector2(90.0f, 0.0f), Vector2::ZERO);

        // Disable keyframe animation from all bones so that they will not interfere with the ragdoll
        AnimatedModel* model = GetComponent<AnimatedModel>();
        Skeleton& skeleton = model->GetSkeleton();
        for (unsigned i = 0; i < skeleton.GetNumBones(); ++i)
            skeleton.GetBone(i)->animated_ = false;

        // Finally remove self from the scene node. Note that this must be the last operation performed in the function
        Remove();
    }
}
コード例 #8
0
void AnimationController::SetNetAnimationsAttr(const PODVector<unsigned char>& value)
{
    MemoryBuffer buf(value);

    AnimatedModel* model = GetComponent<AnimatedModel>();

    // Check which animations we need to remove
    HashSet<StringHash> processedAnimations;

    unsigned numAnimations = buf.ReadVLE();
    while (numAnimations--)
    {
        String animName = buf.ReadString();
        StringHash animHash(animName);
        processedAnimations.Insert(animHash);

        // Check if the animation state exists. If not, add new
        AnimationState* state = GetAnimationState(animHash);
        if (!state)
        {
            Animation* newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(animName);
            state = AddAnimationState(newAnimation);
            if (!state)
            {
                LOGERROR("Animation update applying aborted due to unknown animation");
                return;
            }
        }
        // Check if the internal control structure exists. If not, add new
        unsigned index;
        for (index = 0; index < animations_.Size(); ++index)
        {
            if (animations_[index].hash_ == animHash)
                break;
        }
        if (index == animations_.Size())
        {
            AnimationControl newControl;
            newControl.name_ = animName;
            newControl.hash_ = animHash;
            animations_.Push(newControl);
        }

        unsigned char ctrl = buf.ReadUByte();
        state->SetLayer(buf.ReadUByte());
        state->SetLooped((ctrl & CTRL_LOOPED) != 0);
        animations_[index].speed_ = (float)buf.ReadShort() / 2048.0f; // 11 bits of decimal precision, max. 16x playback speed
        animations_[index].targetWeight_ = (float)buf.ReadUByte() / 255.0f; // 8 bits of decimal precision
        animations_[index].fadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade
        if (ctrl & CTRL_STARTBONE)
        {
            StringHash boneHash = buf.ReadStringHash();
            if (model)
                state->SetStartBone(model->GetSkeleton().GetBone(boneHash));
        }
        else
            state->SetStartBone(0);
        if (ctrl & CTRL_AUTOFADE)
            animations_[index].autoFadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade
        else
            animations_[index].autoFadeTime_ = 0.0f;
        
        animations_[index].removeOnCompletion_ = (ctrl & CTRL_REMOVEONCOMPLETION) != 0;
        
        if (ctrl & CTRL_SETTIME)
        {
            unsigned char setTimeRev = buf.ReadUByte();
            unsigned short setTime = buf.ReadUShort();
            // Apply set time command only if revision differs
            if (setTimeRev != animations_[index].setTimeRev_)
            {
                state->SetTime(((float)setTime / 65535.0f) * state->GetLength());
                animations_[index].setTimeRev_ = setTimeRev;
            }
        }
        if (ctrl & CTRL_SETWEIGHT)
        {
            unsigned char setWeightRev = buf.ReadUByte();
            unsigned char setWeight = buf.ReadUByte();
            // Apply set weight command only if revision differs
            if (setWeightRev != animations_[index].setWeightRev_)
            {
                state->SetWeight((float)setWeight / 255.0f);
                animations_[index].setWeightRev_ = setWeightRev;
            }
        }
    }

    // Set any extra animations to fade out
    for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i)
    {
        if (!processedAnimations.Contains(i->hash_))
        {
            i->targetWeight_ = 0.0f;
            i->fadeTime_ = EXTRA_ANIM_FADEOUT_TIME;
        }
    }
}