Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ObjectEntry.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 "ObjectEntry.h"
21 
22 #include "graphics/Decal.h"
23 #include "graphics/Material.h"
25 #include "graphics/MeshManager.h"
26 #include "graphics/Model.h"
27 #include "graphics/ModelDef.h"
28 #include "graphics/ObjectBase.h"
29 #include "graphics/ObjectManager.h"
31 #include "graphics/SkeletonAnim.h"
33 #include "lib/rand.h"
34 #include "ps/CLogger.h"
35 #include "ps/Game.h"
36 #include "ps/World.h"
37 #include "renderer/Renderer.h"
39 
40 #include <sstream>
41 
43  m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f), m_Model(NULL), m_Outdated(false), m_Simulation(simulation)
44 {
45 }
46 
47 template<typename T, typename S> static void delete_pair_2nd(std::pair<T,S> v) { delete v.second; }
48 
50 {
51  std::for_each(m_Animations.begin(), m_Animations.end(), delete_pair_2nd<CStr, CSkeletonAnim*>);
52 
53  delete m_Model;
54 }
55 
56 
57 bool CObjectEntry::BuildVariation(const std::vector<std::set<CStr> >& selections,
58  const std::vector<u8>& variationKey,
59  CObjectManager& objectManager)
60 {
61  CObjectBase::Variation variation = m_Base->BuildVariation(variationKey);
62 
63  // Copy the chosen data onto this model:
64 
65  for (std::multimap<CStr, CObjectBase::Samp>::iterator it = variation.samplers.begin(); it != variation.samplers.end(); ++it)
66  m_Samplers.push_back(it->second);
67 
68  m_ModelName = variation.model;
69 
70  if (! variation.color.empty())
71  {
72  std::stringstream str;
73  str << variation.color;
74  int r, g, b;
75  if (! (str >> r >> g >> b)) // Any trailing data is ignored
76  LOGERROR(L"Actor '%ls' has invalid RGB colour '%hs'", m_Base->m_ShortName.c_str(), variation.color.c_str());
77  else
78  m_Color = CColor(r/255.0f, g/255.0f, b/255.0f, 1.0f);
79  }
80 
81  if (variation.decal.m_SizeX && variation.decal.m_SizeZ)
82  {
83  CMaterial material = g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material);
84 
85  std::vector<CObjectBase::Samp>::iterator samp;
86  for (samp = m_Samplers.begin(); samp != m_Samplers.end(); ++samp)
87  {
88  CTextureProperties textureProps(samp->m_SamplerFile);
89  textureProps.SetWrap(GL_CLAMP_TO_BORDER);
90  CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
91  // TODO: Should check which renderpath is selected and only preload the necessary textures.
92  texture->Prefetch();
93  material.AddSampler(CMaterial::TextureSampler(samp->m_SamplerName, texture));
94  }
95 
96  SDecal decal(material,
97  variation.decal.m_SizeX, variation.decal.m_SizeZ,
98  variation.decal.m_Angle, variation.decal.m_OffsetX, variation.decal.m_OffsetZ,
100  m_Model = new CModelDecal(objectManager.GetTerrain(), decal);
101 
102  return true;
103  }
104 
105  if (!variation.particles.empty())
106  {
107  m_Model = new CModelParticleEmitter(g_Renderer.GetParticleManager().LoadEmitterType(variation.particles));
108  return true;
109  }
110 
111  std::vector<CObjectBase::Prop> props;
112 
113  for (std::multimap<CStr, CObjectBase::Prop>::iterator it = variation.props.begin(); it != variation.props.end(); ++it)
114  props.push_back(it->second);
115 
116  // Build the model:
117 
118  // try and create a model
119  CModelDefPtr modeldef (objectManager.GetMeshManager().GetMesh(m_ModelName));
120  if (!modeldef)
121  {
122  LOGERROR(L"CObjectEntry::BuildVariation(): Model %ls failed to load", m_ModelName.string().c_str());
123  return false;
124  }
125 
126  // delete old model, create new
127  CModel* model = new CModel(objectManager.GetSkeletonAnimManager(), m_Simulation);
128  delete m_Model;
129  m_Model = model;
130  model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material));
131  model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a));
132  model->InitModel(modeldef);
133 
134  if (m_Samplers.size() == 0)
135  {
136  LOGERROR(L"Actor '%ls' has no textures.", m_Base->m_ShortName.c_str());
137  }
138 
139  std::vector<CObjectBase::Samp>::iterator samp;
140  for (samp = m_Samplers.begin(); samp != m_Samplers.end(); ++samp)
141  {
142  CTextureProperties textureProps(samp->m_SamplerFile);
143  textureProps.SetWrap(GL_CLAMP_TO_EDGE);
144  CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
145  // if we've loaded this model we're probably going to render it soon, so prefetch its texture.
146  // All textures are prefetched even in the fixed pipeline, including the normal maps etc.
147  // TODO: Should check which renderpath is selected and only preload the necessary textures.
148  texture->Prefetch();
149  model->GetMaterial().AddSampler(CMaterial::TextureSampler(samp->m_SamplerName, texture));
150  }
151 
152  // calculate initial object space bounds, based on vertex positions
153  model->CalcStaticObjectBounds();
154 
155  // load the animations
156  for (std::multimap<CStr, CObjectBase::Anim>::iterator it = variation.anims.begin(); it != variation.anims.end(); ++it)
157  {
158  CStr name = it->first.LowerCase();
159 
160  // TODO: Use consistent names everywhere, then remove this translation section.
161  // (It's just mapping the names used in actors onto the names used by code.)
162  if (name == "attack") name = "melee";
163  else if (name == "chop") name = "gather";
164  else if (name == "decay") name = "corpse";
165 
166  if (! it->second.m_FileName.empty())
167  {
168  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);
169  if (anim)
170  m_Animations.insert(std::make_pair(name, anim));
171  }
172  }
173 
174  // ensure there's always an idle animation
175  if (m_Animations.find("idle") == m_Animations.end())
176  {
177  CSkeletonAnim* anim = new CSkeletonAnim();
178  anim->m_Name = "idle";
179  anim->m_AnimDef = NULL;
180  anim->m_Speed = 0.f;
181  anim->m_ActionPos = 0.f;
182  anim->m_ActionPos2 = 0.f;
183  anim->m_SoundPos = 0.f;
184  m_Animations.insert(std::make_pair("idle", anim));
185 
186  // Ignore errors, since they're probably saying this is a non-animated model
187  model->SetAnimation(anim);
188  }
189  else
190  {
191  // start up idling
192  if (!model->SetAnimation(GetRandomAnimation("idle")))
193  LOGERROR(L"Failed to set idle animation in model \"%ls\"", m_ModelName.string().c_str());
194  }
195 
196  // build props - TODO, RC - need to fix up bounds here
197  // TODO: Make sure random variations get handled correctly when a prop fails
198  for (size_t p = 0; p < props.size(); p++)
199  {
200  const CObjectBase::Prop& prop = props[p];
201 
202  // Pluck out the special attachpoint 'projectile'
203  if (prop.m_PropPointName == "projectile")
204  {
206  continue;
207  }
208 
209  CObjectEntry* oe = objectManager.FindObjectVariation(prop.m_ModelName.c_str(), selections);
210  if (!oe)
211  {
212  LOGERROR(L"Failed to build prop model \"%ls\" on actor \"%ls\"", prop.m_ModelName.c_str(), m_Base->m_ShortName.c_str());
213  continue;
214  }
215 
216  // If we don't have a projectile but this prop does (e.g. it's our rider), then
217  // use that as our projectile too
218  if (m_ProjectileModelName.empty() && !oe->m_ProjectileModelName.empty())
220 
221  CStr ppn = prop.m_PropPointName;
222  bool isAmmo = false;
223 
224  // Handle the special attachpoint 'loaded-<proppoint>'
225  if (ppn.Find("loaded-") == 0)
226  {
227  ppn = prop.m_PropPointName.substr(7);
228  isAmmo = true;
229  }
230 
231  const SPropPoint* proppoint = modeldef->FindPropPoint(ppn.c_str());
232  if (proppoint)
233  {
234  CModelAbstract* propmodel = oe->m_Model->Clone();
235  if (isAmmo)
236  model->AddAmmoProp(proppoint, propmodel, oe);
237  else
238  model->AddProp(proppoint, propmodel, oe, prop.m_minHeight, prop.m_maxHeight);
239  if (propmodel->ToCModel())
240  propmodel->ToCModel()->SetAnimation(oe->GetRandomAnimation("idle"));
241  }
242  else
243  LOGERROR(L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str());
244  }
245 
246  // setup flags
248  {
249  model->SetFlags(model->GetFlags()|MODELFLAG_CASTSHADOWS);
250  }
251 
252  return true;
253 }
254 
255 CSkeletonAnim* CObjectEntry::GetRandomAnimation(const CStr& animationName) const
256 {
257  SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound(animationName);
258  SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound(animationName);
259  size_t count = std::distance(lower, upper);
260  if (count == 0)
261  return NULL;
262 
263  size_t id = rand(0, count);
264  std::advance(lower, id);
265  return lower->second;
266 }
267 
268 std::vector<CSkeletonAnim*> CObjectEntry::GetAnimations(const CStr& animationName) const
269 {
270  std::vector<CSkeletonAnim*> anims;
271 
272  SkeletonAnimMap::const_iterator lower = m_Animations.lower_bound(animationName);
273  SkeletonAnimMap::const_iterator upper = m_Animations.upper_bound(animationName);
274  for (SkeletonAnimMap::const_iterator it = lower; it != upper; ++it)
275  anims.push_back(it->second);
276  return anims;
277 }
bool BuildVariation(const std::vector< std::set< CStr > > &selections, const std::vector< u8 > &variationKey, CObjectManager &objectManager)
Definition: ObjectEntry.cpp:57
float g
Definition: Overlay.h:57
Describes the position of a prop point within its parent model.
Definition: ModelDef.h:48
VfsPath m_Material
Definition: ObjectBase.h:174
std::wstring m_ProjectileModelName
Definition: ObjectEntry.h:64
#define LOGERROR
Definition: CLogger.h:35
Definition: Overlay.h:34
CObjectBase * m_Base
Definition: ObjectEntry.h:52
Represents the filename and GL parameters of a texture, for passing to CTextureManager::CreateTexture...
void AddSampler(const TextureSampler &texture)
Definition: Material.cpp:52
std::vector< CObjectBase::Samp > m_Samplers
Definition: ObjectEntry.h:55
virtual CModelAbstract * Clone() const =0
CSkeletonAnimDef * m_AnimDef
Definition: SkeletonAnim.h:38
float m_ActionPos2
Definition: SkeletonAnim.h:48
CSkeletonAnimManager & GetSkeletonAnimManager() const
Definition: ObjectManager.h:64
Public API for simulation system.
Definition: Simulation2.h:46
#define g_Renderer
Definition: Renderer.h:61
CTerrain * GetTerrain()
Get the terrain object that actors managed by this manager should be linked with (primarily for the p...
CMeshManager & GetMeshManager() const
Definition: ObjectManager.h:63
CSkeletonAnim * BuildAnimation(const VfsPath &pathname, const CStr &name, float speed, float actionpos, float actionpos2, float soundpos)
Load raw animation frame animation from given file, and build an animation specific to this model...
Definition: Model.cpp:258
CObjectEntry * FindObjectVariation(const CStrW &objname, const std::vector< std::set< CStr > > &selections)
bool SetAnimation(CSkeletonAnim *anim, bool once=false)
Definition: Model.cpp:449
float b
Definition: Overlay.h:57
std::multimap< CStr, Samp > samplers
Definition: ObjectBase.h:112
bool InitModel(const CModelDefPtr &modeldef)
Definition: Model.cpp:76
const String & string() const
Definition: path.h:123
VfsPath m_ModelName
Definition: ObjectEntry.h:57
struct CObjectBase::@7 m_Properties
float a
Definition: Overlay.h:57
CSkeletonAnim * GetRandomAnimation(const CStr &animationName) const
Terrain decal definition.
Definition: Decal.h:32
std::multimap< CStr, Prop > props
Definition: ObjectBase.h:110
void AddProp(const SPropPoint *point, CModelAbstract *model, CObjectEntry *objectentry, float minHeight=0.f, float maxHeight=0.f)
Add a prop to the model on the given point.
Definition: Model.cpp:511
void AddAmmoProp(const SPropPoint *point, CModelAbstract *model, CObjectEntry *objectentry)
Add a prop to the model on the given point, and treat it as the ammo prop.
Definition: Model.cpp:528
#define MODELFLAG_CASTSHADOWS
Definition: Model.h:40
float m_SoundPos
Definition: SkeletonAnim.h:49
CColor m_Color
Definition: ObjectEntry.h:59
SkeletonAnimMap m_Animations
Definition: ObjectEntry.h:84
float m_ActionPos
Definition: SkeletonAnim.h:47
bool empty() const
Definition: path.h:118
CObjectEntry(CObjectBase *base, CSimulation2 &simulation)
Definition: ObjectEntry.cpp:42
static void delete_pair_2nd(std::pair< T, S > v)
Definition: ObjectEntry.cpp:47
Abstract base class for graphical objects that are used by units, or as props attached to other CMode...
Definition: ModelAbstract.h:36
std::multimap< CStr, Anim > anims
Definition: ObjectBase.h:111
static size_t model
Definition: x86_x64.cpp:211
std::vector< CSkeletonAnim * > GetAnimations(const CStr &animationName) const
CModelAbstract * m_Model
Definition: ObjectEntry.h:74
CModelDefPtr GetMesh(const VfsPath &pathname)
Definition: MeshManager.cpp:41
bool m_CastShadows
Definition: ObjectBase.h:168
const Variation BuildVariation(const std::vector< u8 > &variationKey)
Definition: ObjectBase.cpp:393
virtual CModel * ToCModel()
Dynamic cast.
Definition: ModelAbstract.h:76
bool m_FloatOnWater
Definition: ObjectBase.h:170
Particle emitter model, for attaching emitters as props on other models.
void CalcStaticObjectBounds()
Auxiliary method; calculates object space bounds of this model, based solely on vertex positions...
Definition: Model.cpp:130
Definition: Model.h:50
CMaterial & GetMaterial()
Definition: Model.h:108
size_t rand(size_t min_inclusive, size_t max_exclusive)
return random integer in [min, max).
Definition: rand.cpp:53
void SetWrap(GLint wrap)
Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc).
CStrW m_ShortName
Definition: ObjectBase.h:164
int GetFlags() const
Definition: Model.h:123
CSimulation2 & m_Simulation
Definition: ObjectEntry.h:81
void AddStaticUniform(const char *key, const CVector4D &value)
Definition: Material.cpp:47
void SetFlags(int flags)
Definition: Model.h:121
float r
Definition: Overlay.h:57
void SetMaterial(const CMaterial &material)
Definition: Model.cpp:655
boost::shared_ptr< CModelDef > CModelDefPtr
Definition: MeshManager.h:27
shared_ptr< CTexture > CTexturePtr
Definition: Texture.h:22