Changeset View
Standalone View
source/simulation2/components/CCmpUnitRenderer.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 All 20 Lines | |||||
#include "graphics/Frustum.h" | #include "graphics/Frustum.h" | ||||
#include "graphics/ModelAbstract.h" | #include "graphics/ModelAbstract.h" | ||||
#include "graphics/ObjectEntry.h" | #include "graphics/ObjectEntry.h" | ||||
#include "graphics/Overlay.h" | #include "graphics/Overlay.h" | ||||
#include "graphics/Unit.h" | #include "graphics/Unit.h" | ||||
#include "maths/BoundingSphere.h" | #include "maths/BoundingSphere.h" | ||||
#include "maths/Matrix3D.h" | #include "maths/Matrix3D.h" | ||||
#include "ps/Game.h" | |||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "renderer/RenderingOptions.h" | #include "renderer/RenderingOptions.h" | ||||
vladislavbelov: Wrong order. | |||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
#include "tools/atlas/GameInterface/GameLoop.h" | #include "tools/atlas/GameInterface/GameLoop.h" | ||||
#include <algorithm> | |||||
#include <deque> | |||||
/** | /** | ||||
* Efficiently(ish) renders all the units in the world. | * Efficiently(ish) renders all the units in the world. | ||||
* | * | ||||
* The class maintains a list of all units that currently exist, and the data | * The class maintains a list of all units that currently exist, and the data | ||||
* needed for frustum-culling them. To minimise the amount of work done per | * needed for frustum-culling them. To minimise the amount of work done per | ||||
* frame (despite a unit's interpolated position changing every frame), the | * frame (despite a unit's interpolated position changing every frame), the | ||||
* culling data is only updated once per turn: we store the position at the | * culling data is only updated once per turn: we store the position at the | ||||
* start of the turn, and the position at the end of the turn, and assume the | * start of the turn, and the position at the end of the turn, and assume the | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | struct SUnit | ||||
/** | /** | ||||
* For debug overlay. | * For debug overlay. | ||||
*/ | */ | ||||
bool culled; | bool culled; | ||||
}; | }; | ||||
std::vector<SUnit> m_Units; | std::vector<SUnit> m_Units; | ||||
std::vector<tag_t> m_UnitTagsFree; | std::vector<tag_t> m_UnitTagsFree; | ||||
/** | |||||
* Contains the list of corpses currently displayed. | |||||
*/ | |||||
std::deque<entity_id_t> m_Corpses; | |||||
int m_FrameNumber; | int m_FrameNumber; | ||||
float m_FrameOffset; | float m_FrameOffset; | ||||
Done Inline Actionsseems a bit weird to add it here between those two frame-related variables. I'd plop it above, with a little comment. wraitii: seems a bit weird to add it here between those two frame-related variables. I'd plop it above… | |||||
bool m_EnableDebugOverlays; | bool m_EnableDebugOverlays; | ||||
std::vector<SOverlaySphere> m_DebugSpheres; | std::vector<SOverlaySphere> m_DebugSpheres; | ||||
static void ClassInit(CComponentManager& componentManager) | static void ClassInit(CComponentManager& componentManager) | ||||
{ | { | ||||
componentManager.SubscribeToMessageType(MT_TurnStart); | componentManager.SubscribeToMessageType(MT_TurnStart); | ||||
componentManager.SubscribeToMessageType(MT_Interpolate); | componentManager.SubscribeToMessageType(MT_Interpolate); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | public: | ||||
SUnit* LookupUnit(tag_t tag) | SUnit* LookupUnit(tag_t tag) | ||||
{ | { | ||||
if (tag.n < 1 || tag.n - 1 >= m_Units.size()) | if (tag.n < 1 || tag.n - 1 >= m_Units.size()) | ||||
return NULL; | return NULL; | ||||
return &m_Units[tag.n - 1]; | return &m_Units[tag.n - 1]; | ||||
} | } | ||||
virtual void RegisterCorpse(entity_id_t entity) | |||||
{ | |||||
const int maxCorpses = g_RenderingOptions.GetMaxCorpseCount(); | |||||
Done Inline ActionsCan't use size_t directly here? wraitii: Can't use size_t directly here? | |||||
Done Inline ActionsCould but then I'd have to cast the 0 for fun :D Stan: Could but then I'd have to cast the 0 for fun :D | |||||
if (maxCorpses <= 0) | |||||
Not Done Inline ActionsThe fact that this works for both -1/unlimited and 0/deactivated is a bit weird wraitii: The fact that this works for both -1/unlimited and 0/deactivated is a bit weird | |||||
return; | |||||
if (m_Corpses.size() == static_cast<size_t>(maxCorpses)) | |||||
{ | |||||
const entity_id_t ent = m_Corpses.front(); | |||||
// This will work even if the entity has been destroyed already by CCmpDecay. | |||||
Not Done Inline Actionsmention that it doesn't matter if ent is already destroyed maybe, since that's what makes this work. wraitii: mention that it doesn't matter if ent is already destroyed maybe, since that's what makes this… | |||||
GetSimContext().GetComponentManager().DestroyComponentsSoon(ent); | |||||
m_Corpses.pop_front(); | |||||
} | |||||
m_Corpses.push_back(entity); | |||||
} | |||||
virtual bool ShouldCreateCorpse() const | |||||
{ | |||||
return g_RenderingOptions.GetMaxCorpseCount() != 0; | |||||
} | |||||
Not Done Inline ActionsIt does linear search, so in case of deleting many corpses per turn it might be expensive. vladislavbelov: It does linear search, so in case of deleting many corpses per turn it might be expensive. | |||||
Done Inline ActionsWhat do you suggest then? Stan: What do you suggest then? | |||||
Not Done Inline ActionsThis is partly the reason why I suggested keeping a small 'max' number. I think for < 500 it's going to be generally irrelevant. I might be wrong on that though - perhaps a number as low as 50 is good enough. If you keep the list sorted (precludes doing the pop-swap trick), you can use a binary search. wraitii: This is partly the reason why I suggested keeping a small 'max' number. I think for < 500 it's… | |||||
Not Done Inline ActionsBTW you'll have to do some o(N) thing somewhere -> either search can be amortised with binary search, but then you can pop-swap so erasing will be o(N/2), or you keep like this, and searching is o(N) but erasing o(1). It'd need to be tested to know which is faster and whether any of that is a real problem, which I doubt. wraitii: BTW you'll have to do some o(N) thing somewhere -> either search can be amortised with binary… | |||||
virtual tag_t AddUnit(CEntityHandle entity, CUnit* actor, const CBoundingSphere& boundsApprox, int flags) | virtual tag_t AddUnit(CEntityHandle entity, CUnit* actor, const CBoundingSphere& boundsApprox, int flags) | ||||
{ | { | ||||
Not Done Inline ActionsI think this is what Vladislav had performance concerns over, and it's legitimate to an extent. The thing is, I don't think you actually need this :p Just let the corpse deque hold invalid entities. wraitii: I think this is what Vladislav had performance concerns over, and it's legitimate to an extent. | |||||
ENSURE(actor != NULL); | ENSURE(actor != NULL); | ||||
Done Inline ActionsThis reminds me -> You should swap and pop here instead. wraitii: This reminds me -> You should swap and pop here instead. | |||||
Done Inline ActionsI have feeling something went wrong here. Silier: I have feeling something went wrong here.
You are looking for entity and if you find it, you do… | |||||
Done Inline Actionsok, now i got it :D Silier: ok, now i got it :D | |||||
tag_t tag; | tag_t tag; | ||||
Done Inline ActionsI don't think you need that -> you're calling RemoveCorpse in Deinit() which means the entity is already destroying itself. wraitii: I don't think you need that -> you're calling RemoveCorpse in Deinit() which means the entity… | |||||
Done Inline Actionspop_ wraitii: pop_ | |||||
if (!m_UnitTagsFree.empty()) | if (!m_UnitTagsFree.empty()) | ||||
{ | { | ||||
tag = m_UnitTagsFree.back(); | tag = m_UnitTagsFree.back(); | ||||
m_UnitTagsFree.pop_back(); | m_UnitTagsFree.pop_back(); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
m_Units.push_back(SUnit()); | m_Units.push_back(SUnit()); | ||||
▲ Show 20 Lines • Show All 269 Lines • Show Last 20 Lines |
Wrong order.