Ticket #2324: actorFormat_variationnames.diff
File actorFormat_variationnames.diff, 19.2 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/art/actors/actor.rnc
38 38 element animations { 39 39 element animation { 40 40 attribute name { text } & 41 attribute frequency { xsd:nonNegativeInteger }? & 41 42 attribute file { text }? & 42 43 attribute speed { xsd:nonNegativeInteger } & 43 44 attribute event { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? & -
binaries/data/mods/public/art/actors/actor.rng
94 94 <interleave> 95 95 <attribute name="name"/> 96 96 <optional> 97 <attribute name="frequency"> 98 <data type="nonNegativeInteger"/> 99 </attribute> 100 </optional> 101 <optional> 97 102 <attribute name="file"/> 98 103 </optional> 99 104 <attribute name="speed"> -
binaries/data/mods/public/art/actors/units/athenians/cavalry_javelinist_b.xml
5 5 <variant frequency="1" name="Base"> 6 6 <animations> 7 7 <animation file="quadraped/horse_idle_a.psa" name="Idle" speed="50"/> 8 <animation file="quadraped/horse_walk.psa" name="Walk" speed="120"/>9 8 <animation file="quadraped/horse_gallop.psa" name="Run" speed="50"/> 10 9 <animation file="quadraped/horse_walk.psa" name="carry_meat" speed="120"/> 11 10 <animation event=".5" file="quadraped/horse_attack_a.psa" name="attack_ranged" speed="20"/> … … 15 14 </animations> 16 15 <mesh>skeletal/horse.pmd</mesh> 17 16 <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"/> 19 18 </props> 20 19 </variant> 21 20 </group> … … 43 42 <prop actor="particle/dust_cav.xml" attachpoint="root"/> 44 43 </props> 45 44 </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> 46 51 </group> 47 52 <material>objectcolor.xml</material> 48 53 </actor> -
binaries/data/mods/public/art/actors/units/athenians/cavalry_javelinist_b_r.xml
5 5 <variant frequency="100" name="Base"> 6 6 <animations> 7 7 <animation file="biped/cavalryidle.psa" name="Idle" speed="50"/> 8 <animation file="biped/cavalryidle.psa" name="Walk" speed="50"/>9 8 <animation file="biped/rider_gallop.psa" name="Run" speed="40"/> 10 9 <animation event="0.59" file="biped/rider_javelin_atk_a.psa" load="0" name="attack_ranged" speed="50"/> 11 10 <animation event="0.5" file="cavalry/sword/attack/rider_sword_shield_atk_a.psa" name="attack_slaughter" speed="400"/> … … 26 25 </group> 27 26 <group> 28 27 <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> 29 34 <variant name="attack_slaughter"> 30 35 <props> 31 36 <prop actor="props/units/weapons/spartan_sword.xml" attachpoint="r_hand"/> -
binaries/data/mods/public/art/variants/variant.rnc
34 34 element animations { 35 35 element animation { 36 36 attribute name { text } & 37 attribute frequency { xsd:nonNegativeInteger }? & 37 38 attribute file { text }? & 38 39 attribute speed { xsd:nonNegativeInteger } & 39 40 attribute event { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? & -
binaries/data/mods/public/art/variants/variant.rng
83 83 <interleave> 84 84 <attribute name="name"/> 85 85 <optional> 86 <attribute name="frequency"> 87 <data type="nonNegativeInteger"/> 88 </attribute> 89 </optional> 90 <optional> 86 91 <attribute name="file"/> 87 92 </optional> 88 93 <attribute name="speed"> -
source/graphics/Model.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 255 255 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 256 256 // BuildAnimation: load raw animation frame animation from given file, and build a 257 257 // animation specific to this model 258 CSkeletonAnim* CModel::BuildAnimation(const VfsPath& pathname, const CStr& name, float speed, float actionpos, float actionpos2, float soundpos)258 CSkeletonAnim* CModel::BuildAnimation(const VfsPath& pathname, const CStr& name, int frequency, float speed, float actionpos, float actionpos2, float soundpos) 259 259 { 260 260 CSkeletonAnimDef* def = m_SkeletonAnimManager.GetAnimation(pathname); 261 261 if (!def) … … 263 263 264 264 CSkeletonAnim* anim = new CSkeletonAnim(); 265 265 anim->m_Name = name; 266 anim->m_Frequency = frequency; 266 267 anim->m_AnimDef = def; 267 268 anim->m_Speed = speed; 268 269 -
source/graphics/Model.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 201 201 * animation specific to this model. 202 202 * @param pathname animation file to load 203 203 * @param name animation name (e.g. "idle") 204 * @param frequency influences the random choices 204 205 * @param speed animation speed as a factor of the default animation speed 205 206 * @param actionpos offset of 'action' event, in range [0, 1] 206 207 * @param actionpos2 offset of 'action2' event, in range [0, 1] … … 207 208 * @param sound offset of 'sound' event, in range [0, 1] 208 209 * @return new animation, or NULL on error 209 210 */ 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); 211 212 212 213 /** 213 214 * Add a prop to the model on the given point. -
source/graphics/ObjectBase.cpp
163 163 { 164 164 if (ae.Name == at_name) 165 165 anim.m_AnimName = ae.Value; 166 else if (ae.Name == at_frequency) 167 anim.m_Frequency = ae.Value.ToInt(); 166 168 else if (ae.Name == at_file) 167 169 anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8(); 168 170 else if (ae.Name == at_speed) -
source/graphics/ObjectBase.h
42 42 struct Anim 43 43 { 44 44 // 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) {} 46 46 // name of the animation - "Idle", "Run", etc 47 47 CStr m_AnimName; 48 int m_Frequency; 48 49 // filename of the animation - manidle.psa, manrun.psa, etc 49 50 VfsPath m_FileName; 50 51 // animation speed, as specified in XML actor file -
source/graphics/ObjectEntry.cpp
161 161 162 162 if (!it->second.m_FileName.empty()) 163 163 { 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); 165 165 if (anim) 166 166 m_Animations.insert(std::make_pair(name, anim)); 167 167 } … … 248 248 249 249 CSkeletonAnim* CObjectEntry::GetRandomAnimation(const CStr& animationName) const 250 250 { 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); 256 252 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; 260 269 } 261 270 262 271 std::vector<CSkeletonAnim*> CObjectEntry::GetAnimations(const CStr& animationName) const … … 265 274 266 275 SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound(animationName); 267 276 SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound(animationName); 277 268 278 for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it) 269 279 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); 270 295 return anims; 271 296 } -
source/graphics/ObjectEntry.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 63 63 64 64 std::wstring m_ProjectileModelName; 65 65 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 */ 68 72 CSkeletonAnim* GetRandomAnimation(const CStr& animationName) const; 69 73 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 */ 71 80 std::vector<CSkeletonAnim*> GetAnimations(const CStr& animationName) const; 72 81 73 82 // corresponding model -
source/graphics/SkeletonAnim.h
1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 34 34 public: 35 35 // the name of the action which uses this animation (e.g. "idle") 36 36 CStr m_Name; 37 // frequency of the animation 38 int m_Frequency; 37 39 // the raw animation frame data; may be NULL if this is a static 'animation' 38 40 CSkeletonAnimDef* m_AnimDef; 39 41 // speed at which this animation runs, as a factor of the AnimDef default speed -
source/graphics/UnitAnimation.cpp
1 /* Copyright (C) 201 2Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 41 41 } 42 42 43 43 CUnitAnimation::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), 45 45 m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f) 46 46 { 47 47 ReloadUnit(model, object); … … 56 56 { 57 57 SModelAnimState state; 58 58 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 animation64 65 59 state.model = model; 66 state.animIdx = rand(0, state.anims.size()); 60 state.object = object; 61 state.anim = object->GetRandomAnimation(m_State); 67 62 state.time = 0.f; 68 63 state.pastLoadPos = false; 69 64 state.pastActionPos = false; 70 65 state.pastSoundPos = false; 71 66 67 ENSURE(state.anim != NULL); // there must always be an idle animation 68 72 69 m_AnimStates.push_back(state); 73 70 74 model->SetAnimation(state.anim s[state.animIdx], !m_Looping);71 model->SetAnimation(state.anim, !m_Looping); 75 72 76 73 // 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) 79 76 m_AnimStatesAreStatic = false; 80 77 81 78 // Recursively add all props … … 111 108 if (name != m_State) 112 109 { 113 110 m_State = name; 111 m_AnimationName = name; 114 112 115 113 ReloadUnit(m_Model, m_Object); 116 114 } … … 129 127 // Update all the synced prop models to each coincide with actionTime 130 128 for (std::vector<SModelAnimState>::iterator it = m_AnimStates.begin(); it != m_AnimStates.end(); ++it) 131 129 { 132 CSkeletonAnimDef* animDef = it->anim s[it->animIdx]->m_AnimDef;130 CSkeletonAnimDef* animDef = it->anim->m_AnimDef; 133 131 if (animDef == NULL) 134 132 continue; // ignore static animations 135 133 136 134 float duration = animDef->GetDuration(); 137 135 138 float actionPos = it->anim s[it->animIdx]->m_ActionPos;136 float actionPos = it->anim->m_ActionPos; 139 137 bool hasActionPos = (actionPos != -1.f); 140 138 141 139 if (!hasActionPos) … … 162 160 // Advance all of the prop models independently 163 161 for (std::vector<SModelAnimState>::iterator it = m_AnimStates.begin(); it != m_AnimStates.end(); ++it) 164 162 { 165 CSkeletonAnimDef* animDef = it->anim s[it->animIdx]->m_AnimDef;163 CSkeletonAnimDef* animDef = it->anim->m_AnimDef; 166 164 if (animDef == NULL) 167 165 continue; // ignore static animations 168 166 169 167 float duration = animDef->GetDuration(); 170 168 171 float actionPos = it->anim s[it->animIdx]->m_ActionPos;172 float loadPos = it->anim s[it->animIdx]->m_ActionPos2;173 float soundPos = it->anim s[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; 174 172 bool hasActionPos = (actionPos != -1.f); 175 173 bool hasLoadPos = (loadPos != -1.f); 176 174 bool hasSoundPos = (soundPos != -1.f); … … 180 178 if (m_SyncRepeatTime && hasActionPos) 181 179 speed = duration / m_SyncRepeatTime; 182 180 else 183 speed = m_Speed * it->anim s[it->animIdx]->m_Speed;181 speed = m_Speed * it->anim->m_Speed; 184 182 185 183 // Convert from real time to scaled animation time 186 184 float advance = time * speed; … … 232 230 // Wrap the timer around 233 231 it->time = fmod(it->time + advance, duration); 234 232 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) 237 236 { 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)); 244 247 } 248 else 249 // choose animations that match the root 250 anim = it->object->GetRandomAnimation(m_AnimationName); 245 251 252 if (anim != it->anim) 253 { 254 it->anim = anim; 255 it->model->SetAnimation(anim, !m_Looping); 256 } 257 246 258 it->pastActionPos = false; 247 259 it->pastLoadPos = false; 248 260 it->pastSoundPos = false; -
source/graphics/UnitAnimation.h
1 /* Copyright (C) 201 1Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 95 95 struct SModelAnimState 96 96 { 97 97 CModel* model; 98 std::vector<CSkeletonAnim*> anims;99 size_t animIdx;98 CSkeletonAnim* anim; 99 const CObjectEntry* object; 100 100 float time; 101 101 bool pastLoadPos; 102 102 bool pastActionPos; … … 117 117 CModel* m_Model; 118 118 const CObjectEntry* m_Object; 119 119 CStr m_State; 120 CStr m_AnimationName; 120 121 bool m_Looping; 121 122 float m_OriginalSpeed; 122 123 float m_Speed;