Changeset View
Standalone View
source/simulation2/components/CCmpProjectileManager.cpp
Show All 19 Lines | |||||
#include "simulation2/system/Component.h" | #include "simulation2/system/Component.h" | ||||
#include "ICmpProjectileManager.h" | #include "ICmpProjectileManager.h" | ||||
#include "ICmpObstruction.h" | #include "ICmpObstruction.h" | ||||
#include "ICmpObstructionManager.h" | #include "ICmpObstructionManager.h" | ||||
#include "ICmpPosition.h" | #include "ICmpPosition.h" | ||||
#include "ICmpRangeManager.h" | #include "ICmpRangeManager.h" | ||||
#include "ICmpTerrain.h" | #include "ICmpTerrain.h" | ||||
#include "ICmpVisual.h" | |||||
#include "simulation2/MessageTypes.h" | #include "simulation2/MessageTypes.h" | ||||
#include "graphics/Frustum.h" | #include "graphics/Frustum.h" | ||||
#include "graphics/Model.h" | #include "graphics/Model.h" | ||||
#include "graphics/Unit.h" | #include "graphics/Unit.h" | ||||
#include "graphics/UnitManager.h" | #include "graphics/UnitManager.h" | ||||
#include "maths/Matrix3D.h" | #include "maths/Matrix3D.h" | ||||
#include "maths/Quaternion.h" | #include "maths/Quaternion.h" | ||||
#include "maths/Vector3D.h" | #include "maths/Vector3D.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
// Time (in seconds) before projectiles that stuck in the ground are destroyed | // Time (in seconds) before projectiles that stuck in the ground are destroyed | ||||
const static float PROJECTILE_DECAY_TIME = 30.f; | const static float PROJECTILE_DECAY_TIME = 30.f; | ||||
class CCmpProjectileManager : public ICmpProjectileManager | class CCmpProjectileManager : public ICmpProjectileManager | ||||
{ | { | ||||
elexis: range based loop as long as i is not used , `for (type foo : bar)` | |||||
Done Inline ActionsThere are still some unused parameters here. If a TODO might need them in the future we can add them once we need them. leper: There are still some unused parameters here. If a TODO might need them in the future we can add… | |||||
Done Inline ActionsSuch as? Mate-86: Such as? | |||||
Done Inline ActionsAh, it seems I just can't read. Is there a reason for the newline (and then using a tab, making this strange to read. Also the { belongs on the next line (see Coding_Conventions). leper: Ah, it seems I just can't read.
Is there a reason for the newline (and then using a tab… | |||||
Done Inline ActionsThe cited coding convention says "Try to avoid very wide lines". I'm happy to use a better indentation if you can suggest one. Mate-86: The cited coding convention says "Try to avoid very wide lines". I'm happy to use a better… | |||||
Done Inline ActionsYes, however that line is already quite long at the point where you split it. So either split it earlier, possibly align (that is not tabs, someone will come along and point out that this doesn't look nice with a tabwidth or 3 or 5) the parameters after a line break. But the main point was that the { is not in the right place. leper: Yes, however that line is already quite long at the point where you split it. So either split… | |||||
public: | public: | ||||
static void ClassInit(CComponentManager& componentManager) | static void ClassInit(CComponentManager& componentManager) | ||||
{ | { | ||||
Not Done Inline ActionsCan't that be inlined somehow, just curious Stan: Can't that be inlined somehow, just curious | |||||
Done Inline ActionsI prefer c++ types cast when possible, https://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast but that's just a personal choice, and I don't think we have a specific coding convention for those. Stan: I prefer c++ types cast when possible, https://stackoverflow.com/questions/28002/regular-cast… | |||||
Done Inline ActionsI've copied the existing code, I haven't changed this. Mate-86: I've copied the existing code, I haven't changed this. | |||||
Done Inline ActionsI believe we use C-style casts when converting between "obvious" types. Looks fine to me. wraitii: I believe we use C-style casts when converting between "obvious" types. Looks fine to me. | |||||
Done Inline ActionsFair enough as well. Stan: Fair enough as well. | |||||
componentManager.SubscribeToMessageType(MT_Interpolate); | componentManager.SubscribeToMessageType(MT_Interpolate); | ||||
componentManager.SubscribeToMessageType(MT_RenderSubmit); | componentManager.SubscribeToMessageType(MT_RenderSubmit); | ||||
Done Inline Actionsprobably could use a continue to nuke the else. Not sure the line gain is worth though. Stan: probably could use a continue to nuke the else. Not sure the line gain is worth though. | |||||
Done Inline ActionsNeither me. Putting the deletion of the projectile in the else instead of the loop body looks better to me. Mate-86: Neither me. Putting the deletion of the projectile in the else instead of the loop body looks… | |||||
Done Inline ActionsFair enough. Stan: Fair enough. | |||||
} | } | ||||
DEFAULT_COMPONENT_ALLOCATOR(ProjectileManager) | DEFAULT_COMPONENT_ALLOCATOR(ProjectileManager) | ||||
static std::string GetSchema() | static std::string GetSchema() | ||||
{ | { | ||||
Done Inline ActionsIs that for a different patch or does it include a huge number of files ? Stan: Is that for a different patch or does it include a huge number of files ? | |||||
Done Inline ActionsThere are 223 hits in 203 actor files for attachpoint="projectile". Please suggest if it makes to do it here or in a separate patch. Mate-86: There are 223 hits in 203 actor files for `attachpoint="projectile"`. Please suggest if it… | |||||
Done Inline ActionsDoing it in a separate patch sounds good to me, that's something we can handle in the team too I think, though you're free to submit a diff for that change separately. wraitii: Doing it in a separate patch sounds good to me, that's something we can handle in the team too… | |||||
Done Inline ActionsNah I think it's better in a separate patch, especially since it will break every mod. Stan: Nah I think it's better in a separate patch, especially since it will break every mod. | |||||
return "<a:component type='system'/><empty/>"; | return "<a:component type='system'/><empty/>"; | ||||
} | } | ||||
Done Inline Actions(++i I could be done in the consequent) elexis: (++i I could be done in the consequent) | |||||
virtual void Init(const CParamNode& UNUSED(paramNode)) | virtual void Init(const CParamNode& UNUSED(paramNode)) | ||||
{ | { | ||||
m_ActorSeed = 0; | m_ActorSeed = 0; | ||||
Done Inline ActionsWhy did this get commented out? wraitii: Why did this get commented out? | |||||
Done Inline ActionsIf not commented out then new projectile hit animations are created in each cycle after the projectile was stopped but not decayed yet. As the TODO above says the proper solution of continuous delay (and animation) will come in #1912 anyway. Mate-86: If not commented out then new projectile hit animations are created in each cycle after the… | |||||
Done Inline ActionsJust remove the commented code entirely then. wraitii: Just remove the commented code entirely then. | |||||
m_NextId = 1; | m_NextId = 1; | ||||
} | } | ||||
virtual void Deinit() | virtual void Deinit() | ||||
{ | { | ||||
for (size_t i = 0; i < m_Projectiles.size(); ++i) | for (size_t i = 0; i < m_Projectiles.size(); ++i) | ||||
GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles[i].unit); | GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles[i].unit); | ||||
m_Projectiles.clear(); | m_Projectiles.clear(); | ||||
Show All 31 Lines | virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
{ | { | ||||
const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); | const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); | ||||
RenderSubmit(msgData.collector, msgData.frustum, msgData.culling); | RenderSubmit(msgData.collector, msgData.frustum, msgData.culling); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
virtual uint32_t LaunchProjectileAtPoint(entity_id_t source, const CFixedVector3D& target, fixed speed, fixed gravity) | virtual uint32_t LaunchProjectileAtPoint(const CFixedVector3D& launchPoint, const CFixedVector3D& target, fixed speed, fixed gravity, const std::wstring& actorName, const std::wstring& impactActorName, fixed impactAnimationLifetime) | ||||
Not Done Inline ActionsSame here. wraitii: Same here. | |||||
{ | { | ||||
return LaunchProjectile(source, target, speed, gravity); | return LaunchProjectile(launchPoint, target, speed, gravity, actorName, impactActorName, impactAnimationLifetime); | ||||
} | } | ||||
virtual void RemoveProjectile(uint32_t); | virtual void RemoveProjectile(uint32_t); | ||||
void RenderModel(CModelAbstract& model, const CVector3D& position, SceneCollector& collector, const CFrustum& frustum, bool culling, | |||||
Done Inline ActionsNo need to virtual this one I believe. wraitii: No need to virtual this one I believe. | |||||
ICmpRangeManager::CLosQuerier los, bool losRevealAll) const; | |||||
private: | private: | ||||
struct Projectile | struct Projectile | ||||
{ | { | ||||
CUnit* unit; | CUnit* unit; | ||||
CVector3D origin; | CVector3D origin; | ||||
CVector3D pos; | CVector3D pos; | ||||
CVector3D v; | CVector3D v; | ||||
float time; | float time; | ||||
float timeHit; | float timeHit; | ||||
Done Inline ActionsMove this after timeHit; wraitii: Move this after timeHit; | |||||
float gravity; | float gravity; | ||||
bool stopped; | bool stopped; | ||||
Not Done Inline ActionsReorder this struct to minimise the size it takes. Bools should be put together at the end I think. Use god bolt.org to check on different compilers if you want. wraitii: Reorder this struct to minimise the size it takes. Bools should be put together at the end I… | |||||
Not Done Inline ActionsI checked this godbolt and the order of the variables does not affect the size of the generated assembly code (if that was the question). Mate-86: I checked this godbolt and the order of the variables does not affect the size of the generated… | |||||
uint32_t id; | uint32_t id; | ||||
std::wstring impactActorName; | |||||
Not Done Inline ActionsMake this a std::unique_ptr<std::wstring>. It'll take far less memory in the case where it doesn't exist and won't be much slower when it does exist. static_assert(sizeof(Projectile) == 80, "Projectiles is 80 bytes large") bit, we like to be explicit about our sizes. You're right about the order not mattering here anyhow though. wraitii: Make this a std::unique_ptr<std::wstring>. It'll take far less memory in the case where it… | |||||
Not Done Inline ActionsI did some experiment with this unique_ptr member but it looks like I have to define move constructor and operator= for Projectile class in order to use push_back and swap on std::vector<Projectile> m_Projectiles. Otherwise I get errors like: Defining move constructor and operator= seems pretty complicated to me because all the struct members need to be listed there. Is this what we really want? Mate-86: I did some experiment with this unique_ptr member but it looks like I have to define move… | |||||
Not Done Inline Actions
I tried to get the size of the struct which is not trivial because I had to copy all the Projectile and Vector members into a console application and print out the sizeof value. The end result is 92 but I get the compilation error: CCmpProjectileManager.cpp(149): error C2338: Projectiles is 92 bytes large static_assert(sizeof(Projectile) == 92, "Projectiles is 92 bytes large"); Mate-86: > static_assert(sizeof(Projectile) == 80, "Projectiles is 80 bytes large")
I tried to get the… | |||||
Not Done Inline ActionsHello @Mate-86, re your second question: That's normal, that's not how you do it :p . Because of "alignment", a somewhat complicated thing which will be better explained elsewhere, you can't simply add up all the sizes to get the size of the struct. In fact, this one I believe takes up 96 bytes, which means it is 16-bytes aligned (96/16 = 6). The std::unique_ptr version only takes up 80 bytes (80/16 = 5). You're right about the move and copy constructor, that is more advanced C++ indeed. I think I'll upload a separate patch after I've committed this then. I'll address the format issues before committing. wraitii: Hello @Mate-86, re your second question:
That's normal, that's not how you do it :p . Because… | |||||
float impactAnimationLifetime; | |||||
Done Inline Actionsfeel like "Lifetime" would describe this better. Still not a fan of "hit" though. wraitii: feel like "Lifetime" would describe this better. Still not a fan of "hit" though. | |||||
Not Done Inline ActionsHow about impactAnimationLifeTime or finalAnimationLifeTime? Or you can check the thesaurus :) http://www.thesaurus.com/browse/hit?s=t Mate-86: How about `impactAnimationLifeTime` or `finalAnimationLifeTime`? Or you can check the thesaurus… | |||||
CVector3D position(float t) | CVector3D position(float t) | ||||
{ | { | ||||
float t2 = t; | float t2 = t; | ||||
if (t2 > timeHit) | if (t2 > timeHit) | ||||
t2 = timeHit + logf(1.f + t2 - timeHit); | t2 = timeHit + logf(1.f + t2 - timeHit); | ||||
CVector3D ret(origin); | CVector3D ret(origin); | ||||
ret.X += v.X * t2; | ret.X += v.X * t2; | ||||
ret.Z += v.Z * t2; | ret.Z += v.Z * t2; | ||||
ret.Y += v.Y * t2 - 0.5f * gravity * t * t; | ret.Y += v.Y * t2 - 0.5f * gravity * t * t; | ||||
return ret; | return ret; | ||||
} | } | ||||
}; | }; | ||||
struct ProjectileImpactAnimation { | |||||
CUnit* unit; | |||||
CVector3D pos; | |||||
float time; | |||||
}; | |||||
std::vector<Projectile> m_Projectiles; | std::vector<Projectile> m_Projectiles; | ||||
std::vector<ProjectileImpactAnimation> m_ProjectileImpactAnimations; | |||||
uint32_t m_ActorSeed; | uint32_t m_ActorSeed; | ||||
uint32_t m_NextId; | uint32_t m_NextId; | ||||
uint32_t LaunchProjectile(entity_id_t source, CFixedVector3D targetPoint, fixed speed, fixed gravity); | uint32_t LaunchProjectile(CFixedVector3D launchPoint, CFixedVector3D targetPoint, fixed speed, fixed gravity, | ||||
const std::wstring& actorName, const std::wstring& impactActorName, fixed impactAnimationLifetime); | |||||
void AdvanceProjectile(Projectile& projectile, float dt) const; | void AdvanceProjectile(Projectile& projectile, float dt) const; | ||||
void Interpolate(float frameTime); | void Interpolate(float frameTime); | ||||
void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) const; | void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) const; | ||||
}; | }; | ||||
REGISTER_COMPONENT_TYPE(ProjectileManager) | REGISTER_COMPONENT_TYPE(ProjectileManager) | ||||
uint32_t CCmpProjectileManager::LaunchProjectile(entity_id_t source, CFixedVector3D targetPoint, fixed speed, fixed gravity) | uint32_t CCmpProjectileManager::LaunchProjectile(CFixedVector3D launchPoint, CFixedVector3D targetPoint, fixed speed, fixed gravity, const std::wstring& actorName, const std::wstring& impactActorName, fixed impactAnimationLifetime) | ||||
{ | { | ||||
// This is network synced so don't use GUI checks before incrementing or it breaks any non GUI simulations | // This is network synced so don't use GUI checks before incrementing or it breaks any non GUI simulations | ||||
uint32_t currentId = m_NextId++; | uint32_t currentId = m_NextId++; | ||||
if (!GetSimContext().HasUnitManager()) | if (!GetSimContext().HasUnitManager() || actorName.empty()) | ||||
Not Done Inline ActionsThis might be personal but I like to keep unrelated early exit separate. wraitii: This might be personal but I like to keep unrelated early exit separate.
@leper opinion? | |||||
return currentId; // do nothing if graphics are disabled | return currentId; // do nothing if graphics are disabled | ||||
CmpPtr<ICmpVisual> cmpSourceVisual(GetSimContext(), source); | |||||
if (!cmpSourceVisual) | |||||
return currentId; | |||||
std::wstring name = cmpSourceVisual->GetProjectileActor(); | |||||
if (name.empty()) | |||||
{ | |||||
// If the actor was actually loaded, complain that it doesn't have a projectile | |||||
if (!cmpSourceVisual->GetActorShortName().empty()) | |||||
LOGERROR("Unit with actor '%s' launched a projectile but has no actor on 'projectile' attachpoint", utf8_from_wstring(cmpSourceVisual->GetActorShortName())); | |||||
return currentId; | |||||
} | |||||
Projectile projectile; | Projectile projectile; | ||||
projectile.id = currentId; | projectile.id = currentId; | ||||
projectile.time = 0.f; | projectile.time = 0.f; | ||||
projectile.stopped = false; | projectile.stopped = false; | ||||
projectile.gravity = gravity.ToFloat(); | projectile.gravity = gravity.ToFloat(); | ||||
projectile.origin = cmpSourceVisual->GetProjectileLaunchPoint(); | if (!impactActorName.empty()) | ||||
Done Inline ActionsGenerally preferable to call this cmpSourceVisualActor (the interface is poorly named). wraitii: Generally preferable to call this cmpSourceVisualActor (the interface is poorly named). | |||||
if (!projectile.origin) | |||||
{ | { | ||||
// If there's no explicit launch point, take a guess based on the entity position | projectile.impactActorName = impactActorName; | ||||
CmpPtr<ICmpPosition> sourcePos(GetSimContext(), source); | projectile.impactAnimationLifetime = impactAnimationLifetime.ToFloat(); | ||||
if (!sourcePos) | } | ||||
return currentId; | else | ||||
projectile.origin = sourcePos->GetPosition(); | { | ||||
Done Inline Actions{ on newline. wraitii: { on newline. | |||||
projectile.origin.Y += 3.f; | projectile.impactActorName = L""; | ||||
projectile.impactAnimationLifetime = 0.0f; | |||||
} | } | ||||
projectile.origin = launchPoint; | |||||
Done Inline Actionssame wraitii: same | |||||
std::set<CStr> selections; | std::set<CStr> selections; | ||||
projectile.unit = GetSimContext().GetUnitManager().CreateUnit(name, m_ActorSeed++, selections); | projectile.unit = GetSimContext().GetUnitManager().CreateUnit(actorName, m_ActorSeed++, selections); | ||||
if (!projectile.unit) // The error will have already been logged | if (!projectile.unit) // The error will have already been logged | ||||
return currentId; | return currentId; | ||||
projectile.pos = projectile.origin; | projectile.pos = projectile.origin; | ||||
CVector3D offset(targetPoint); | CVector3D offset(targetPoint); | ||||
offset -= projectile.pos; | offset -= projectile.pos; | ||||
float horizDistance = sqrtf(offset.X*offset.X + offset.Z*offset.Z); | float horizDistance = sqrtf(offset.X*offset.X + offset.Z*offset.Z); | ||||
projectile.timeHit = horizDistance / speed.ToFloat(); | projectile.timeHit = horizDistance / speed.ToFloat(); | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < m_Projectiles.size(); ++i) | ||||
AdvanceProjectile(m_Projectiles[i], frameTime); | AdvanceProjectile(m_Projectiles[i], frameTime); | ||||
} | } | ||||
// Remove the ones that have reached their target | // Remove the ones that have reached their target | ||||
for (size_t i = 0; i < m_Projectiles.size(); ) | for (size_t i = 0; i < m_Projectiles.size(); ) | ||||
{ | { | ||||
// Projectiles hitting targets get removed immediately. | // Projectiles hitting targets get removed immediately. | ||||
// Those hitting the ground stay for a while, because it looks pretty. | // Those hitting the ground stay for a while, because it looks pretty. | ||||
if (m_Projectiles[i].stopped) | if (!m_Projectiles[i].stopped) | ||||
Done Inline ActionsSwitch these two ifs to early "continue" instead. wraitii: Switch these two ifs to early "continue" instead. | |||||
{ | { | ||||
if (m_Projectiles[i].time - m_Projectiles[i].timeHit > PROJECTILE_DECAY_TIME) | ++i; | ||||
wraitiiUnsubmitted Done Inline ActionsDon't delete this if, add a new parameter to projectile so that the impact actor creation only happens once. wraitii: Don't delete this if, add a new parameter to projectile so that the impact actor creation only… | |||||
continue; | |||||
Done Inline ActionsI'd rather define those above their first use. wraitii: I'd rather define those above their first use. | |||||
} | |||||
if (!m_Projectiles[i].impactActorName.empty()) | |||||
{ | { | ||||
CMatrix3D transform; | |||||
CQuaternion quat; | |||||
quat.ToMatrix(transform); | |||||
transform.Translate(m_Projectiles[i].pos); | |||||
std::set<CStr> selections; | |||||
CUnit* unit = GetSimContext().GetUnitManager().CreateUnit(m_Projectiles[i].impactActorName, m_ActorSeed++, selections); | |||||
unit->GetModel().SetTransform(transform); | |||||
ProjectileImpactAnimation projectileImpactAnimation; | |||||
projectileImpactAnimation.unit = unit; | |||||
projectileImpactAnimation.time = m_Projectiles[i].impactAnimationLifetime; | |||||
projectileImpactAnimation.pos = m_Projectiles[i].pos; | |||||
m_ProjectileImpactAnimations.push_back(projectileImpactAnimation); | |||||
} | |||||
// Delete in-place by swapping with the last in the list | // Delete in-place by swapping with the last in the list | ||||
std::swap(m_Projectiles[i], m_Projectiles.back()); | std::swap(m_Projectiles[i], m_Projectiles.back()); | ||||
GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles.back().unit); | GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles.back().unit); | ||||
m_Projectiles.pop_back(); | m_Projectiles.pop_back(); | ||||
continue; // don't increment i | |||||
} | |||||
} | } | ||||
for (size_t i = 0; i < m_ProjectileImpactAnimations.size();) | |||||
{ | |||||
if (m_ProjectileImpactAnimations[i].time > 0) | |||||
{ | |||||
m_ProjectileImpactAnimations[i].time -= frameTime; | |||||
++i; | ++i; | ||||
} | } | ||||
else | |||||
{ | |||||
std::swap(m_ProjectileImpactAnimations[i], m_ProjectileImpactAnimations.back()); | |||||
GetSimContext().GetUnitManager().DeleteUnit(m_ProjectileImpactAnimations.back().unit); | |||||
m_ProjectileImpactAnimations.pop_back(); | |||||
} | |||||
} | |||||
} | } | ||||
void CCmpProjectileManager::RemoveProjectile(uint32_t id) | void CCmpProjectileManager::RemoveProjectile(uint32_t id) | ||||
{ | { | ||||
// Scan through the projectile list looking for one with the correct id to remove | // Scan through the projectile list looking for one with the correct id to remove | ||||
for (size_t i = 0; i < m_Projectiles.size(); i++) | for (size_t i = 0; i < m_Projectiles.size(); i++) | ||||
{ | { | ||||
if (m_Projectiles[i].id == id) | if (m_Projectiles[i].id == id) | ||||
{ | { | ||||
// Delete in-place by swapping with the last in the list | // Delete in-place by swapping with the last in the list | ||||
std::swap(m_Projectiles[i], m_Projectiles.back()); | std::swap(m_Projectiles[i], m_Projectiles.back()); | ||||
GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles.back().unit); | GetSimContext().GetUnitManager().DeleteUnit(m_Projectiles.back().unit); | ||||
m_Projectiles.pop_back(); | m_Projectiles.pop_back(); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) const | void CCmpProjectileManager::RenderModel(CModelAbstract& model, const CVector3D& position, SceneCollector& collector, | ||||
{ | const CFrustum& frustum, bool culling, ICmpRangeManager::CLosQuerier los, bool losRevealAll) const | ||||
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity()); | |||||
int player = GetSimContext().GetCurrentDisplayedPlayer(); | |||||
ICmpRangeManager::CLosQuerier los(cmpRangeManager->GetLosQuerier(player)); | |||||
bool losRevealAll = cmpRangeManager->GetLosRevealAll(player); | |||||
for (size_t i = 0; i < m_Projectiles.size(); ++i) | |||||
{ | { | ||||
// Don't display projectiles outside the visible area | // Don't display objects outside the visible area | ||||
ssize_t posi = (ssize_t)(0.5f + m_Projectiles[i].pos.X / TERRAIN_TILE_SIZE); | ssize_t posi = (ssize_t)(0.5f + position.X / TERRAIN_TILE_SIZE); | ||||
ssize_t posj = (ssize_t)(0.5f + m_Projectiles[i].pos.Z / TERRAIN_TILE_SIZE); | ssize_t posj = (ssize_t)(0.5f + position.Z / TERRAIN_TILE_SIZE); | ||||
if (!losRevealAll && !los.IsVisible(posi, posj)) | if (!losRevealAll && !los.IsVisible(posi, posj)) | ||||
continue; | return; | ||||
CModelAbstract& model = m_Projectiles[i].unit->GetModel(); | |||||
model.ValidatePosition(); | model.ValidatePosition(); | ||||
if (culling && !frustum.IsBoxVisible(model.GetWorldBoundsRec())) | if (culling && !frustum.IsBoxVisible(model.GetWorldBoundsRec())) | ||||
continue; | return; | ||||
// TODO: do something about LOS (copy from CCmpVisualActor) | // TODO: do something about LOS (copy from CCmpVisualActor) | ||||
collector.SubmitRecursive(&model); | collector.SubmitRecursive(&model); | ||||
} | } | ||||
void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) const | |||||
{ | |||||
CmpPtr<ICmpRangeManager> cmpRangeManager(GetSystemEntity()); | |||||
int player = GetSimContext().GetCurrentDisplayedPlayer(); | |||||
ICmpRangeManager::CLosQuerier los(cmpRangeManager->GetLosQuerier(player)); | |||||
bool losRevealAll = cmpRangeManager->GetLosRevealAll(player); | |||||
for (const Projectile& projectile : m_Projectiles) | |||||
{ | |||||
RenderModel(projectile.unit->GetModel(), projectile.pos, collector, frustum, culling, los, losRevealAll); | |||||
} | |||||
for (const ProjectileImpactAnimation& projectileImpactAnimation : m_ProjectileImpactAnimations) | |||||
{ | |||||
RenderModel(projectileImpactAnimation.unit->GetModel(), projectileImpactAnimation.pos, | |||||
collector, frustum, culling, los, losRevealAll); | |||||
Done Inline ActionsFeel like you could put these on one line now. wraitii: Feel like you could put these on one line now. | |||||
} | |||||
} | } |
range based loop as long as i is not used , for (type foo : bar)