Skip to content

Commit e270edf

Browse files
gunslingermodXottab-DUTY
authored andcommitted
[Bugfix] More correct way to fix camera glitching
In commit 0aab576 we have attempts to fix camera glitching when one of effectors finishes working. The root of glitches is effector's deletion in CCameraManager::ProcessCameraEffector. Cycle in CCameraManager::UpdateCamEffectors uses reverse iterator and doesn't expect that entry in the list would be removed. Due to specific behavior of reverse iterator it really points to the next element relative to element which it dereferenced to. So, when ProcessCameraEffector deletes currently dereferenced element, iterator automatically starts point to element before deleted one. But the UpdateCamEffectors doesn't know about it, and cycle changes iterator on next iteration. So, processing of one camera effect would be skipped in this moment. Changes in 0aab576 don't seems to be the best solution, because 1) vector is less suitable for situations where we are often want to add or remove random elements 2) Deletion of current effector in ProcessCameraEffector seems to be not safe. For example, we could have CCameraManager's childs with overridden ProcessCameraEffector method. They could be deadly surprised if pointer to current effector would start pointing to non-existent element. So, this commit: 1) Reverts changes from 0aab576 2) Removes effector's deletion from CCameraManager::ProcessCameraEffector; now the method returns false if it should be deleted, or true otherwise 3) Adds code for removing 'old' effectors to UpdateCamEffectors method.
1 parent 42ac33e commit e270edf

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed

src/xrEngine/CameraManager.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ void CCameraManager::UpdateDeffered()
8686
RemoveCamEffector((*it)->eType);
8787

8888
if ((*it)->AbsolutePositioning())
89-
m_EffectorsCam.insert(m_EffectorsCam.begin(), *it);
89+
m_EffectorsCam.push_front(*it);
9090
else
9191
m_EffectorsCam.push_back(*it);
9292
}
@@ -222,23 +222,19 @@ void CCameraManager::Update(const Fvector& P, const Fvector& D, const Fvector& N
222222

223223
bool CCameraManager::ProcessCameraEffector(CEffectorCam* eff)
224224
{
225+
// Do NOT delete effector here! It's unsafe because:
226+
// 1. Leads to failed iterators in UpdateCamEffectors
227+
// 2. Child classes with overrided ProcessCameraEffector would be surprised if eff becames invalid pointer
228+
// The best way - return 'false' when the effector should be deleted, and delete it in ProcessCameraEffector
229+
225230
bool res = false;
226231
if (eff->Valid() && eff->ProcessCam(m_cam_info))
227232
{
228233
res = true;
229234
}
230-
else
235+
else if (eff->AllowProcessingIfInvalid())
231236
{
232-
if (eff->AllowProcessingIfInvalid())
233-
{
234-
eff->ProcessIfInvalid(m_cam_info);
235-
res = true;
236-
}
237-
238-
EffectorCamVec::iterator it = std::find(m_EffectorsCam.begin(), m_EffectorsCam.end(), eff);
239-
240-
m_EffectorsCam.erase(it);
241-
OnEffectorReleased(eff);
237+
eff->ProcessIfInvalid(m_cam_info);
242238
}
243239
return res;
244240
}
@@ -247,8 +243,22 @@ void CCameraManager::UpdateCamEffectors()
247243
{
248244
if (m_EffectorsCam.empty())
249245
return;
250-
for (int i = m_EffectorsCam.size() - 1; i >= 0; --i)
251-
ProcessCameraEffector(m_EffectorsCam[i]);
246+
247+
auto r_it = m_EffectorsCam.rbegin();
248+
while (r_it != m_EffectorsCam.rend())
249+
{
250+
if (ProcessCameraEffector(*r_it))
251+
++r_it;
252+
else
253+
{
254+
// Dereferencing reverse iterator returns previous element of the list, r_it.base() returns current element
255+
// So, we should use base()-1 iterator to delete just processed element. 'Previous' element would be
256+
// automatically changed after deletion, so r_it would dereferencing to another value, no need to change it
257+
OnEffectorReleased(*r_it);
258+
auto r_to_del = r_it.base();
259+
m_EffectorsCam.erase(--r_to_del);
260+
}
261+
}
252262

253263
m_cam_info.d.normalize();
254264
m_cam_info.n.normalize();

src/xrEngine/CameraManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "CameraDefs.h"
44
#include "xrCore/PostProcess/PPInfo.hpp"
55

6-
using EffectorCamVec = xr_vector<CEffectorCam*>;
6+
using EffectorCamVec = xr_list<CEffectorCam*>;
77
using EffectorPPVec = xr_vector<CEffectorPP*>;
88

99
#define effCustomEffectorStartID 10000

0 commit comments

Comments
 (0)