1 /* Copyright (C) 2021 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #ifndef INCLUDED_OBJECTBASE
19 #define INCLUDED_OBJECTBASE
21 #include "lib/file/vfs/vfs_path.h"
23 #include "ps/CStrIntern.h"
31 #include <boost/random/mersenne_twister.hpp>
35 #include <unordered_set>
39 * Maintains the tree of possible objects from a specific actor definition at a given quality level.
40 * An Object Base is made of:
42 * - a few properties (float on water / casts shadow / ...)
43 * - a number of variant groups.
44 * Any actual object in game will pick a variant from each group (see ObjectEntry).
50 // See CopyWithQuality() below.
51 NONCOPYABLE(CObjectBase
);
56 Anim() : m_Frequency(0), m_Speed(1.f
), m_ActionPos(-1.f
), m_ActionPos2(-1.f
), m_SoundPos(-1.f
) {}
57 // name of the animation - "Idle", "Run", etc
59 // ID of the animation: if not empty, something specific to sync with props.
62 // filename of the animation - manidle.psa, manrun.psa, etc
64 // animation speed, as specified in XML actor file
66 // fraction [0.0, 1.0] of the way through the animation that the interesting bit(s)
67 // happens, or -1.0 if unspecified
76 Prop() : m_minHeight(0.f
), m_maxHeight(0.f
), m_selectable(true) {}
77 // name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc ..
79 // name of the model file - art/actors/props/sword.xml or whatever
81 // allow the prop to ajust the height from minHeight to maxHeight relative to the main model
89 // identifier name of sampler in GLSL shaders
90 CStrIntern m_SamplerName
;
92 VfsPath m_SamplerFile
;
97 Decal() : m_SizeX(0.f
), m_SizeZ(0.f
), m_Angle(0.f
), m_OffsetX(0.f
), m_OffsetZ(0.f
) {}
108 Variant() : m_Frequency(0) {}
110 CStr m_VariantName
; // lowercase name
112 VfsPath m_ModelFilename
;
117 std::vector
<Anim
> m_Anims
;
118 std::vector
<Prop
> m_Props
;
119 std::vector
<Samp
> m_Samplers
;
128 std::multimap
<CStr
, Prop
> props
;
129 std::multimap
<CStr
, Anim
> anims
;
130 std::multimap
<CStr
, Samp
> samplers
;
133 CObjectBase(CObjectManager
& objectManager
, CActorDef
& actorDef
, u8 QualityLevel
);
135 // Returns a set of selection such that, added to initialSelections, CalculateVariationKey can proceed.
136 std::set
<CStr
> CalculateRandomRemainingSelections(uint32_t seed
, const std::vector
<std::set
<CStr
>>& initialSelections
) const;
138 // Get the variation key (indices of chosen variants from each group)
139 // based on the selection strings.
140 // Should not have to make a random choice: the selections should be complete.
141 std::vector
<u8
> CalculateVariationKey(const std::vector
<const std::set
<CStr
>*>& selections
) const;
143 // Get the final actor data, combining all selected variants
144 const Variation
BuildVariation(const std::vector
<u8
>& variationKey
) const;
146 // Get a list of variant groups for this object, plus for all possible
147 // props. Duplicated groups are removed, if several props share the same
149 std::vector
<std::vector
<CStr
> > GetVariantGroups() const;
151 // Return a string identifying this actor uniquely (includes quality level information);
152 const CStr
& GetIdentifier() const;
155 * Returns whether this object (including any possible props)
156 * uses the given file. (This is used for hotloading.)
158 bool UsesFile(const VfsPath
& pathname
) const;
162 // cast shadows from this object
164 // float on top of water
171 // Quality level - part of the data resource path.
175 // Private interface for CActorDef/ObjectEntry
178 * Acts as an explicit copy constructor, for a new quality level.
179 * Note that this does not reload the actor, so this setting will only change props.
181 std::unique_ptr
<CObjectBase
> CopyWithQuality(u8 newQualityLevel
) const;
183 // A low-quality RNG like rand48 causes visible non-random patterns (particularly
184 // in large grids of the same actor with consecutive seeds, e.g. forests),
185 // so use a better one that appears to avoid those patterns
186 using rng_t
= boost::mt19937
;
187 std::set
<CStr
> CalculateRandomRemainingSelections(rng_t
& rng
, const std::vector
<std::set
<CStr
>>& initialSelections
) const;
190 * Get all quality levels at which this object changes (includes props).
191 * Intended to be called by CActorFef.
192 * @param splits - a sorted vector of unique quality splits.
194 void GetQualitySplits(std::vector
<u8
>& splits
) const;
196 [[nodiscard
]] bool Load(const CXeromyces
& XeroFile
, const XMBElement
& base
);
197 [[nodiscard
]] bool LoadVariant(const CXeromyces
& XeroFile
, const XMBElement
& variant
, Variant
& currentVariant
);
200 // Backref to the owning actor.
201 CActorDef
& m_ActorDef
;
203 // Used to identify this actor uniquely in the ObjectManager (and for debug).
206 std::vector
< std::vector
<Variant
> > m_VariantGroups
;
207 CObjectManager
& m_ObjectManager
;
211 * Represents an actor file. Actors can contain various quality levels.
212 * An ActorDef maintains a CObjectBase for each specified quality level, and provides access to it.
216 // Friend these three so they can use GetBase.
217 friend class CObjectManager
;
218 friend class CObjectBase
;
219 friend class CObjectEntry
;
221 NONCOPYABLE(CActorDef
);
224 CActorDef(CObjectManager
& objectManager
);
226 std::vector
<u8
> QualityLevels() const;
228 VfsPath
GetPathname() const { return m_Pathname
; }
231 * Return a list of selections specifying a particular variant in all groups, based on the seed.
233 std::set
<CStr
> PickSelectionsAtRandom(uint32_t seed
) const;
235 // Interface accessible from CObjectManager / CObjectBase
238 * Return the Object base matching the given quality level.
240 const std::shared_ptr
<CObjectBase
>& GetBase(u8 QualityLevel
) const;
243 * Initialise this object by loading from the given file.
244 * Returns false on error.
246 bool Load(const VfsPath
& pathname
);
249 * Initialise this object with a default placeholder actor,
250 * pretending to be the actor at pathname.
252 void LoadErrorPlaceholder(const VfsPath
& pathname
);
255 * Returns whether this actor (including any possible props)
256 * uses the given file. (This is used for hotloading.)
258 bool UsesFile(const VfsPath
& pathname
) const;
260 // filename that this was loaded from
264 CObjectManager
& m_ObjectManager
;
266 // std::shared_ptr to avoid issues during hotloading.
267 std::vector
<std::shared_ptr
<CObjectBase
>> m_ObjectBases
;
269 std::unordered_set
<VfsPath
> m_UsedFiles
;