Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpVisualActor.cpp
/* Copyright (C) 2020 Wildfire Games. | /* Copyright (C) 2021 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | private: | ||||
// Current animation state | // Current animation state | ||||
std::string m_AnimName; | std::string m_AnimName; | ||||
bool m_AnimOnce; | bool m_AnimOnce; | ||||
fixed m_AnimSpeed; | fixed m_AnimSpeed; | ||||
std::wstring m_SoundGroup; | std::wstring m_SoundGroup; | ||||
fixed m_AnimDesync; | fixed m_AnimDesync; | ||||
fixed m_AnimSyncRepeatTime; // 0.0 if not synced | fixed m_AnimSyncRepeatTime; // 0.0 if not synced | ||||
fixed m_AnimSyncOffsetTime; | fixed m_AnimSyncOffsetTime; | ||||
u8 m_MaxLevelOfDetail; | |||||
u8 m_CurrentLevelOfDetail; | |||||
std::map<CStr, CStr> m_VariantSelections; | std::map<CStr, CStr> m_VariantSelections; | ||||
u32 m_Seed; // seed used for random variations | u32 m_Seed; // seed used for random variations | ||||
bool m_ConstructionPreview; | bool m_ConstructionPreview; | ||||
bool m_VisibleInAtlasOnly; | bool m_VisibleInAtlasOnly; | ||||
Show All 13 Lines | return | ||||
"<a:example>" | "<a:example>" | ||||
"<Actor>units/hellenes/infantry_spearman_b.xml</Actor>" | "<Actor>units/hellenes/infantry_spearman_b.xml</Actor>" | ||||
"</a:example>" | "</a:example>" | ||||
"<a:example>" | "<a:example>" | ||||
"<Actor>structures/hellenes/barracks.xml</Actor>" | "<Actor>structures/hellenes/barracks.xml</Actor>" | ||||
"<FoundationActor>structures/fndn_4x4.xml</FoundationActor>" | "<FoundationActor>structures/fndn_4x4.xml</FoundationActor>" | ||||
"</a:example>" | "</a:example>" | ||||
"<element name='Actor' a:help='Filename of the actor to be used for this unit'>" | "<element name='Actor' a:help='Filename of the actor to be used for this unit'>" | ||||
"<optional>" | |||||
"<attribute name='lods'>" | |||||
"<data type='integer'>" | |||||
"<param name='minInclusive'>0</param>" | |||||
"</data>" | |||||
"</attribute>" | |||||
"</optional>" | |||||
"<text/>" | "<text/>" | ||||
"</element>" | "</element>" | ||||
"<optional>" | "<optional>" | ||||
"<element name='FoundationActor' a:help='Filename of the actor to be used the foundation while this unit is being constructed'>" | "<element name='FoundationActor' a:help='Filename of the actor to be used the foundation while this unit is being constructed'>" | ||||
"<optional>" | |||||
"<attribute name='lods'>" | |||||
"<data type='integer'>" | |||||
"<param name='minInclusive'>0</param>" | |||||
"</data>" | |||||
"</attribute>" | |||||
"</optional>" | |||||
"<text/>" | "<text/>" | ||||
"</element>" | "</element>" | ||||
"</optional>" | "</optional>" | ||||
"<optional>" | "<optional>" | ||||
"<element name='Foundation' a:help='Used internally; if present, the unit will be rendered as a foundation'>" | "<element name='Foundation' a:help='Used internally; if present, the unit will be rendered as a foundation'>" | ||||
"<empty/>" | "<empty/>" | ||||
"</element>" | "</element>" | ||||
"</optional>" | "</optional>" | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | virtual void Init(const CParamNode& paramNode) | ||||
m_ConstructionPreview = paramNode.GetChild("ConstructionPreview").IsOk(); | m_ConstructionPreview = paramNode.GetChild("ConstructionPreview").IsOk(); | ||||
m_Seed = GetEntityId(); | m_Seed = GetEntityId(); | ||||
m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk(); | m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk(); | ||||
m_BaseActorName = paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").ToString(); | m_BaseActorName = paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").ToString(); | ||||
m_CurrentLevelOfDetail = 0; | |||||
m_MaxLevelOfDetail = static_cast<u8>(paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").GetChild("@lods").ToInt()); | |||||
ParseActorName(m_BaseActorName); | ParseActorName(m_BaseActorName); | ||||
m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool(); | m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool(); | ||||
m_IsActorOnly = paramNode.GetChild("ActorOnly").IsOk(); | m_IsActorOnly = paramNode.GetChild("ActorOnly").IsOk(); | ||||
m_SilhouetteDisplay = paramNode.GetChild("SilhouetteDisplay").ToBool(); | m_SilhouetteDisplay = paramNode.GetChild("SilhouetteDisplay").ToBool(); | ||||
m_SilhouetteOccluder = paramNode.GetChild("SilhouetteOccluder").ToBool(); | m_SilhouetteOccluder = paramNode.GetChild("SilhouetteOccluder").ToBool(); | ||||
m_DisableShadows = paramNode.GetChild("DisableShadows").ToBool(); | m_DisableShadows = paramNode.GetChild("DisableShadows").ToBool(); | ||||
// Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the | // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the | ||||
// Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint | // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint | ||||
// shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in | // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in | ||||
// which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just | // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just | ||||
// initialize the selection shape descriptor on-demand. | // initialize the selection shape descriptor on-demand. | ||||
InitSelectionShapeDescriptor(paramNode); | InitSelectionShapeDescriptor(paramNode); | ||||
} | } | ||||
virtual bool HasLevelsOfDetail() const | |||||
{ | |||||
return m_MaxLevelOfDetail > 0; | |||||
} | |||||
virtual u8 GetCurrentLevelOfDetail() const | |||||
{ | |||||
return m_CurrentLevelOfDetail; | |||||
} | |||||
virtual u8 GetMaxLevelOfDetail() const | |||||
{ | |||||
return m_MaxLevelOfDetail; | |||||
} | |||||
virtual void SetMaxLevelOfDetail(u8 levelOfDetail) | |||||
{ | |||||
m_MaxLevelOfDetail = levelOfDetail; | |||||
} | |||||
virtual void SetLevelOfDetail(u8 levelOfDetail) | |||||
{ | |||||
if (m_CurrentLevelOfDetail == levelOfDetail) | |||||
return; | |||||
ENSURE(levelOfDetail >= 0 && levelOfDetail <= m_MaxLevelOfDetail); | |||||
m_CurrentLevelOfDetail = levelOfDetail; | |||||
// ToDo: Config Option: | |||||
// std::max(m_CurrentLevelOfDetail, m_MinLevelOfDetail); | |||||
RecomputeActorName(); | |||||
} | |||||
virtual void Deinit() | virtual void Deinit() | ||||
{ | { | ||||
if (m_Unit) | if (m_Unit) | ||||
{ | { | ||||
GetSimContext().GetUnitManager().DeleteUnit(m_Unit); | GetSimContext().GetUnitManager().DeleteUnit(m_Unit); | ||||
m_Unit = NULL; | m_Unit = NULL; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 298 Lines • ▼ Show 20 Lines | public: | ||||
virtual void RecomputeActorName() | virtual void RecomputeActorName() | ||||
{ | { | ||||
CmpPtr<ICmpValueModificationManager> cmpValueModificationManager(GetSystemEntity()); | CmpPtr<ICmpValueModificationManager> cmpValueModificationManager(GetSystemEntity()); | ||||
std::wstring newActorName; | std::wstring newActorName; | ||||
if (m_IsFoundationActor) | if (m_IsFoundationActor) | ||||
newActorName = cmpValueModificationManager->ApplyModifications(L"VisualActor/FoundationActor", m_BaseActorName, GetEntityId()); | newActorName = cmpValueModificationManager->ApplyModifications(L"VisualActor/FoundationActor", m_BaseActorName, GetEntityId()); | ||||
else | else | ||||
newActorName = cmpValueModificationManager->ApplyModifications(L"VisualActor/Actor", m_BaseActorName, GetEntityId()); | newActorName = cmpValueModificationManager->ApplyModifications(L"VisualActor/Actor", m_BaseActorName, GetEntityId()); | ||||
Silier: m_BaseActorName.concat("_" + lod_number) ? | |||||
if (m_CurrentLevelOfDetail != 0) | |||||
// ToDo: Should be a.lod.xml and not a.xml.lod.xml. | |||||
newActorName = fmt::format(L"{0}.{1}.xml", newActorName, m_CurrentLevelOfDetail); | |||||
if (newActorName != m_ActorName) | if (newActorName != m_ActorName) | ||||
{ | { | ||||
ParseActorName(newActorName); | ParseActorName(newActorName); | ||||
ReloadActor(); | ReloadActor(); | ||||
} | } | ||||
} | } | ||||
virtual bool HasConstructionPreview() const | virtual bool HasConstructionPreview() const | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | else | ||||
// shouldn't happen by virtue of validation against schema | // shouldn't happen by virtue of validation against schema | ||||
LOGERROR("[VisualActor] No selection shape specified"); | LOGERROR("[VisualActor] No selection shape specified"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void CCmpVisualActor::ReloadActor() | void CCmpVisualActor::ReloadActor() | ||||
{ | { | ||||
if (!m_Unit) | CColor shading; | ||||
return; | player_id_t playerID; | ||||
if (m_Unit) | |||||
{ | |||||
// Save some data from the old unit | // Save some data from the old unit | ||||
CColor shading = m_Unit->GetModel().GetShadingColor(); | shading = m_Unit->GetModel().GetShadingColor(); | ||||
player_id_t playerID = m_Unit->GetModel().GetPlayerID(); | playerID = m_Unit->GetModel().GetPlayerID(); | ||||
// Replace with the new unit | // Replace with the new unit | ||||
GetSimContext().GetUnitManager().DeleteUnit(m_Unit); | GetSimContext().GetUnitManager().DeleteUnit(m_Unit); | ||||
} | |||||
else { | |||||
// If LODS are missing use sane values. | |||||
shading = CColor(1, 1, 1, 1); | |||||
CmpPtr<ICmpOwnership> cmpOwner(GetEntityHandle()); | |||||
if (cmpOwner) | |||||
playerID = cmpOwner->GetOwner(); | |||||
} | |||||
// HACK: selection shape needs template data, but rather than storing all that data | // HACK: selection shape needs template data, but rather than storing all that data | ||||
// in the component, we load the template here and pass it into a helper function | // in the component, we load the template here and pass it into a helper function | ||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(GetSystemEntity()); | CmpPtr<ICmpTemplateManager> cmpTemplateManager(GetSystemEntity()); | ||||
const CParamNode* node = cmpTemplateManager->LoadLatestTemplate(GetEntityId()); | const CParamNode* node = cmpTemplateManager->LoadLatestTemplate(GetEntityId()); | ||||
ENSURE(node && node->GetChild("VisualActor").IsOk()); | ENSURE(node && node->GetChild("VisualActor").IsOk()); | ||||
InitSelectionShapeDescriptor(node->GetChild("VisualActor")); | InitSelectionShapeDescriptor(node->GetChild("VisualActor")); | ||||
InitModel(); | InitModel(); | ||||
// If the units has missing lods it may crash. | |||||
if (!m_Unit) | |||||
return; | |||||
ReloadUnitAnimation(); | ReloadUnitAnimation(); | ||||
m_Unit->GetModel().SetShadingColor(shading); | m_Unit->GetModel().SetShadingColor(shading); | ||||
m_Unit->GetModel().SetPlayerID(playerID); | m_Unit->GetModel().SetPlayerID(playerID); | ||||
if (m_ModelTag.valid()) | if (m_ModelTag.valid()) | ||||
{ | { | ||||
Show All 25 Lines |
Wildfire Games · Phabricator
m_BaseActorName.concat("_" + lod_number) ?