Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ObjectBase.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 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 #include "precompiled.h"
19 
20 #include <algorithm>
21 #include <queue>
22 
23 #include "ObjectBase.h"
24 
25 #include "ObjectManager.h"
26 #include "ps/XML/Xeromyces.h"
27 #include "ps/Filesystem.h"
28 #include "ps/CLogger.h"
29 #include "lib/timer.h"
30 #include "maths/MathUtil.h"
31 
32 #include <boost/random/uniform_int.hpp>
33 
35 : m_ObjectManager(objectManager)
36 {
37  m_Properties.m_CastShadows = false;
38  m_Properties.m_FloatOnWater = false;
39 }
40 
41 bool CObjectBase::Load(const VfsPath& pathname)
42 {
43  m_UsedFiles.clear();
44  m_UsedFiles.insert(pathname);
45 
46  CXeromyces XeroFile;
47  if (XeroFile.Load(g_VFS, pathname) != PSRETURN_OK)
48  return false;
49 
50  // Define all the elements used in the XML file
51  #define EL(x) int el_##x = XeroFile.GetElementID(#x)
52  #define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
53  EL(actor);
54  EL(castshadow);
55  EL(float);
56  EL(material);
57  EL(group);
58  EL(variant);
59  EL(animations);
60  EL(animation);
61  EL(props);
62  EL(prop);
63  EL(mesh);
64  EL(texture);
65  EL(textures);
66  EL(colour);
67  EL(decal);
68  EL(particles);
69  AT(file);
70  AT(name);
71  AT(speed);
72  AT(event);
73  AT(load);
74  AT(sound);
75  AT(attachpoint);
76  AT(actor);
77  AT(frequency);
78  AT(width);
79  AT(depth);
80  AT(angle);
81  AT(offsetx);
82  AT(offsetz);
83  AT(minheight);
84  AT(maxheight);
85  #undef AT
86  #undef EL
87 
88  XMBElement root = XeroFile.GetRoot();
89 
90  if (root.GetNodeName() != el_actor)
91  {
92  LOGERROR(L"Invalid actor format (unrecognised root element '%hs')", XeroFile.GetElementString(root.GetNodeName()).c_str());
93  return false;
94  }
95 
96 
97  m_VariantGroups.clear();
98 
99  m_Pathname = pathname;
100  m_ShortName = pathname.Basename().string();
101 
102 
103  // Set up the vector<vector<T>> m_Variants to contain the right number
104  // of elements, to avoid wasteful copying/reallocation later.
105  {
106  // Count the variants in each group
107  std::vector<int> variantGroupSizes;
108  XERO_ITER_EL(root, child)
109  {
110  if (child.GetNodeName() == el_group)
111  {
112  variantGroupSizes.push_back(child.GetChildNodes().Count);
113  }
114  }
115 
116  m_VariantGroups.resize(variantGroupSizes.size());
117  // Set each vector to match the number of variants
118  for (size_t i = 0; i < variantGroupSizes.size(); ++i)
119  m_VariantGroups[i].resize(variantGroupSizes[i]);
120  }
121 
122 
123  // (This XML-reading code is rather worryingly verbose...)
124 
125  std::vector<std::vector<Variant> >::iterator currentGroup = m_VariantGroups.begin();
126 
127  XERO_ITER_EL(root, child)
128  {
129  int child_name = child.GetNodeName();
130 
131  if (child_name == el_group)
132  {
133  std::vector<Variant>::iterator currentVariant = currentGroup->begin();
134  XERO_ITER_EL(child, variant)
135  {
136  ENSURE(variant.GetNodeName() == el_variant);
137  XERO_ITER_ATTR(variant, attr)
138  {
139  if (attr.Name == at_name)
140  currentVariant->m_VariantName = attr.Value.LowerCase();
141 
142  else if (attr.Name == at_frequency)
143  currentVariant->m_Frequency = attr.Value.ToInt();
144  }
145 
146  XERO_ITER_EL(variant, option)
147  {
148  int option_name = option.GetNodeName();
149 
150  if (option_name == el_mesh)
151  {
152  currentVariant->m_ModelFilename = VfsPath("art/meshes") / option.GetText().FromUTF8();
153  }
154  else if (option_name == el_textures)
155  {
156  XERO_ITER_EL(option, textures_element)
157  {
158  ENSURE(textures_element.GetNodeName() == el_texture);
159 
160  Samp samp;
161  XERO_ITER_ATTR(textures_element, se)
162  {
163  if (se.Name == at_file)
164  samp.m_SamplerFile = VfsPath("art/textures/skins") / se.Value.FromUTF8();
165  else if (se.Name == at_name)
166  samp.m_SamplerName = se.Value;
167  }
168  currentVariant->m_Samplers.push_back(samp);
169  }
170  }
171  else if (option_name == el_decal)
172  {
173  XMBAttributeList attrs = option.GetAttributes();
174  Decal decal;
175  decal.m_SizeX = attrs.GetNamedItem(at_width).ToFloat();
176  decal.m_SizeZ = attrs.GetNamedItem(at_depth).ToFloat();
177  decal.m_Angle = DEGTORAD(attrs.GetNamedItem(at_angle).ToFloat());
178  decal.m_OffsetX = attrs.GetNamedItem(at_offsetx).ToFloat();
179  decal.m_OffsetZ = attrs.GetNamedItem(at_offsetz).ToFloat();
180  currentVariant->m_Decal = decal;
181  }
182  else if (option_name == el_particles)
183  {
184  XMBAttributeList attrs = option.GetAttributes();
185  VfsPath file = VfsPath("art/particles") / attrs.GetNamedItem(at_file).FromUTF8();
186  currentVariant->m_Particles = file;
187 
188  // For particle hotloading, it's easiest to reload the entire actor,
189  // so remember the relevant particle file as a dependency for this actor
190  m_UsedFiles.insert(file);
191  }
192  else if (option_name == el_colour)
193  {
194  currentVariant->m_Color = option.GetText();
195  }
196  else if (option_name == el_animations)
197  {
198  XERO_ITER_EL(option, anim_element)
199  {
200  ENSURE(anim_element.GetNodeName() == el_animation);
201 
202  Anim anim;
203  XERO_ITER_ATTR(anim_element, ae)
204  {
205  if (ae.Name == at_name)
206  {
207  anim.m_AnimName = ae.Value;
208  }
209  else if (ae.Name == at_file)
210  {
211  anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8();
212  }
213  else if (ae.Name == at_speed)
214  {
215  anim.m_Speed = ae.Value.ToInt() / 100.f;
216  if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
217  }
218  else if (ae.Name == at_event)
219  {
220  float pos = ae.Value.ToFloat();
221  anim.m_ActionPos = clamp(pos, 0.f, 1.f);
222  }
223  else if (ae.Name == at_load)
224  {
225  float pos = ae.Value.ToFloat();
226  anim.m_ActionPos2 = clamp(pos, 0.f, 1.f);
227  }
228  else if (ae.Name == at_sound)
229  {
230  float pos = ae.Value.ToFloat();
231  anim.m_SoundPos = clamp(pos, 0.f, 1.f);
232  }
233  }
234  currentVariant->m_Anims.push_back(anim);
235  }
236 
237  }
238  else if (option_name == el_props)
239  {
240  XERO_ITER_EL(option, prop_element)
241  {
242  ENSURE(prop_element.GetNodeName() == el_prop);
243 
244  Prop prop;
245  XERO_ITER_ATTR(prop_element, pe)
246  {
247  if (pe.Name == at_attachpoint)
248  prop.m_PropPointName = pe.Value;
249  else if (pe.Name == at_actor)
250  prop.m_ModelName = pe.Value.FromUTF8();
251  else if (pe.Name == at_minheight)
252  prop.m_minHeight = pe.Value.ToFloat();
253  else if (pe.Name == at_maxheight)
254  prop.m_maxHeight = pe.Value.ToFloat();
255  }
256  currentVariant->m_Props.push_back(prop);
257  }
258  }
259  }
260 
261  ++currentVariant;
262  }
263 
264  if (currentGroup->size() == 0)
265  {
266  LOGERROR(L"Actor group has zero variants ('%ls')", pathname.string().c_str());
267  }
268 
269  ++currentGroup;
270  }
271  else if (child_name == el_castshadow)
272  {
273  m_Properties.m_CastShadows = true;
274  }
275  else if (child_name == el_float)
276  {
277  m_Properties.m_FloatOnWater = true;
278  }
279  else if (child_name == el_material)
280  {
281  m_Material = VfsPath("art/materials") / child.GetText().FromUTF8();
282  }
283  }
284 
285  if (m_Material.empty())
286  m_Material = VfsPath("art/materials/default.xml");
287 
288  return true;
289 }
290 
292 {
293  return Load(m_Pathname);
294 }
295 
296 bool CObjectBase::UsesFile(const VfsPath& pathname)
297 {
298  return m_UsedFiles.find(pathname) != m_UsedFiles.end();
299 }
300 
301 std::vector<u8> CObjectBase::CalculateVariationKey(const std::vector<std::set<CStr> >& selections)
302 {
303  // (TODO: see CObjectManager::FindObjectVariation for an opportunity to
304  // call this function a bit less frequently)
305 
306  // Calculate a complete list of choices, one per group, based on the
307  // supposedly-complete selections (i.e. not making random choices at this
308  // stage).
309  // In each group, if one of the variants has a name matching a string in the
310  // first 'selections', set use that one.
311  // Otherwise, try with the next (lower priority) selections set, and repeat.
312  // Otherwise, choose the first variant (arbitrarily).
313 
314  std::vector<u8> choices;
315 
316  std::multimap<CStr, CStrW> chosenProps;
317 
318  for (std::vector<std::vector<CObjectBase::Variant> >::iterator grp = m_VariantGroups.begin();
319  grp != m_VariantGroups.end();
320  ++grp)
321  {
322  // Ignore groups with nothing inside. (A warning will have been
323  // emitted by the loading code.)
324  if (grp->size() == 0)
325  continue;
326 
327  int match = -1; // -1 => none found yet
328 
329  // If there's only a single variant, choose that one
330  if (grp->size() == 1)
331  {
332  match = 0;
333  }
334  else
335  {
336  // Determine the first variant that matches the provided strings,
337  // starting with the highest priority selections set:
338 
339  for (std::vector<std::set<CStr> >::const_iterator selset = selections.begin(); selset < selections.end(); ++selset)
340  {
341  ENSURE(grp->size() < 256); // else they won't fit in 'choices'
342 
343  for (size_t i = 0; i < grp->size(); ++i)
344  {
345  if (selset->count((*grp)[i].m_VariantName))
346  {
347  match = (u8)i;
348  break;
349  }
350  }
351 
352  // Stop after finding the first match
353  if (match != -1)
354  break;
355  }
356 
357  // If no match, just choose the first
358  if (match == -1)
359  match = 0;
360  }
361 
362  choices.push_back(match);
363 
364  // Remember which props were chosen, so we can call CalculateVariationKey on them
365  // at the end.
366  Variant& var ((*grp)[match]);
367  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
368  {
369  // Erase all existing props which are overridden by this variant:
370  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
371  chosenProps.erase(it->m_PropPointName);
372  // and then insert the new ones:
373  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
374  if (! it->m_ModelName.empty())
375  chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName));
376  }
377  }
378 
379  // Load each prop, and add their CalculateVariationKey to our key:
380  for (std::multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)
381  {
382  CObjectBase* prop = m_ObjectManager.FindObjectBase(it->second);
383  if (prop)
384  {
385  std::vector<u8> propChoices = prop->CalculateVariationKey(selections);
386  choices.insert(choices.end(), propChoices.begin(), propChoices.end());
387  }
388  }
389 
390  return choices;
391 }
392 
393 const CObjectBase::Variation CObjectBase::BuildVariation(const std::vector<u8>& variationKey)
394 {
395  Variation variation;
396 
397  // variationKey should correspond with m_Variants, giving the id of the
398  // chosen variant from each group. (Except variationKey has some bits stuck
399  // on the end for props, but we don't care about those in here.)
400 
401  std::vector<std::vector<CObjectBase::Variant> >::iterator grp = m_VariantGroups.begin();
402  std::vector<u8>::const_iterator match = variationKey.begin();
403  for ( ;
404  grp != m_VariantGroups.end() && match != variationKey.end();
405  ++grp, ++match)
406  {
407  // Ignore groups with nothing inside. (A warning will have been
408  // emitted by the loading code.)
409  if (grp->size() == 0)
410  continue;
411 
412  size_t id = *match;
413  if (id >= grp->size())
414  {
415  // This should be impossible
416  debug_warn(L"BuildVariation: invalid variant id");
417  continue;
418  }
419 
420  // Get the matched variant
421  CObjectBase::Variant& var ((*grp)[id]);
422 
423  // Apply its data:
424 
425  if (! var.m_ModelFilename.empty())
426  variation.model = var.m_ModelFilename;
427 
428  if (var.m_Decal.m_SizeX && var.m_Decal.m_SizeZ)
429  variation.decal = var.m_Decal;
430 
431  if (! var.m_Particles.empty())
432  variation.particles = var.m_Particles;
433 
434  if (! var.m_Color.empty())
435  variation.color = var.m_Color;
436 
437  // If one variant defines one prop attached to e.g. "root", and this
438  // variant defines two different props with the same attachpoint, the one
439  // original should be erased, and replaced by the two new ones.
440  //
441  // So, erase all existing props which are overridden by this variant:
442  for (std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
443  variation.props.erase(it->m_PropPointName);
444  // and then insert the new ones:
445  for (std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
446  if (! it->m_ModelName.empty()) // if the name is empty then the overridden prop is just deleted
447  variation.props.insert(make_pair(it->m_PropPointName, *it));
448 
449  // Same idea applies for animations.
450  // So, erase all existing animations which are overridden by this variant:
451  for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it)
452  variation.anims.erase(it->m_AnimName);
453  // and then insert the new ones:
454  for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it)
455  variation.anims.insert(make_pair(it->m_AnimName, *it));
456 
457  // Same for samplers, though perhaps not strictly necessary:
458  for (std::vector<CObjectBase::Samp>::iterator it = var.m_Samplers.begin(); it != var.m_Samplers.end(); ++it)
459  variation.samplers.erase(it->m_SamplerName);
460  for (std::vector<CObjectBase::Samp>::iterator it = var.m_Samplers.begin(); it != var.m_Samplers.end(); ++it)
461  variation.samplers.insert(make_pair(it->m_SamplerName, *it));
462  }
463 
464  return variation;
465 }
466 
467 std::set<CStr> CObjectBase::CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections)
468 {
469  rng_t rng;
470  rng.seed(seed);
471 
472  std::set<CStr> remainingSelections = CalculateRandomRemainingSelections(rng, std::vector<std::set<CStr> >(1, initialSelections));
473  remainingSelections.insert(initialSelections.begin(), initialSelections.end());
474 
475  return remainingSelections; // now actually a complete set of selections
476 }
477 
478 std::set<CStr> CObjectBase::CalculateRandomRemainingSelections(uint32_t seed, const std::vector<std::set<CStr> >& initialSelections)
479 {
480  rng_t rng;
481  rng.seed(seed);
482  return CalculateRandomRemainingSelections(rng, initialSelections);
483 }
484 
485 std::set<CStr> CObjectBase::CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr> >& initialSelections)
486 {
487  std::set<CStr> remainingSelections;
488  std::multimap<CStr, CStrW> chosenProps;
489 
490  // Calculate a complete list of selections, so there is at least one
491  // (and in most cases only one) per group.
492  // In each group, if one of the variants has a name matching a string in
493  // 'selections', use that one.
494  // If more than one matches, choose randomly from those matching ones.
495  // If none match, choose randomly from all variants.
496  //
497  // When choosing randomly, make use of each variant's frequency. If all
498  // variants have frequency 0, treat them as if they were 1.
499 
500  for (std::vector<std::vector<Variant> >::iterator grp = m_VariantGroups.begin();
501  grp != m_VariantGroups.end();
502  ++grp)
503  {
504  // Ignore groups with nothing inside. (A warning will have been
505  // emitted by the loading code.)
506  if (grp->size() == 0)
507  continue;
508 
509  int match = -1; // -1 => none found yet
510 
511  // If there's only a single variant, choose that one
512  if (grp->size() == 1)
513  {
514  match = 0;
515  }
516  else
517  {
518  // See if a variant (or several, but we only care about the first)
519  // is already matched by the selections we've made, keeping their
520  // priority order into account
521 
522  for (size_t s = 0; s < initialSelections.size(); ++s)
523  {
524  for (size_t i = 0; i < grp->size(); ++i)
525  {
526  if (initialSelections[s].count((*grp)[i].m_VariantName))
527  {
528  match = (int)i;
529  break;
530  }
531  }
532 
533  if (match >= 0)
534  break;
535  }
536 
537  // If there was one, we don't need to do anything now because there's
538  // already something to choose. Otherwise, choose randomly from the others.
539  if (match == -1)
540  {
541  // Sum the frequencies
542  int totalFreq = 0;
543  for (size_t i = 0; i < grp->size(); ++i)
544  totalFreq += (*grp)[i].m_Frequency;
545 
546  // Someone might be silly and set all variants to have freq==0, in
547  // which case we just pretend they're all 1
548  bool allZero = (totalFreq == 0);
549  if (allZero) totalFreq = (int)grp->size();
550 
551  // Choose a random number in the interval [0..totalFreq)
552  int randNum = boost::uniform_int<>(0, totalFreq-1)(rng);
553 
554  // and use that to choose one of the variants
555  for (size_t i = 0; i < grp->size(); ++i)
556  {
557  randNum -= (allZero ? 1 : (*grp)[i].m_Frequency);
558  if (randNum < 0)
559  {
560  remainingSelections.insert((*grp)[i].m_VariantName);
561  // (If this change to 'remainingSelections' interferes with earlier choices, then
562  // we'll get some non-fatal inconsistencies that just break the randomness. But that
563  // shouldn't happen, much.)
564  // (As an example, suppose you have a group with variants "a" and "b", and another
565  // with variants "a" and "c"; now if random selection choses "b" for the first
566  // and "a" for the second, then the selection of "a" from the second group will
567  // cause "a" to be used in the first instead of the "b").
568  match = (int)i;
569  break;
570  }
571  }
572  ENSURE(randNum < 0);
573  // This should always succeed; otherwise it
574  // wouldn't have chosen any of the variants.
575  }
576  }
577 
578  // Remember which props were chosen, so we can call CalculateRandomVariation on them
579  // at the end.
580  Variant& var ((*grp)[match]);
581  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
582  {
583  // Erase all existing props which are overridden by this variant:
584  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
585  chosenProps.erase(it->m_PropPointName);
586  // and then insert the new ones:
587  for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
588  if (! it->m_ModelName.empty())
589  chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName));
590  }
591  }
592 
593  // Load each prop, and add their required selections to ours:
594  for (std::multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)
595  {
596  CObjectBase* prop = m_ObjectManager.FindObjectBase(it->second);
597  if (prop)
598  {
599  std::vector<std::set<CStr> > propInitialSelections = initialSelections;
600  if (!remainingSelections.empty())
601  propInitialSelections.push_back(remainingSelections);
602 
603  std::set<CStr> propRemainingSelections = prop->CalculateRandomRemainingSelections(rng, propInitialSelections);
604  remainingSelections.insert(propRemainingSelections.begin(), propRemainingSelections.end());
605 
606  // Add the prop's used files to our own (recursively) so we can hotload
607  // when any prop is changed
608  m_UsedFiles.insert(prop->m_UsedFiles.begin(), prop->m_UsedFiles.end());
609  }
610  }
611 
612  return remainingSelections;
613 }
614 
615 std::vector<std::vector<CStr> > CObjectBase::GetVariantGroups() const
616 {
617  std::vector<std::vector<CStr> > groups;
618 
619  // Queue of objects (main actor plus props (recursively)) to be processed
620  std::queue<const CObjectBase*> objectsQueue;
621  objectsQueue.push(this);
622 
623  // Set of objects already processed, so we don't do them more than once
624  std::set<const CObjectBase*> objectsProcessed;
625 
626  while (!objectsQueue.empty())
627  {
628  const CObjectBase* obj = objectsQueue.front();
629  objectsQueue.pop();
630  // Ignore repeated objects (likely to be props)
631  if (objectsProcessed.find(obj) != objectsProcessed.end())
632  continue;
633 
634  objectsProcessed.insert(obj);
635 
636  // Iterate through the list of groups
637  for (size_t i = 0; i < obj->m_VariantGroups.size(); ++i)
638  {
639  // Copy the group's variant names into a new vector
640  std::vector<CStr> group;
641  group.reserve(obj->m_VariantGroups[i].size());
642  for (size_t j = 0; j < obj->m_VariantGroups[i].size(); ++j)
643  group.push_back(obj->m_VariantGroups[i][j].m_VariantName);
644 
645  // If this group is identical to one elsewhere, don't bother listing
646  // it twice.
647  // Linear search is theoretically not very efficient, but hopefully
648  // we don't have enough props for that to matter...
649  bool dupe = false;
650  for (size_t j = 0; j < groups.size(); ++j)
651  {
652  if (groups[j] == group)
653  {
654  dupe = true;
655  break;
656  }
657  }
658  if (dupe)
659  continue;
660 
661  // Add non-trivial groups (i.e. not just one entry) to the returned list
662  if (obj->m_VariantGroups[i].size() > 1)
663  groups.push_back(group);
664 
665  // Add all props onto the queue to be considered
666  for (size_t j = 0; j < obj->m_VariantGroups[i].size(); ++j)
667  {
668  const std::vector<Prop>& props = obj->m_VariantGroups[i][j].m_Props;
669  for (size_t k = 0; k < props.size(); ++k)
670  {
671  if (! props[k].m_ModelName.empty())
672  {
673  CObjectBase* prop = m_ObjectManager.FindObjectBase(props[k].m_ModelName.c_str());
674  if (prop)
675  objectsQueue.push(prop);
676  }
677  }
678  }
679  }
680  }
681 
682  return groups;
683 }
#define u8
Definition: types.h:39
bool UsesFile(const VfsPath &pathname)
Returns whether this object (including any possible props) uses the given file.
Definition: ObjectBase.cpp:296
Path VfsPath
VFS path of the form &quot;(dir/)*file?&quot;.
Definition: vfs_path.h:40
VfsPath m_ModelFilename
Definition: ObjectBase.h:94
VfsPath m_Material
Definition: ObjectBase.h:174
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Load from an XML file (with invisible XMB caching).
Definition: Xeromyces.cpp:65
#define LOGERROR
Definition: CLogger.h:35
#define XERO_ITER_ATTR(parent_element, attribute)
Definition: Xeromyces.h:99
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
CObjectBase * FindObjectBase(const CStrW &objname)
bool Load(const VfsPath &pathname)
Initialise this object by loading from the given file.
Definition: ObjectBase.cpp:41
CObjectBase(CObjectManager &objectManager)
Definition: ObjectBase.cpp:34
#define XERO_ITER_EL(parent_element, child_element)
Definition: Xeromyces.h:91
std::vector< Prop > m_Props
Definition: ObjectBase.h:100
#define AT(x)
Path Basename() const
Definition: path.h:166
std::vector< std::vector< Variant > > m_VariantGroups
Definition: ObjectBase.h:184
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
std::vector< u8 > CalculateVariationKey(const std::vector< std::set< CStr > > &selections)
Definition: ObjectBase.cpp:301
std::multimap< CStr, Samp > samplers
Definition: ObjectBase.h:112
Definition: path.h:75
boost::mt19937 rng
Random number generator (Boost Mersenne Twister)
Definition: Noise.cpp:34
std::vector< Anim > m_Anims
Definition: ObjectBase.h:99
const String & string() const
Definition: path.h:123
std::vector< std::vector< CStr > > GetVariantGroups() const
Definition: ObjectBase.cpp:615
std::vector< Samp > m_Samplers
Definition: ObjectBase.h:101
struct CObjectBase::@7 m_Properties
VfsPath m_Pathname
Definition: ObjectBase.h:161
std::multimap< CStr, Prop > props
Definition: ObjectBase.h:110
CObjectManager & m_ObjectManager
Definition: ObjectBase.h:185
CStr8 GetNamedItem(const int AttributeName) const
Definition: XeroXMB.cpp:259
std::string GetElementString(const int ID) const
Definition: XeroXMB.cpp:148
bool empty() const
Definition: path.h:118
XMBElement GetRoot() const
Definition: XeroXMB.cpp:84
std::set< CStr > CalculateRandomVariation(uint32_t seed, const std::set< CStr > &initialSelections)
Definition: ObjectBase.cpp:467
bool Reload()
Reload this object from the file that it was previously loaded from.
Definition: ObjectBase.cpp:291
std::multimap< CStr, Anim > anims
Definition: ObjectBase.h:111
unsigned int uint32_t
Definition: wposix_types.h:53
const Variation BuildVariation(const std::vector< u8 > &variationKey)
Definition: ObjectBase.cpp:393
boost::mt19937 rng_t
Definition: ObjectBase.h:180
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:324
#define DEGTORAD(a)
Definition: MathUtil.h:21
PIVFS g_VFS
Definition: Filesystem.cpp:30
#define EL(x)
CStrW m_ShortName
Definition: ObjectBase.h:164
std::set< CStr > CalculateRandomRemainingSelections(uint32_t seed, const std::vector< std::set< CStr > > &initialSelections)
Definition: ObjectBase.cpp:478
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
boost::unordered_set< VfsPath > m_UsedFiles
Definition: ObjectBase.h:187
int GetNodeName() const
Definition: XeroXMB.cpp:166