Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
CCmpVisualActor.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 
21 #include "ICmpVisual.h"
22 
24 
25 #include "ICmpFootprint.h"
26 #include "ICmpOwnership.h"
27 #include "ICmpPosition.h"
28 #include "ICmpRangeManager.h"
29 #include "ICmpSelectable.h"
30 #include "ICmpTemplateManager.h"
31 #include "ICmpTerrain.h"
32 #include "ICmpUnitMotion.h"
33 #include "ICmpVision.h"
34 
35 #include "graphics/Decal.h"
36 #include "graphics/Frustum.h"
37 #include "graphics/Model.h"
38 #include "graphics/ObjectBase.h"
39 #include "graphics/ObjectEntry.h"
40 #include "graphics/Unit.h"
41 #include "graphics/UnitAnimation.h"
42 #include "graphics/UnitManager.h"
43 #include "maths/Matrix3D.h"
44 #include "maths/Vector3D.h"
45 #include "ps/CLogger.h"
46 #include "renderer/Scene.h"
47 
48 #include "tools/atlas/GameInterface/GameLoop.h"
49 
51 {
52 public:
53  static void ClassInit(CComponentManager& componentManager)
54  {
55  componentManager.SubscribeToMessageType(MT_Update_Final);
56  componentManager.SubscribeToMessageType(MT_Interpolate);
57  componentManager.SubscribeToMessageType(MT_RenderSubmit);
60  }
61 
63 
64 private:
65  std::wstring m_ActorName;
67 
68  fixed m_R, m_G, m_B; // shading colour
69 
70  std::map<std::string, std::string> m_AnimOverride;
71 
72  ICmpRangeManager::ELosVisibility m_Visibility; // only valid between Interpolate and RenderSubmit
73 
74  // Current animation state
75  fixed m_AnimRunThreshold; // if non-zero this is the special walk/run mode
76  std::string m_AnimName;
77  bool m_AnimOnce;
79  std::wstring m_SoundGroup;
81  fixed m_AnimSyncRepeatTime; // 0.0 if not synced
82 
83  u32 m_Seed; // seed used for random variations
84 
87 
89 
90  /// Whether the visual actor has been rendered at least once.
91  /// Necessary because the visibility update runs on simulation update,
92  /// which may not occur immediately if the game starts paused.
94 
95 public:
96  static std::string GetSchema()
97  {
98  return
99  "<a:help>Display the unit using the engine's actor system.</a:help>"
100  "<a:example>"
101  "<Actor>units/hellenes/infantry_spearman_b.xml</Actor>"
102  "</a:example>"
103  "<a:example>"
104  "<Actor>structures/hellenes/barracks.xml</Actor>"
105  "<FoundationActor>structures/fndn_4x4.xml</FoundationActor>"
106  "</a:example>"
107  "<element name='Actor' a:help='Filename of the actor to be used for this unit'>"
108  "<text/>"
109  "</element>"
110  "<optional>"
111  "<element name='FoundationActor' a:help='Filename of the actor to be used the foundation while this unit is being constructed'>"
112  "<text/>"
113  "</element>"
114  "</optional>"
115  "<optional>"
116  "<element name='Foundation' a:help='Used internally; if present, the unit will be rendered as a foundation'>"
117  "<empty/>"
118  "</element>"
119  "</optional>"
120  "<optional>"
121  "<element name='ConstructionPreview' a:help='If present, the unit should have a construction preview'>"
122  "<empty/>"
123  "</element>"
124  "</optional>"
125  "<optional>"
126  "<element name='DisableShadows' a:help='Used internally; if present, shadows will be disabled'>"
127  "<empty/>"
128  "</element>"
129  "</optional>"
130  "<element name='SilhouetteDisplay'>"
131  "<data type='boolean'/>"
132  "</element>"
133  "<element name='SilhouetteOccluder'>"
134  "<data type='boolean'/>"
135  "</element>"
136  "<optional>"
137  "<element name='SelectionShape'>"
138  "<choice>"
139  "<element name='Bounds' a:help='Determines the selection box based on the model bounds'>"
140  "<empty/>"
141  "</element>"
142  "<element name='Footprint' a:help='Determines the selection box based on the entity Footprint component'>"
143  "<empty/>"
144  "</element>"
145  "<element name='Box' a:help='Sets the selection shape to a box of specified dimensions'>"
146  "<attribute name='width'>"
147  "<ref name='positiveDecimal' />"
148  "</attribute>"
149  "<attribute name='height'>"
150  "<ref name='positiveDecimal' />"
151  "</attribute>"
152  "<attribute name='depth'>"
153  "<ref name='positiveDecimal' />"
154  "</attribute>"
155  "</element>"
156  "<element name='Cylinder' a:help='Sets the selection shape to a cylinder of specified dimensions'>"
157  "<attribute name='radius'>"
158  "<ref name='positiveDecimal' />"
159  "</attribute>"
160  "<attribute name='height'>"
161  "<ref name='positiveDecimal' />"
162  "</attribute>"
163  "</element>"
164  "</choice>"
165  "</element>"
166  "</optional>"
167  "<element name='VisibleInAtlasOnly'>"
168  "<data type='boolean'/>"
169  "</element>";
170  }
171 
172  virtual void Init(const CParamNode& paramNode)
173  {
174  m_PreviouslyRendered = false;
175  m_Unit = NULL;
177  m_R = m_G = m_B = fixed::FromInt(1);
178 
179  m_ConstructionPreview = paramNode.GetChild("ConstructionPreview").IsOk();
181 
182  m_Seed = GetEntityId();
183 
184  if (paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk())
185  m_ActorName = paramNode.GetChild("FoundationActor").ToString();
186  else
187  m_ActorName = paramNode.GetChild("Actor").ToString();
188 
189  m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool();
190 
191  InitModel(paramNode);
192 
193  // We need to select animation even if graphics are disabled, as this modifies serialized state
194  SelectAnimation("idle", false, fixed::FromInt(1), L"");
195  }
196 
197  virtual void Deinit()
198  {
199  if (m_Unit)
200  {
202  m_Unit = NULL;
203  }
204  }
205 
206  template<typename S>
207  void SerializeCommon(S& serialize)
208  {
209  serialize.NumberFixed_Unbounded("r", m_R);
210  serialize.NumberFixed_Unbounded("g", m_G);
211  serialize.NumberFixed_Unbounded("b", m_B);
212 
213  serialize.NumberFixed_Unbounded("anim run threshold", m_AnimRunThreshold);
214  serialize.StringASCII("anim name", m_AnimName, 0, 256);
215  serialize.Bool("anim once", m_AnimOnce);
216  serialize.NumberFixed_Unbounded("anim speed", m_AnimSpeed);
217  serialize.String("sound group", m_SoundGroup, 0, 256);
218  serialize.NumberFixed_Unbounded("anim desync", m_AnimDesync);
219  serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime);
220 
221  serialize.NumberU32_Unbounded("seed", m_Seed);
222  // TODO: variation/selection strings
223 
224  serialize.NumberFixed_Unbounded("constructionprogress", m_ConstructionProgress);
225 
226  // TODO: store actor variables?
227  }
228 
229  virtual void Serialize(ISerializer& serialize)
230  {
231  // TODO: store the actor name, if !debug and it differs from the template
232 
233  if (serialize.IsDebug())
234  {
235  serialize.String("actor", m_ActorName, 0, 256);
236  }
237 
238  SerializeCommon(serialize);
239  }
240 
241  virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
242  {
243  Init(paramNode);
244 
245  u32 oldSeed = GetActorSeed();
246 
247  SerializeCommon(deserialize);
248 
249  // If we serialized a different seed, reload actor
250  if (oldSeed != GetActorSeed())
251  ReloadActor();
252 
253  fixed repeattime = m_AnimSyncRepeatTime; // save because SelectAnimation overwrites it
254 
257  else
259 
260  SetAnimationSyncRepeat(repeattime);
261 
262  if (m_Unit)
263  {
264  CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
265  if (cmpOwnership)
266  m_Unit->GetModel().SetPlayerID(cmpOwnership->GetOwner());
267  }
268  }
269 
270  virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
271  {
272  // Quick exit for running in non-graphical mode
273  if (m_Unit == NULL)
274  return;
275 
276  switch (msg.GetType())
277  {
278  case MT_Update_Final:
279  {
280  const CMessageUpdate_Final& msgData = static_cast<const CMessageUpdate_Final&> (msg);
281  Update(msgData.turnLength);
282  break;
283  }
284  case MT_Interpolate:
285  {
286  const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg);
287  Interpolate(msgData.deltaSimTime, msgData.offset);
288  break;
289  }
290  case MT_RenderSubmit:
291  {
292  const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg);
293  RenderSubmit(msgData.collector, msgData.frustum, msgData.culling);
294  break;
295  }
296  case MT_OwnershipChanged:
297  {
298  const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
299  m_Unit->GetModel().SetPlayerID(msgData.to);
300  break;
301  }
302  case MT_TerrainChanged:
303  {
304  const CMessageTerrainChanged& msgData = static_cast<const CMessageTerrainChanged&> (msg);
305  m_Unit->GetModel().SetTerrainDirty(msgData.i0, msgData.j0, msgData.i1, msgData.j1);
306  break;
307  }
308  }
309  }
310 
312  {
313  if (!m_Unit)
315  return m_Unit->GetModel().GetWorldBounds();
316  }
317 
318  virtual CUnit* GetUnit()
319  {
320  return m_Unit;
321  }
322 
324  {
325  if (!m_Unit)
327  return m_Unit->GetModel().GetSelectionBox();
328  }
329 
331  {
332  if (!m_Unit)
333  return CVector3D(0, 0, 0);
335  }
336 
337  virtual std::wstring GetActorShortName()
338  {
339  if (!m_Unit)
340  return L"";
341  return m_Unit->GetObject().m_Base->m_ShortName;
342  }
343 
344  virtual std::wstring GetProjectileActor()
345  {
346  if (!m_Unit)
347  return L"";
349  }
350 
352  {
353  if (!m_Unit)
354  return CVector3D();
355 
356  if (m_Unit->GetModel().ToCModel())
357  {
358  // Ensure the prop transforms are correct
360 
362  if (ammo)
363  return ammo->GetTransform().GetTranslation();
364  }
365 
366  return CVector3D();
367  }
368 
369  virtual void SelectAnimation(std::string name, bool once, fixed speed, std::wstring soundgroup)
370  {
372  m_AnimName = name;
373  m_AnimOnce = once;
374  m_AnimSpeed = speed;
375  m_SoundGroup = soundgroup;
376  m_AnimDesync = fixed::FromInt(1)/20; // TODO: make this an argument
378 
379  if (m_Unit)
380  {
382  if (m_Unit->GetAnimation())
384  }
385  }
386 
387  virtual void ReplaceMoveAnimation(std::string name, std::string replace)
388  {
389  m_AnimOverride[name] = replace;
390  }
391 
392  virtual void ResetMoveAnimation(std::string name)
393  {
394  std::map<std::string, std::string>::const_iterator it = m_AnimOverride.find(name);
395  if (it != m_AnimOverride.end())
396  m_AnimOverride.erase(name);
397  }
398 
399  virtual void SetUnitEntitySelection(const CStr& selection)
400  {
401  if (m_Unit)
402  {
403  m_Unit->SetEntitySelection(selection);
404  }
405  }
406 
407  virtual void SelectMovementAnimation(fixed runThreshold)
408  {
409  m_AnimRunThreshold = runThreshold;
410 
411  if (m_Unit)
412  {
413  m_Unit->SetEntitySelection("walk");
414  if (m_Unit->GetAnimation())
415  m_Unit->GetAnimation()->SetAnimationState("walk", false, 1.f, 0.f, L"");
416  }
417  }
418 
419  virtual void SetAnimationSyncRepeat(fixed repeattime)
420  {
421  m_AnimSyncRepeatTime = repeattime;
422 
423  if (m_Unit)
424  {
425  if (m_Unit->GetAnimation())
427  }
428  }
429 
430  virtual void SetAnimationSyncOffset(fixed actiontime)
431  {
432  if (m_Unit)
433  {
434  if (m_Unit->GetAnimation())
436  }
437  }
438 
439  virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a)
440  {
441  m_R = r;
442  m_G = g;
443  m_B = b;
444  UNUSED2(a); // TODO: why is this even an argument?
445  }
446 
447  virtual void SetVariable(std::string name, float value)
448  {
449  if (m_Unit)
450  {
451  m_Unit->GetModel().SetEntityVariable(name, value);
452  }
453  }
454 
455  virtual u32 GetActorSeed()
456  {
457  return m_Seed;
458  }
459 
460  virtual void SetActorSeed(u32 seed)
461  {
462  if (seed == m_Seed)
463  return;
464 
465  m_Seed = seed;
466  ReloadActor();
467  }
468 
469  virtual bool HasConstructionPreview()
470  {
471  return m_ConstructionPreview;
472  }
473 
474  virtual void SetConstructionProgress(fixed progress)
475  {
476  m_ConstructionProgress = progress;
477  }
478 
479  virtual void Hotload(const VfsPath& name)
480  {
481  if (!m_Unit)
482  return;
483 
484  if (name != m_ActorName)
485  return;
486 
487  ReloadActor();
488  }
489 
490 private:
491  /// Helper function shared by component init and actor reloading
492  void InitModel(const CParamNode& paramNode);
493 
494  /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init.
495  void InitSelectionShapeDescriptor(const CParamNode& paramNode);
496 
497  void ReloadActor();
498 
499  void Update(fixed turnLength);
500  void UpdateVisibility();
501  void Interpolate(float frameTime, float frameOffset);
502  void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling);
503 };
504 
505 REGISTER_COMPONENT_TYPE(VisualActor)
506 
507 // ------------------------------------------------------------------------------------------------------------------
508 
509 void CCmpVisualActor::InitModel(const CParamNode& paramNode)
510 {
511  if (GetSimContext().HasUnitManager())
512  {
513  std::set<CStr> selections;
514  m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
515  if (m_Unit)
516  {
517  CModelAbstract& model = m_Unit->GetModel();
518  if (model.ToCModel())
519  {
520  u32 modelFlags = 0;
521 
522  if (paramNode.GetChild("SilhouetteDisplay").ToBool())
523  modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY;
524 
525  if (paramNode.GetChild("SilhouetteOccluder").ToBool())
526  modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER;
527 
528  CmpPtr<ICmpVision> cmpVision(GetEntityHandle());
529  if (cmpVision && cmpVision->GetAlwaysVisible())
530  modelFlags |= MODELFLAG_IGNORE_LOS;
531 
532  model.ToCModel()->AddFlagsRec(modelFlags);
533  }
534 
535  if (paramNode.GetChild("DisableShadows").IsOk())
536  {
537  if (model.ToCModel())
538  model.ToCModel()->RemoveShadowsRec();
539  else if (model.ToCModelDecal())
540  model.ToCModelDecal()->RemoveShadows();
541  }
542 
543  // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the
544  // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint
545  // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in
546  // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just
547  // initialize the selection shape descriptor on-demand.
548  InitSelectionShapeDescriptor(paramNode);
549 
550  m_Unit->SetID(GetEntityId());
551  }
552  }
553 }
554 
556 {
557  // by default, we don't need a custom selection shape and we can just keep the default behaviour
558  CModelAbstract::CustomSelectionShape* shapeDescriptor = NULL;
559 
560  const CParamNode& shapeNode = paramNode.GetChild("SelectionShape");
561  if (shapeNode.IsOk())
562  {
563  if (shapeNode.GetChild("Bounds").IsOk())
564  {
565  // default; no need to take action
566  }
567  else if (shapeNode.GetChild("Footprint").IsOk())
568  {
569  CmpPtr<ICmpFootprint> cmpFootprint(GetEntityHandle());
570  if (cmpFootprint)
571  {
572  ICmpFootprint::EShape fpShape; // fp stands for "footprint"
573  entity_pos_t fpSize0, fpSize1, fpHeight; // fp stands for "footprint"
574  cmpFootprint->GetShape(fpShape, fpSize0, fpSize1, fpHeight);
575 
576  float size0 = fpSize0.ToFloat();
577  float size1 = fpSize1.ToFloat();
578 
579  // TODO: we should properly distinguish between CIRCLE and SQUARE footprint shapes here, but since cylinders
580  // aren't implemented yet and are almost indistinguishable from boxes for small enough sizes anyway,
581  // we'll just use boxes for either case. However, for circular footprints the size0 and size1 values both
582  // represent the radius, so we do have to adjust them to match the size1 and size0's of square footprints
583  // (which represent the full width and depth).
584  if (fpShape == ICmpFootprint::CIRCLE)
585  {
586  size0 *= 2;
587  size1 *= 2;
588  }
589 
590  shapeDescriptor = new CModelAbstract::CustomSelectionShape;
592  shapeDescriptor->m_Size0 = size0;
593  shapeDescriptor->m_Size1 = size1;
594  shapeDescriptor->m_Height = fpHeight.ToFloat();
595  }
596  else
597  {
598  LOGERROR(L"[VisualActor] Cannot apply footprint-based SelectionShape; Footprint component not initialized.");
599  }
600  }
601  else if (shapeNode.GetChild("Box").IsOk())
602  {
603  // TODO: we might need to support the ability to specify a different box center in the future
604  shapeDescriptor = new CModelAbstract::CustomSelectionShape;
606  shapeDescriptor->m_Size0 = shapeNode.GetChild("Box").GetChild("@width").ToFixed().ToFloat();
607  shapeDescriptor->m_Size1 = shapeNode.GetChild("Box").GetChild("@depth").ToFixed().ToFloat();
608  shapeDescriptor->m_Height = shapeNode.GetChild("Box").GetChild("@height").ToFixed().ToFloat();
609  }
610  else if (shapeNode.GetChild("Cylinder").IsOk())
611  {
612  LOGWARNING(L"[VisualActor] TODO: Cylinder selection shapes are not yet implemented; defaulting to recursive bounding boxes");
613  }
614  else
615  {
616  // shouldn't happen by virtue of validation against schema
617  LOGERROR(L"[VisualActor] No selection shape specified");
618  }
619  }
620 
621  ENSURE(m_Unit);
622  // the model is now responsible for cleaning up the descriptor
623  m_Unit->GetModel().SetCustomSelectionShape(shapeDescriptor);
624 }
625 
627 {
628  if (!m_Unit)
629  return;
630 
631  std::set<CStr> selections;
632  CUnit* newUnit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
633 
634  if (!newUnit)
635  return;
636 
637  // Save some data from the old unit
638  CColor shading = m_Unit->GetModel().GetShadingColor();
639  player_id_t playerID = m_Unit->GetModel().GetPlayerID();
640 
641  // Replace with the new unit
643 
644  // HACK: selection shape needs template data, but rather than storing all that data
645  // in the component, we load the template here and pass it into a helper function
646  CmpPtr<ICmpTemplateManager> cmpTemplateManager(GetSystemEntity());
647  const CParamNode* node = cmpTemplateManager->LoadLatestTemplate(GetEntityId());
648  ENSURE(node && node->GetChild("VisualActor").IsOk());
649 
650  InitModel(node->GetChild("VisualActor"));
651 
653  if (m_Unit->GetAnimation())
655 
656  // We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate
658  if (m_Unit->GetAnimation())
660 
661  m_Unit->GetModel().SetShadingColor(shading);
662 
663  m_Unit->GetModel().SetPlayerID(playerID);
664 }
665 
667 {
668  if (m_Unit == NULL)
669  return;
670 
672 
673  // If we're in the special movement mode, select an appropriate animation
674  if (!m_AnimRunThreshold.IsZero())
675  {
676  CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
677  if (!cmpPosition || !cmpPosition->IsInWorld())
678  return;
679 
680  CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetEntityHandle());
681  if (!cmpUnitMotion)
682  return;
683 
684  float speed = cmpUnitMotion->GetCurrentSpeed().ToFloat();
685 
686  std::string name;
687  if (speed == 0.0f)
688  name = "idle";
689  else
690  name = (speed < m_AnimRunThreshold.ToFloat()) ? "walk" : "run";
691 
692  std::map<std::string, std::string>::const_iterator it = m_AnimOverride.find(name);
693  if (it != m_AnimOverride.end())
694  name = it->second;
695 
696  m_Unit->SetEntitySelection(name);
697  if (speed == 0.0f)
698  {
699  m_Unit->SetEntitySelection(name);
700  if (m_Unit->GetAnimation())
701  m_Unit->GetAnimation()->SetAnimationState(name, false, 1.f, 0.f, L"");
702  }
703  else
704  {
705  m_Unit->SetEntitySelection(name);
706  if (m_Unit->GetAnimation())
707  m_Unit->GetAnimation()->SetAnimationState(name, false, speed, 0.f, L"");
708  }
709  }
710 }
711 
713 {
715  CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
716  if (cmpPosition && cmpPosition->IsInWorld())
717  {
718  // The 'always visible' flag means we should always render the unit
719  // (regardless of whether the LOS system thinks it's visible)
720  CmpPtr<ICmpVision> cmpVision(GetEntityHandle());
721  if (cmpVision && cmpVision->GetAlwaysVisible())
723  else
724  {
725  CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity());
726  // Uncomment the following lines to prevent the models from popping into existence
727  // near the LOS boundary. Is rather resource intensive.
728  //if (cmpVision->GetRetainInFog())
729  // m_Visibility = ICmpRangeManager::VIS_VISIBLE;
730  //else
731  m_Visibility = cmpRangeManager->GetLosVisibility(GetEntityHandle(),
732  GetSimContext().GetCurrentDisplayedPlayer());
733  }
734  }
735  else
737 
738  if (m_Visibility != oldVisibility)
739  {
740  // Change the visibility of the visual actor's selectable if it has one.
741  CmpPtr<ICmpSelectable> cmpSelectable(GetEntityHandle());
742  if (cmpSelectable)
743  cmpSelectable->SetVisibility(m_Visibility == ICmpRangeManager::VIS_HIDDEN ? false : true);
744  }
745 }
746 
747 void CCmpVisualActor::Interpolate(float frameTime, float frameOffset)
748 {
749  if (m_Unit == NULL)
750  return;
751 
752  // Disable rendering of the unit if it has no position
753  CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
754  if (!cmpPosition || !cmpPosition->IsInWorld())
755  return;
756  else if (!m_PreviouslyRendered)
757  {
759  m_PreviouslyRendered = true;
760  }
761 
762  // Even if HIDDEN due to LOS, we need to set up the transforms
763  // so that projectiles will be launched from the right place
764 
765  bool floating = m_Unit->GetObject().m_Base->m_Properties.m_FloatOnWater;
766 
767  CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset, floating));
768 
770  {
771  // We use selection boxes to calculate the model size, since the model could be offset
772  // TODO: this annoyingly shows decals, would be nice to hide them
774  if (!bounds.IsEmpty())
775  {
776  float dy = 2.0f * bounds.m_HalfSizes.Y;
777 
778  // If this is a floating unit, we want it to start all the way under the terrain,
779  // so find the difference between its current position and the terrain
780 
781  CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity());
782  if (floating && cmpTerrain)
783  {
784  CVector3D pos = transform.GetTranslation();
785  float ground = cmpTerrain->GetExactGroundLevel(pos.X, pos.Z);
786  dy += std::max(0.f, pos.Y - ground);
787  }
788 
789  transform.Translate(0.0f, (m_ConstructionProgress.ToFloat() - 1.0f) * dy, 0.0f);
790  }
791  }
792 
794 
795  model.SetTransform(transform);
796  m_Unit->UpdateModel(frameTime);
797 
798  // If not hidden, then we need to set up some extra state for rendering
800  {
801  model.ValidatePosition();
802  model.SetShadingColor(CColor(m_R.ToFloat(), m_G.ToFloat(), m_B.ToFloat(), 1.0f));
803  }
804 }
805 
806 void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling)
807 {
808  if (m_Unit == NULL)
809  return;
810 
812  return;
813 
815 
816  if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetWorldBoundsRec()))
817  return;
818 
819  if (!g_AtlasGameLoop->running && m_VisibleInAtlasOnly)
820  return;
821 
822  collector.SubmitRecursive(&model);
823 }
An entity initialisation parameter node.
Definition: ParamNode.h:112
virtual void HandleMessage(const CMessage &msg, bool global)
void SubscribeToMessageType(MessageTypeId mtid)
Subscribe the current component type to the given message type.
A simple fixed-point number class.
Definition: Fixed.h:115
virtual CVector3D GetProjectileLaunchPoint()
Return the exact position where a projectile should be launched from (based on the actor&#39;s ammo prop ...
std::string m_AnimName
#define REGISTER_COMPONENT_TYPE(cname)
Definition: Component.h:30
virtual void ResetMoveAnimation(std::string name)
Ensures that the given animation will be used when it normally would be, removing reference to any an...
virtual void Hotload(const VfsPath &name)
Called when an actor file has been modified and reloaded dynamically.
const CFrustum & frustum
Definition: MessageTypes.h:156
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
float m_Size0
Box width if BOX, or radius if CYLINDER.
Definition: ModelAbstract.h:56
bool ToBool() const
Parses the content of this node as a boolean (&quot;true&quot; == true, anything else == false) ...
Definition: ParamNode.cpp:236
virtual void SetPlayerID(player_id_t id)
static CFixed Zero()
Definition: Fixed.h:127
std::wstring m_ProjectileModelName
Definition: ObjectEntry.h:64
float m_Height
Box height if BOX, cylinder height if CYLINDER.
Definition: ModelAbstract.h:58
const std::wstring & ToString() const
Returns the content of this node as a string.
Definition: ParamNode.cpp:198
#define LOGERROR
Definition: CLogger.h:35
virtual bool IsDebug() const
Returns true if the serializer is being used in debug mode.
static const CBoundingBoxAligned EMPTY
float m_Size1
Box depth if BOX, or radius if CYLINDER.
Definition: ModelAbstract.h:57
void DeleteUnit(CUnit *unit)
Definition: UnitManager.cpp:72
void SetEntitySelection(const CStr &selection)
Definition: Unit.cpp:80
void Interpolate(float frameTime, float frameOffset)
bool IsOk() const
Returns true if this is a valid CParamNode, false if it represents a non-existent node...
Definition: ParamNode.cpp:193
virtual void SelectAnimation(std::string name, bool once, fixed speed, std::wstring soundgroup)
Start playing the given animation.
Definition: Overlay.h:34
Serialization interface; see serialization overview.
Definition: ISerializer.h:120
std::wstring m_SoundGroup
CObjectBase * m_Base
Definition: ObjectEntry.h:52
virtual float GetExactGroundLevel(float x, float z)=0
Add renderable objects to the scene collector.
Definition: MessageTypes.h:145
Sent when terrain (texture or elevation) has been changed.
Definition: MessageTypes.h:282
virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1)=0
Called when terrain has changed in the given inclusive bounds.
virtual const CBoundingBoxOriented & GetSelectionBox()
Returns the world-space selection box of this model.
virtual void SetTransform(const CMatrix3D &transform)
bool IsBoxVisible(const CVector3D &position, const CBoundingBoxAligned &bounds) const
Definition: Frustum.cpp:116
void SetCustomSelectionShape(CustomSelectionShape *descriptor)
Sets a custom selection shape as described by a descriptor.
Provides efficient range-based queries of the game world, and also LOS-based effects (fog of war)...
GameLoopState * g_AtlasGameLoop
virtual bool GetAlwaysVisible()=0
Definition: Unit.h:35
virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating)=0
Get the current interpolated transform matrix, for rendering.
CModelAbstract & GetModel() const
Definition: Unit.h:56
#define MODELFLAG_IGNORE_LOS
Definition: Model.h:44
virtual bool IsInWorld()=0
Returns true if the entity currently exists at a defined position in the world.
virtual void SubmitRecursive(CModelAbstract *model)
Submit a model that is part of the scene, including attached sub-models.
Definition: Scene.cpp:37
float deltaSimTime
Elapsed simulation time since previous interpolate, in seconds.
Definition: MessageTypes.h:134
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog=false)=0
Returns the visibility status of the given entity, with respect to the given player.
virtual bool HasConstructionPreview()
Returns true if this entity should have a construction preview.
int32_t player_id_t
valid player IDs are non-negative (see ICmpOwnership)
Definition: Player.h:24
This interface accepts renderable objects.
Definition: Scene.h:82
Describes a custom selection shape to be used for a model&#39;s selection box instead of the default recu...
Definition: ModelAbstract.h:46
virtual void Serialize(ISerializer &serialize)
#define LOGWARNING
Definition: CLogger.h:34
CEntityHandle GetEntityHandle() const
Definition: IComponent.h:45
fixed ToFixed() const
Parses the content of this node as a fixed-point number.
Definition: ParamNode.cpp:222
void RenderSubmit(SceneCollector &collector, const CFrustum &frustum, bool culling)
bool m_PreviouslyRendered
Whether the visual actor has been rendered at least once.
virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a)
Set the shading colour that will be modulated with the model&#39;s textures.
entity_id_t GetEntityId() const
Definition: IComponent.h:48
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
virtual int GetType() const =0
virtual void ReplaceMoveAnimation(std::string name, std::string replace)
Replaces a specified animation with another.
void RemoveShadowsRec()
Definition: Model.cpp:639
const CParamNode & GetChild(const char *name) const
Returns the (unique) child node with the given name, or a node with IsOk() == false if there is none...
Definition: ParamNode.cpp:185
Final update phase, after all other updates.
Definition: MessageTypes.h:106
virtual CUnit * GetUnit()
Returns the underlying unit of this visual actor.
static std::string GetSchema()
float X
Definition: Vector3D.h:31
virtual void SetUnitEntitySelection(const CStr &selection)
Sets the specified entity selection on the underlying unit.
virtual void SelectMovementAnimation(fixed runThreshold)
Start playing the walk/run animations, scaled to the unit&#39;s movement speed.
Definition: path.h:75
float Y
Definition: Vector3D.h:31
static const CBoundingBoxOriented EMPTY
float ToFloat() const
Convert to float. May be lossy - float can&#39;t represent all values.
Definition: Fixed.h:161
virtual std::wstring GetProjectileActor()
Return the filename of the actor to be used for projectiles from this unit, or the empty string if no...
virtual void SetVariable(std::string name, float value)
Set an arbitrarily-named variable that the model may use to alter its appearance (e.g.
void SerializeCommon(S &serialize)
struct CObjectBase::@7 m_Properties
virtual player_id_t GetOwner()=0
float offset
Range [0, 1] (inclusive); fractional time of current frame between previous/next simulation turns...
Definition: MessageTypes.h:136
static void ClassInit(CComponentManager &componentManager)
void SetAnimationState(const CStr &name, bool once, float speed, float desync, const CStrW &actionSound)
Start playing an animation.
void InitModel(const CParamNode &paramNode)
Helper function shared by component init and actor reloading.
#define DEFAULT_COMPONENT_ALLOCATOR(cname)
Definition: Component.h:44
const CSimContext & GetSimContext() const
Definition: IComponent.h:52
void SubscribeGloballyToMessageType(MessageTypeId mtid)
Subscribe the current component type to all messages of the given message type.
virtual void SetActorSeed(u32 seed)
Set actor seed for random variations and reload model.
CVector3D m_HalfSizes
Half the sizes of the box in each dimension (u,v,w).
std::wstring m_ActorName
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
virtual CVector3D GetPosition()
Get the world-space position of the base point of the object&#39;s visual representation.
void String(const char *name, const std::wstring &value, uint32_t minlength, uint32_t maxlength)
Serialize a Unicode string.
Definition: ISerializer.cpp:82
const CObjectEntry & GetObject() const
Definition: Unit.h:54
virtual player_id_t GetPlayerID() const
virtual void SetEntityVariable(const std::string &name, float value)
Called when the entity tries to set some variable to affect the display of this model and/or its chil...
CEntityHandle GetSystemEntity() const
Definition: IComponent.h:50
static CFixed FromInt(int n)
Definition: Fixed.h:136
#define MODELFLAG_SILHOUETTE_DISPLAY
Definition: Model.h:42
void SetAnimationSyncRepeat(float repeatTime)
Adjust the speed of the current animation, so that Update(repeatTime) will do a complete animation lo...
CModelAbstract * FindFirstAmmoProp()
Find the first prop used for ammo, by this model or its own props.
Definition: Model.cpp:570
virtual void SetConstructionProgress(fixed progress)
Set construction progress of the model, this affects the rendered position of the model...
void Update(fixed turnLength)
#define u32
Definition: types.h:41
Abstract base class for graphical objects that are used by units, or as props attached to other CMode...
Definition: ModelAbstract.h:36
bool IsZero() const
Returns true if the number is precisely 0.
Definition: Fixed.h:199
CUnitManager & GetUnitManager() const
Definition: SimContext.cpp:45
SceneCollector & collector
Definition: MessageTypes.h:155
static size_t model
Definition: x86_x64.cpp:211
virtual fixed GetCurrentSpeed()=0
Get the current movement speed.
virtual void Deinit()
virtual void SetVisibility(bool visible)=0
Enables or disables rendering of an entity&#39;s selectable.
bool m_FloatOnWater
Definition: ObjectBase.h:170
virtual CModel * ToCModel()
Dynamic cast.
Definition: ModelAbstract.h:76
float Z
Definition: Vector3D.h:31
CUnit * CreateUnit(const CStrW &actorName, uint32_t seed, const std::set< CStr8 > &selections)
Definition: UnitManager.cpp:90
const CMatrix3D & GetTransform() const
virtual const CParamNode * LoadLatestTemplate(entity_id_t ent)=0
Returns the template most recently specified for the entity &#39;ent&#39;.
virtual void GetShape(EShape &shape, entity_pos_t &size0, entity_pos_t &size1, entity_pos_t &height)=0
Return the shape of this footprint.
virtual void SetShadingColor(const CColor &colour)
virtual CColor GetShadingColor() const
CUnitAnimation * GetAnimation()
Definition: Unit.h:58
void InitSelectionShapeDescriptor(const CParamNode &paramNode)
Helper method; initializes the model selection shape descriptor from XML. Factored out for readabilit...
virtual std::wstring GetActorShortName()
Return the short name of the actor that&#39;s being displayed, or the empty string on error...
Prepare for rendering a new frame (set up model positions etc).
Definition: MessageTypes.h:122
virtual const CBoundingBoxAligned GetWorldBoundsRec()
Returns world space bounds of this object and all child objects.
Definition: ModelAbstract.h:92
CVector3D GetTranslation() const
Definition: Matrix3D.cpp:195
virtual void Deserialize(const CParamNode &paramNode, IDeserializer &deserialize)
#define MODELFLAG_SILHOUETTE_OCCLUDER
Definition: Model.h:43
const CBoundingBoxAligned & GetWorldBounds()
Returns the world-space axis-aligned bounds of this object.
void RemoveShadows()
Definition: Decal.cpp:111
virtual CBoundingBoxOriented GetSelectionBox()
Get the oriented world-space bounding box of the object&#39;s visual representation, clipped at the Y=0 p...
void SetAnimationSyncOffset(float actionTime)
Adjust the offset of the current animation, so that Update(actionTime) will advance it to the &#39;action...
void UpdateModel(float frameTime)
Update the model&#39;s animation.
Definition: Unit.cpp:67
CStrW m_ShortName
Definition: ObjectBase.h:164
The selection shape is determined by an oriented box of custom, user-specified size.
Definition: ModelAbstract.h:50
virtual u32 GetActorSeed()
Get actor seed used for random variations.
virtual CModelDecal * ToCModelDecal()
Dynamic cast.
Definition: ModelAbstract.h:79
std::map< std::string, std::string > m_AnimOverride
virtual void SetAnimationSyncRepeat(fixed repeattime)
Adjust the speed of the current animation, so it can match simulation events.
virtual void SetAnimationSyncOffset(fixed actiontime)
Adjust the offset of the current animation, so it can match simulation events.
virtual void Init(const CParamNode &paramNode)
ICmpRangeManager::ELosVisibility m_Visibility
virtual void ValidatePosition()=0
Ensure that both the transformation and the bone matrices are correct for this model and all its prop...
virtual CBoundingBoxAligned GetBounds()
Get the world-space bounding box of the object&#39;s visual representation.
Deserialization interface; see serialization overview.
Definition: IDeserializer.h:34
The visual representation of an entity (typically an actor).
Definition: ICmpVisual.h:34
void AddFlagsRec(int flags)
Definition: Model.cpp:624