Ticket #2324: actorFormat_variationnames.diff

File actorFormat_variationnames.diff, 19.2 KB (added by sanderd17, 8 years ago)
  • binaries/data/mods/public/art/actors/actor.rnc

     
    3838            element animations {
    3939                element animation {
    4040                    attribute name { text } &
     41                    attribute frequency { xsd:nonNegativeInteger }? &
    4142                    attribute file { text }? &
    4243                    attribute speed { xsd:nonNegativeInteger } &
    4344                    attribute event { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? &
  • binaries/data/mods/public/art/actors/actor.rng

     
    9494                      <interleave>
    9595                        <attribute name="name"/>
    9696                        <optional>
     97                          <attribute name="frequency">
     98                            <data type="nonNegativeInteger"/>
     99                          </attribute>
     100                        </optional>
     101                        <optional>
    97102                          <attribute name="file"/>
    98103                        </optional>
    99104                        <attribute name="speed">
  • binaries/data/mods/public/art/actors/units/athenians/cavalry_javelinist_b.xml

     
    55    <variant frequency="1" name="Base">
    66      <animations>
    77        <animation file="quadraped/horse_idle_a.psa" name="Idle" speed="50"/>
    8         <animation file="quadraped/horse_walk.psa" name="Walk" speed="120"/>
    98        <animation file="quadraped/horse_gallop.psa" name="Run" speed="50"/>
    109        <animation file="quadraped/horse_walk.psa" name="carry_meat" speed="120"/>
    1110        <animation event=".5" file="quadraped/horse_attack_a.psa" name="attack_ranged" speed="20"/>
     
    1514      </animations>
    1615      <mesh>skeletal/horse.pmd</mesh>
    1716      <props>
    18         <prop actor="units/hellenes/cavalry_javelinist_b_r.xml" attachpoint="rider"/>
     17        <prop actor="units/athenians/cavalry_javelinist_b_r.xml" attachpoint="rider"/>
    1918      </props>
    2019    </variant>
    2120  </group>
     
    4342        <prop actor="particle/dust_cav.xml" attachpoint="root"/>
    4443      </props>
    4544    </variant>
     45    <variant name="Walk">
     46      <animations>
     47        <animation file="quadraped/horse_walk.psa" frequency="1" name="walk_slow" speed="120"/>
     48        <animation file="quadraped/horse_gallop.psa" frequency="1" name="walk_fast" speed="50"/>
     49      </animations>
     50    </variant>
    4651  </group>
    4752  <material>objectcolor.xml</material>
    4853</actor>
  • binaries/data/mods/public/art/actors/units/athenians/cavalry_javelinist_b_r.xml

     
    55    <variant frequency="100" name="Base">
    66      <animations>
    77        <animation file="biped/cavalryidle.psa" name="Idle" speed="50"/>
    8         <animation file="biped/cavalryidle.psa" name="Walk" speed="50"/>
    98        <animation file="biped/rider_gallop.psa" name="Run" speed="40"/>
    109        <animation event="0.59" file="biped/rider_javelin_atk_a.psa" load="0" name="attack_ranged" speed="50"/>
    1110        <animation event="0.5" file="cavalry/sword/attack/rider_sword_shield_atk_a.psa" name="attack_slaughter" speed="400"/>
     
    2625  </group>
    2726  <group>
    2827    <variant frequency="100" name="Idle"/>
     28    <variant name="Walk">
     29      <animations>
     30        <animation file="biped/cavalryidle.psa" name="walk_slow" frequency="1" speed="50"/>
     31        <animation file="cavalry/sword/attack/rider_sword_shield_atk_a.psa" name="walk_fast" frequency="1" speed="400"/>
     32      </animations>
     33    </variant>
    2934    <variant name="attack_slaughter">
    3035      <props>
    3136        <prop actor="props/units/weapons/spartan_sword.xml" attachpoint="r_hand"/>
  • binaries/data/mods/public/art/variants/variant.rnc

     
    3434    element animations {
    3535        element animation {
    3636            attribute name { text } &
     37            attribute frequency { xsd:nonNegativeInteger }? &
    3738            attribute file { text }? &
    3839            attribute speed { xsd:nonNegativeInteger } &
    3940            attribute event { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? &
  • binaries/data/mods/public/art/variants/variant.rng

     
    8383          <interleave>
    8484            <attribute name="name"/>
    8585            <optional>
     86                <attribute name="frequency">
     87                    <data type="nonNegativeInteger"/>
     88                </attribute>
     89            </optional>
     90            <optional>
    8691              <attribute name="file"/>
    8792            </optional>
    8893            <attribute name="speed">
  • source/graphics/Model.cpp

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    255255/////////////////////////////////////////////////////////////////////////////////////////////////////////////
    256256// BuildAnimation: load raw animation frame animation from given file, and build a
    257257// animation specific to this model
    258 CSkeletonAnim* CModel::BuildAnimation(const VfsPath& pathname, const CStr& name, float speed, float actionpos, float actionpos2, float soundpos)
     258CSkeletonAnim* CModel::BuildAnimation(const VfsPath& pathname, const CStr& name, int frequency, float speed, float actionpos, float actionpos2, float soundpos)
    259259{
    260260    CSkeletonAnimDef* def = m_SkeletonAnimManager.GetAnimation(pathname);
    261261    if (!def)
     
    263263
    264264    CSkeletonAnim* anim = new CSkeletonAnim();
    265265    anim->m_Name = name;
     266    anim->m_Frequency = frequency;
    266267    anim->m_AnimDef = def;
    267268    anim->m_Speed = speed;
    268269
  • source/graphics/Model.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    201201     * animation specific to this model.
    202202     * @param pathname animation file to load
    203203     * @param name animation name (e.g. "idle")
     204     * @param frequency influences the random choices
    204205     * @param speed animation speed as a factor of the default animation speed
    205206     * @param actionpos offset of 'action' event, in range [0, 1]
    206207     * @param actionpos2 offset of 'action2' event, in range [0, 1]
     
    207208     * @param sound offset of 'sound' event, in range [0, 1]
    208209     * @return new animation, or NULL on error
    209210     */
    210     CSkeletonAnim* BuildAnimation(const VfsPath& pathname, const CStr& name, float speed, float actionpos, float actionpos2, float soundpos);
     211    CSkeletonAnim* BuildAnimation(const VfsPath& pathname, const CStr& name, int frequency, float speed, float actionpos, float actionpos2, float soundpos);
    211212
    212213    /**
    213214     * Add a prop to the model on the given point.
  • source/graphics/ObjectBase.cpp

     
    163163                {
    164164                    if (ae.Name == at_name)
    165165                        anim.m_AnimName = ae.Value;
     166                    else if (ae.Name == at_frequency)
     167                        anim.m_Frequency = ae.Value.ToInt();
    166168                    else if (ae.Name == at_file)
    167169                        anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8();
    168170                    else if (ae.Name == at_speed)
  • source/graphics/ObjectBase.h

     
    4242    struct Anim
    4343    {
    4444        // constructor
    45         Anim() : m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f), m_SoundPos(-1.f) {}
     45        Anim() : m_Frequency(0), m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f), m_SoundPos(-1.f) {}
    4646        // name of the animation - "Idle", "Run", etc
    4747        CStr m_AnimName;
     48        int m_Frequency;
    4849        // filename of the animation - manidle.psa, manrun.psa, etc
    4950        VfsPath m_FileName;
    5051        // animation speed, as specified in XML actor file
  • source/graphics/ObjectEntry.cpp

     
    161161
    162162        if (!it->second.m_FileName.empty())
    163163        {
    164             CSkeletonAnim* anim = model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2, it->second.m_SoundPos);
     164            CSkeletonAnim* anim = model->BuildAnimation(it->second.m_FileName, name, it->second.m_Frequency, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2, it->second.m_SoundPos);
    165165            if (anim)
    166166                m_Animations.insert(std::make_pair(name, anim));
    167167        }
     
    248248
    249249CSkeletonAnim* CObjectEntry::GetRandomAnimation(const CStr& animationName) const
    250250{
    251     SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound(animationName);
    252     SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound(animationName);
    253     size_t count = std::distance(lower, upper);
    254     if (count == 0)
    255         return NULL;
     251    std::vector<CSkeletonAnim*> anims = GetAnimations(animationName);
    256252
    257     size_t id = rand(0, count);
    258     std::advance(lower, id);
    259     return lower->second;
     253    int totalFreq = 0;
     254    for (CSkeletonAnim* anim : anims)
     255        totalFreq += anim->m_Frequency;
     256
     257    if (totalFreq == 0)
     258        return anims[rand(0, anims.size())];
     259
     260    int r = rand(0, totalFreq);
     261    for (CSkeletonAnim* anim : anims)
     262    {
     263        r -= anim->m_Frequency;
     264        if (r < 0)
     265            return anim;
     266    }
     267    LOGERROR("No animation found");
     268    return NULL;
    260269}
    261270
    262271std::vector<CSkeletonAnim*> CObjectEntry::GetAnimations(const CStr& animationName) const
     
    265274
    266275    SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound(animationName);
    267276    SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound(animationName);
     277
    268278    for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it)
    269279        anims.push_back(it->second);
     280
     281    if (anims.size() == 0)
     282        for (const std::pair<CStr, CSkeletonAnim*>& anim : m_Animations)
     283            if (anim.second->m_Frequency > 0)
     284                anims.push_back(anim.second);
     285
     286    if (anims.size() == 0)
     287    {
     288        SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound("idle");
     289        SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound("idle");
     290        for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it)
     291            anims.push_back(it->second);
     292    }
     293
     294    ENSURE(anims.size() > 0);
    270295    return anims;
    271296}
  • source/graphics/ObjectEntry.h

     
    1 /* Copyright (C) 2013 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    6363
    6464    std::wstring m_ProjectileModelName;
    6565
    66     // Returns a randomly-chosen animation matching the given name.
    67     // If none is found, returns NULL.
     66    /**
     67     * Returns a randomly-chosen animation matching the given name.
     68     * The chosen animation is picked randomly from the GetAnimations list
     69     * with the frequencies as weights (if there are any defined).
     70     * This method should always return an animation
     71     */
    6872    CSkeletonAnim* GetRandomAnimation(const CStr& animationName) const;
    6973
    70     // Returns all the animations matching the given name.
     74    /**
     75     * Returns all the animations matching the given name.
     76     * - Prefers the animations names like the animationName
     77     * - Second choice are animations with a frequency
     78     * - Last choice are the Idle animations (which are always added)
     79     */
    7180    std::vector<CSkeletonAnim*> GetAnimations(const CStr& animationName) const;
    7281
    7382    // corresponding model
  • source/graphics/SkeletonAnim.h

     
    1 /* Copyright (C) 2010 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    3434public:
    3535    // the name of the action which uses this animation (e.g. "idle")
    3636    CStr m_Name;
     37    // frequency of the animation
     38    int m_Frequency;
    3739    // the raw animation frame data; may be NULL if this is a static 'animation'
    3840    CSkeletonAnimDef* m_AnimDef;
    3941    // speed at which this animation runs, as a factor of the AnimDef default speed
  • source/graphics/UnitAnimation.cpp

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    4141}
    4242
    4343CUnitAnimation::CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object)
    44     : m_Entity(ent), m_State("idle"), m_Looping(true),
     44    : m_Entity(ent), m_State("idle"), m_AnimationName("idle"), m_Looping(true),
    4545      m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f)
    4646{
    4747    ReloadUnit(model, object);
     
    5656{
    5757    SModelAnimState state;
    5858
    59     state.anims = object->GetAnimations(m_State);
    60 
    61     if (state.anims.empty())
    62         state.anims = object->GetAnimations("idle");
    63     ENSURE(!state.anims.empty()); // there must always be an idle animation
    64 
    6559    state.model = model;
    66     state.animIdx = rand(0, state.anims.size());
     60    state.object = object;
     61    state.anim = object->GetRandomAnimation(m_State);
    6762    state.time = 0.f;
    6863    state.pastLoadPos = false;
    6964    state.pastActionPos = false;
    7065    state.pastSoundPos = false;
    7166
     67    ENSURE(state.anim != NULL); // there must always be an idle animation
     68
    7269    m_AnimStates.push_back(state);
    7370
    74     model->SetAnimation(state.anims[state.animIdx], !m_Looping);
     71    model->SetAnimation(state.anim, !m_Looping);
    7572
    7673    // Detect if this unit has any non-static animations
    77     for (size_t i = 0; i < state.anims.size(); i++)
    78         if (state.anims[i]->m_AnimDef != NULL)
     74    for (CSkeletonAnim* anim : object->GetAnimations(m_State))
     75        if (anim->m_AnimDef != NULL)
    7976            m_AnimStatesAreStatic = false;
    8077
    8178    // Recursively add all props
     
    111108    if (name != m_State)
    112109    {
    113110        m_State = name;
     111        m_AnimationName = name;
    114112
    115113        ReloadUnit(m_Model, m_Object);
    116114    }
     
    129127    // Update all the synced prop models to each coincide with actionTime
    130128    for (std::vector<SModelAnimState>::iterator it = m_AnimStates.begin(); it != m_AnimStates.end(); ++it)
    131129    {
    132         CSkeletonAnimDef* animDef = it->anims[it->animIdx]->m_AnimDef;
     130        CSkeletonAnimDef* animDef = it->anim->m_AnimDef;
    133131        if (animDef == NULL)
    134132            continue; // ignore static animations
    135133
    136134        float duration = animDef->GetDuration();
    137135
    138         float actionPos = it->anims[it->animIdx]->m_ActionPos;
     136        float actionPos = it->anim->m_ActionPos;
    139137        bool hasActionPos = (actionPos != -1.f);
    140138
    141139        if (!hasActionPos)
     
    162160    // Advance all of the prop models independently
    163161    for (std::vector<SModelAnimState>::iterator it = m_AnimStates.begin(); it != m_AnimStates.end(); ++it)
    164162    {
    165         CSkeletonAnimDef* animDef = it->anims[it->animIdx]->m_AnimDef;
     163        CSkeletonAnimDef* animDef = it->anim->m_AnimDef;
    166164        if (animDef == NULL)
    167165            continue; // ignore static animations
    168166
    169167        float duration = animDef->GetDuration();
    170168
    171         float actionPos = it->anims[it->animIdx]->m_ActionPos;
    172         float loadPos = it->anims[it->animIdx]->m_ActionPos2;
    173         float soundPos = it->anims[it->animIdx]->m_SoundPos;
     169        float actionPos = it->anim->m_ActionPos;
     170        float loadPos = it->anim->m_ActionPos2;
     171        float soundPos = it->anim->m_SoundPos;
    174172        bool hasActionPos = (actionPos != -1.f);
    175173        bool hasLoadPos = (loadPos != -1.f);
    176174        bool hasSoundPos = (soundPos != -1.f);
     
    180178        if (m_SyncRepeatTime && hasActionPos)
    181179            speed = duration / m_SyncRepeatTime;
    182180        else
    183             speed = m_Speed * it->anims[it->animIdx]->m_Speed;
     181            speed = m_Speed * it->anim->m_Speed;
    184182
    185183        // Convert from real time to scaled animation time
    186184        float advance = time * speed;
     
    232230            // Wrap the timer around
    233231            it->time = fmod(it->time + advance, duration);
    234232
    235             // If there's a choice of multiple animations, pick a new random one
    236             if (it->anims.size() > 1)
     233            // Pick a new random animation
     234            CSkeletonAnim* anim;
     235            if (it->model == m_Model)
    237236            {
    238                 size_t newAnimIdx = rand(0, it->anims.size());
    239                 if (newAnimIdx != it->animIdx)
    240                 {
    241                     it->animIdx = newAnimIdx;
    242                     it->model->SetAnimation(it->anims[it->animIdx], !m_Looping);
    243                 }
     237                // we're handling the root model
     238                // choose animations from the complete state
     239                anim = it->object->GetRandomAnimation(m_State);
     240                m_AnimationName = anim->m_Name;
     241                // if we use a new animation name,
     242                // update the animations of all non-root models
     243                if (it->anim->m_Name != m_AnimationName)
     244                    for (SModelAnimState animState : m_AnimStates)
     245                        if (animState.model != m_Model)
     246                            animState.model->SetAnimation(animState.object->GetRandomAnimation(m_AnimationName));
    244247            }
     248            else
     249                // choose animations that match the root
     250                anim = it->object->GetRandomAnimation(m_AnimationName);
    245251
     252            if (anim != it->anim)
     253            {
     254                it->anim = anim;
     255                it->model->SetAnimation(anim, !m_Looping);
     256            }
     257
    246258            it->pastActionPos = false;
    247259            it->pastLoadPos = false;
    248260            it->pastSoundPos = false;
  • source/graphics/UnitAnimation.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    9595    struct SModelAnimState
    9696    {
    9797        CModel* model;
    98         std::vector<CSkeletonAnim*> anims;
    99         size_t animIdx;
     98        CSkeletonAnim* anim;
     99        const CObjectEntry* object;
    100100        float time;
    101101        bool pastLoadPos;
    102102        bool pastActionPos;
     
    117117    CModel* m_Model;
    118118    const CObjectEntry* m_Object;
    119119    CStr m_State;
     120    CStr m_AnimationName;
    120121    bool m_Looping;
    121122    float m_OriginalSpeed;
    122123    float m_Speed;