Changeset View
Changeset View
Standalone View
Standalone View
source/graphics/ObjectBase.h
Show All 16 Lines | |||||
#ifndef INCLUDED_OBJECTBASE | #ifndef INCLUDED_OBJECTBASE | ||||
#define INCLUDED_OBJECTBASE | #define INCLUDED_OBJECTBASE | ||||
#include "lib/file/vfs/vfs_path.h" | #include "lib/file/vfs/vfs_path.h" | ||||
#include "ps/CStr.h" | #include "ps/CStr.h" | ||||
#include "ps/CStrIntern.h" | #include "ps/CStrIntern.h" | ||||
class CActorDef; | |||||
class CModel; | class CModel; | ||||
class CObjectEntry; | |||||
class CObjectManager; | class CObjectManager; | ||||
class CSkeletonAnim; | class CSkeletonAnim; | ||||
class CXeromyces; | class CXeromyces; | ||||
class XMBElement; | class XMBElement; | ||||
#include <boost/random/mersenne_twister.hpp> | #include <boost/random/mersenne_twister.hpp> | ||||
#include <map> | #include <map> | ||||
#include <set> | #include <set> | ||||
#include <unordered_set> | #include <unordered_set> | ||||
#include <vector> | #include <vector> | ||||
/** | |||||
* Maintains the tree of possible objects from a specific actor-LOD definition. | |||||
* An Object Base is made of: | |||||
* - a material | |||||
* - a few properties (float on water / casts shadow / ...) | |||||
* - a number of variant groups. | |||||
* Any actual object in game will pick a variant from each group (see ObjectEntry). | |||||
*/ | |||||
class CObjectBase | class CObjectBase | ||||
{ | { | ||||
friend CActorDef; | |||||
// See CopyWithLOD() below. | |||||
NONCOPYABLE(CObjectBase); | NONCOPYABLE(CObjectBase); | ||||
public: | public: | ||||
struct Anim | struct Anim | ||||
{ | { | ||||
// constructor | // constructor | ||||
Anim() : m_Frequency(0), m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f), m_SoundPos(-1.f) {} | Anim() : m_Frequency(0), m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f), m_SoundPos(-1.f) {} | ||||
// name of the animation - "Idle", "Run", etc | // name of the animation - "Idle", "Run", etc | ||||
CStr m_AnimName; | CStr m_AnimName; | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | struct Variation | ||||
Decal decal; | Decal decal; | ||||
VfsPath particles; | VfsPath particles; | ||||
CStr color; | CStr color; | ||||
std::multimap<CStr, Prop> props; | std::multimap<CStr, Prop> props; | ||||
std::multimap<CStr, Anim> anims; | std::multimap<CStr, Anim> anims; | ||||
std::multimap<CStr, Samp> samplers; | std::multimap<CStr, Samp> samplers; | ||||
}; | }; | ||||
CObjectBase(CObjectManager& objectManager); | CObjectBase(CObjectManager& objectManager, CActorDef& actorDef, u8 lodLevel); | ||||
// Get the variation key (indices of chosen variants from each group) | // Get the variation key (indices of chosen variants from each group) | ||||
// based on the selection strings | // based on the selection strings | ||||
std::vector<u8> CalculateVariationKey(const std::vector<std::set<CStr> >& selections); | std::vector<u8> CalculateVariationKey(const std::vector<std::set<CStr> >& selections) const; | ||||
// Get the final actor data, combining all selected variants | // Get the final actor data, combining all selected variants | ||||
const Variation BuildVariation(const std::vector<u8>& variationKey); | const Variation BuildVariation(const std::vector<u8>& variationKey) const; | ||||
// Get a set of selection strings that are complete enough to specify an | |||||
// exact variation of the actor, using the initial selections wherever possible | |||||
// and choosing randomly where a choice is necessary. | |||||
std::set<CStr> CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections); | |||||
// Given a prioritized vector of selection string sets that partially specify | |||||
// a variation, calculates a remaining set of selection strings such that the resulting | |||||
// set merged with the initial selections fully specifies an exact variation of | |||||
// the actor. The resulting selections are selected randomly, but only where a choice | |||||
// is necessary (i.e. where there are multiple variants but the initial selections, | |||||
// applied in priority order, fail to select one). | |||||
std::set<CStr> CalculateRandomRemainingSelections(uint32_t seed, const std::vector<std::set<CStr> >& initialSelections); | |||||
// Get a list of variant groups for this object, plus for all possible | // Get a list of variant groups for this object, plus for all possible | ||||
// props. Duplicated groups are removed, if several props share the same | // props. Duplicated groups are removed, if several props share the same | ||||
// variant names. | // variant names. | ||||
std::vector<std::vector<CStr> > GetVariantGroups() const; | std::vector<std::vector<CStr> > GetVariantGroups() const; | ||||
CStrW GetPathname() const; | |||||
public: | |||||
struct { | |||||
// cast shadows from this object | |||||
bool m_CastShadows; | |||||
// float on top of water | |||||
bool m_FloatOnWater; | |||||
} m_Properties; | |||||
// the material file | |||||
VfsPath m_Material; | |||||
u8 m_LODLevel; | |||||
// short human-readable name | |||||
CStrW m_ShortName; | |||||
private: | |||||
/** | |||||
* Acts as an explicit copy constructor, for a new LOD level. | |||||
*/ | |||||
std::unique_ptr<CObjectBase> CopyWithLOD(u8 newLod) const; | |||||
friend std::unique_ptr<CObjectBase> CObjectBase::CopyWithLOD(u8 newLod) const; | |||||
// A low-quality RNG like rand48 causes visible non-random patterns (particularly | |||||
// in large grids of the same actor with consecutive seeds, e.g. forests), | |||||
// so use a better one that appears to avoid those patterns | |||||
using rng_t = boost::mt19937; | |||||
std::set<CStr> CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr>>& initialSelections) const; | |||||
/** | |||||
* Get all LOD levels at which this object changes (includes props). | |||||
* Intended to be called by the actor def. | |||||
* @param splits - a sorted vector of unique LOD splits. | |||||
*/ | |||||
void GetLODSplits(std::vector<u8>& splits) const; | |||||
void Load(const CXeromyces& XeroFile, const XMBElement& base); | |||||
void LoadVariant(const CXeromyces& XeroFile, const XMBElement& variant, Variant& currentVariant); | |||||
private: | |||||
// Backref to the owning actor. | |||||
CActorDef& m_ActorDef; | |||||
std::vector< std::vector<Variant> > m_VariantGroups; | |||||
CObjectManager& m_ObjectManager; | |||||
}; | |||||
/** | |||||
* Represents an actor file. Actors can contain various Level of Detail (LOD) levels. | |||||
* An ActorDef maintains a CObjectBase for each specified LOD level, and provides access to it. | |||||
*/ | |||||
class CActorDef | |||||
{ | |||||
friend class CObjectManager; | |||||
friend class CObjectBase; | |||||
NONCOPYABLE(CActorDef); | |||||
public: | |||||
CActorDef(CObjectManager& objectManager); | |||||
/** | |||||
* Actors can have various LOD, and ideally we want those to match. | |||||
* This calculates a complete list of selection for the highest-LOD actor, | |||||
* which should be used for any-LOD entry. | |||||
*/ | |||||
std::set<CStr> CalculateRandomVariation(uint32_t seed, const std::vector<std::set<CStr>>& initialSelections) const; | |||||
/** | |||||
* Return a list of Object Entries (one for each LOD level) matching the selections. | |||||
*/ | |||||
std::vector<CObjectEntry*> CreateEntries(const std::vector<std::set<CStr>>& selections); | |||||
std::vector<u8> LODLevels() const; | |||||
u8 GetLODFor(u8 ratio) const; | |||||
VfsPath GetPathname() const { return m_Pathname; } | |||||
// Interface accessible from CObjectManager / CObjectBase | |||||
protected: | |||||
/** | |||||
* Return the Object base matching the given LOD level. | |||||
*/ | |||||
CObjectBase* GetBase(u8 LODLevel) const; | |||||
/** | /** | ||||
* Initialise this object by loading from the given file. | * Initialise this object by loading from the given file. | ||||
* Returns false on error. | * Returns false on error. | ||||
*/ | */ | ||||
bool Load(const VfsPath& pathname); | bool Load(const VfsPath& pathname); | ||||
/** | /** | ||||
* Reload this object from the file that it was previously loaded from. | * Reload this object from the file that it was previously loaded from. | ||||
* Returns false on error. | * Returns false on error. | ||||
*/ | */ | ||||
bool Reload(); | bool Reload(); | ||||
/** | /** | ||||
* Returns whether this object (including any possible props) | * Returns whether this object (including any possible props) | ||||
* uses the given file. (This is used for hotloading.) | * uses the given file. (This is used for hotloading.) | ||||
*/ | */ | ||||
bool UsesFile(const VfsPath& pathname); | bool UsesFile(const VfsPath& pathname); | ||||
// filename that this was loaded from | // filename that this was loaded from | ||||
VfsPath m_Pathname; | VfsPath m_Pathname; | ||||
// short human-readable name | |||||
CStrW m_ShortName; | |||||
struct { | |||||
// cast shadows from this object | |||||
bool m_CastShadows; | |||||
// float on top of water | |||||
bool m_FloatOnWater; | |||||
} m_Properties; | |||||
// the material file | |||||
VfsPath m_Material; | |||||
private: | private: | ||||
// A low-quality RNG like rand48 causes visible non-random patterns (particularly | |||||
// in large grids of the same actor with consecutive seeds, e.g. forests), | |||||
// so use a better one that appears to avoid those patterns | |||||
using rng_t = boost::mt19937; | |||||
std::set<CStr> CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr> >& initialSelections); | |||||
std::vector< std::vector<Variant> > m_VariantGroups; | |||||
CObjectManager& m_ObjectManager; | CObjectManager& m_ObjectManager; | ||||
std::unordered_set<VfsPath> m_UsedFiles; | std::vector<std::unique_ptr<CObjectBase>> m_ObjectBases; | ||||
void LoadVariant(const CXeromyces& XeroFile, const XMBElement& variant, Variant& currentVariant); | std::unordered_set<VfsPath> m_UsedFiles; | ||||
}; | }; | ||||
#endif | #endif |
Wildfire Games · Phabricator