1 /* Copyright (C) 2016 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef INCLUDED_OBJECTBASE 19 #define INCLUDED_OBJECTBASE 20 21 class CModel; 22 class CSkeletonAnim; 23 class CObjectManager; 24 class CXeromyces; 25 class XMBElement; 26 27 #include <vector> 28 #include <set> 29 #include <map> 30 #include <boost/unordered_set.hpp> 31 #include "lib/file/vfs/vfs_path.h" 32 #include "ps/CStr.h" 33 #include "ps/CStrIntern.h" 34 35 #include <boost/random/mersenne_twister.hpp> 36 37 class CObjectBase 38 { 39 NONCOPYABLE(CObjectBase); 40 public: 41 42 struct Anim 43 { 44 // constructor AnimAnim45 Anim() : m_Frequency(0), m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f), m_SoundPos(-1.f) {} 46 // name of the animation - "Idle", "Run", etc 47 CStr m_AnimName; 48 // ID of the animation: if not empty, something specific to sync with props. 49 CStr m_ID = ""; 50 int m_Frequency; 51 // filename of the animation - manidle.psa, manrun.psa, etc 52 VfsPath m_FileName; 53 // animation speed, as specified in XML actor file 54 float m_Speed; 55 // fraction [0.0, 1.0] of the way through the animation that the interesting bit(s) 56 // happens, or -1.0 if unspecified 57 float m_ActionPos; 58 float m_ActionPos2; 59 float m_SoundPos; 60 }; 61 62 struct Prop 63 { 64 // constructor PropProp65 Prop() : m_minHeight(0.f), m_maxHeight(0.f), m_selectable(true) {} 66 // name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc .. 67 CStr m_PropPointName; 68 // name of the model file - art/actors/props/sword.xml or whatever 69 CStrW m_ModelName; 70 // allow the prop to ajust the height from minHeight to maxHeight relative to the main model 71 float m_minHeight; 72 float m_maxHeight; 73 bool m_selectable; 74 }; 75 76 struct Samp 77 { 78 // identifier name of sampler in GLSL shaders 79 CStrIntern m_SamplerName; 80 // path to load from 81 VfsPath m_SamplerFile; 82 }; 83 84 struct Decal 85 { DecalDecal86 Decal() : m_SizeX(0.f), m_SizeZ(0.f), m_Angle(0.f), m_OffsetX(0.f), m_OffsetZ(0.f) {} 87 88 float m_SizeX; 89 float m_SizeZ; 90 float m_Angle; 91 float m_OffsetX; 92 float m_OffsetZ; 93 }; 94 95 struct Variant 96 { VariantVariant97 Variant() : m_Frequency(0) {} 98 99 CStr m_VariantName; // lowercase name 100 int m_Frequency; 101 VfsPath m_ModelFilename; 102 Decal m_Decal; 103 VfsPath m_Particles; 104 CStr m_Color; 105 106 std::vector<Anim> m_Anims; 107 std::vector<Prop> m_Props; 108 std::vector<Samp> m_Samplers; 109 }; 110 111 struct Variation 112 { 113 VfsPath model; 114 Decal decal; 115 VfsPath particles; 116 CStr color; 117 std::multimap<CStr, Prop> props; 118 std::multimap<CStr, Anim> anims; 119 std::multimap<CStr, Samp> samplers; 120 }; 121 122 CObjectBase(CObjectManager& objectManager); 123 124 // Get the variation key (indices of chosen variants from each group) 125 // based on the selection strings 126 std::vector<u8> CalculateVariationKey(const std::vector<std::set<CStr> >& selections); 127 128 // Get the final actor data, combining all selected variants 129 const Variation BuildVariation(const std::vector<u8>& variationKey); 130 131 // Get a set of selection strings that are complete enough to specify an 132 // exact variation of the actor, using the initial selections wherever possible 133 // and choosing randomly where a choice is necessary. 134 std::set<CStr> CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections); 135 136 // Given a prioritized vector of selection string sets that partially specify 137 // a variation, calculates a remaining set of selection strings such that the resulting 138 // set merged with the initial selections fully specifies an exact variation of 139 // the actor. The resulting selections are selected randomly, but only where a choice 140 // is necessary (i.e. where there are multiple variants but the initial selections, 141 // applied in priority order, fail to select one). 142 std::set<CStr> CalculateRandomRemainingSelections(uint32_t seed, const std::vector<std::set<CStr> >& initialSelections); 143 144 // Get a list of variant groups for this object, plus for all possible 145 // props. Duplicated groups are removed, if several props share the same 146 // variant names. 147 std::vector<std::vector<CStr> > GetVariantGroups() const; 148 149 /** 150 * Initialise this object by loading from the given file. 151 * Returns false on error. 152 */ 153 bool Load(const VfsPath& pathname); 154 155 /** 156 * Reload this object from the file that it was previously loaded from. 157 * Returns false on error. 158 */ 159 bool Reload(); 160 161 /** 162 * Returns whether this object (including any possible props) 163 * uses the given file. (This is used for hotloading.) 164 */ 165 bool UsesFile(const VfsPath& pathname); 166 167 // filename that this was loaded from 168 VfsPath m_Pathname; 169 170 // short human-readable name 171 CStrW m_ShortName; 172 173 struct { 174 // cast shadows from this object 175 bool m_CastShadows; 176 // float on top of water 177 bool m_FloatOnWater; 178 } m_Properties; 179 180 // the material file 181 VfsPath m_Material; 182 183 private: 184 // A low-quality RNG like rand48 causes visible non-random patterns (particularly 185 // in large grids of the same actor with consecutive seeds, e.g. forests), 186 // so use a better one that appears to avoid those patterns 187 typedef boost::mt19937 rng_t; 188 189 std::set<CStr> CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr> >& initialSelections); 190 191 std::vector< std::vector<Variant> > m_VariantGroups; 192 CObjectManager& m_ObjectManager; 193 194 boost::unordered_set<VfsPath> m_UsedFiles; 195 196 void LoadVariant(const CXeromyces& XeroFile, const XMBElement& variant, Variant& currentVariant); 197 }; 198 199 #endif 200