Skip to content

Commit 920c4e6

Browse files
authored
bugfix(smudge): Decouple smudge time step from render update (#2484)
1 parent 6e96a09 commit 920c4e6

6 files changed

Lines changed: 158 additions & 50 deletions

File tree

Core/GameEngine/Include/GameClient/Smudge.h

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,39 +28,59 @@
2828

2929
struct Smudge : public DLNodeClass<Smudge>
3030
{
31+
typedef void *Identifier;
32+
3133
W3DMPO_GLUE(Smudge)
3234

35+
Identifier m_identifier; //a number or pointer to identify this smudge
3336
Vector3 m_pos; //position of smudge center
3437
Vector2 m_offset; // difference in position between "texture" extraction and re-insertion for center vertex
3538
Real m_size; //size of smudge in world space.
3639
Real m_opacity; //alpha of center vertex, corners are assumed at 0
40+
Bool m_draw; //whether this smudge needs to be drawn
3741

3842
struct smudgeVertex
39-
{ Vector3 pos; //world-space position of vertex
43+
{
44+
Vector3 pos; //world-space position of vertex
4045
Vector2 uv; //uv coordinates of vertex
4146
};
4247
smudgeVertex m_verts[5]; //5 vertices of this smudge (in counter-clockwise order, starting at top-left, ending in center.)
4348
};
4449

45-
struct SmudgeSet : public DLNodeClass<SmudgeSet>
50+
#ifdef USING_STLPORT
51+
namespace std
4652
{
47-
W3DMPO_GLUE(SmudgeSet)
48-
49-
public:
53+
template<> struct hash<Smudge::Identifier>
54+
{
55+
size_t operator()(Smudge::Identifier id) const { return reinterpret_cast<size_t>(id); }
56+
};
57+
}
58+
#endif // USING_STLPORT
5059

60+
struct SmudgeSet : public DLNodeClass<SmudgeSet>
61+
{
5162
friend class SmudgeManager;
5263

64+
W3DMPO_GLUE(SmudgeSet)
65+
5366
SmudgeSet();
5467
virtual ~SmudgeSet() override;
68+
5569
void reset();
70+
void resetDraw();
71+
72+
Smudge *addSmudgeToSet(Smudge::Identifier identifier); ///< add and return a smudge to the set with the given identifier
73+
void removeSmudgeFromSet(Smudge *&smudge); ///< remove and invalidate the given smudge
74+
Smudge *findSmudge(Smudge::Identifier identifier); ///< find the smudge that belongs to this identifier
5675

57-
Smudge *addSmudgeToSet();
58-
void removeSmudgeFromSet ( Smudge &mySmudge);
5976
DLListClass<Smudge> &getUsedSmudgeList() { return m_usedSmudgeList;}
6077
Int getUsedSmudgeCount() { return m_usedSmudgeCount; } ///<active smudges that need rendering.
6178

6279
private:
80+
typedef std::hash_map<Smudge::Identifier, Smudge *> SmudgeIdToPtrMap;
81+
6382
DLListClass<Smudge> m_usedSmudgeList; ///<list of smudges in this set.
83+
SmudgeIdToPtrMap m_usedSmudgeMap;
6484
static DLListClass<Smudge> m_freeSmudgeList; ///<list of unused smudges for use by SmudgeSets.
6585
Int m_usedSmudgeCount;
6686
};
@@ -76,10 +96,12 @@ class SmudgeManager
7696
virtual void ReleaseResources() {}
7797
virtual void ReAcquireResources() {}
7898

79-
SmudgeSet *addSmudgeSet();
80-
void removeSmudgeSet(SmudgeSet &mySmudge);
99+
void resetDraw(); ///< reset whether all smudges need to be drawn
100+
101+
SmudgeSet *addSmudgeSet(); ///< add and return a new smudge set
102+
void removeSmudgeSet(SmudgeSet *&smudgeSet); ///< remove and invalidate the given smudge set
103+
Smudge *findSmudge(Smudge::Identifier identifier); ///< find the smudge from any smudge set
81104
Int getSmudgeCountLastFrame() {return m_smudgeCountLastFrame;} ///<return number of smudges submitted last frame.
82-
void setSmudgeCountLastFrame(Int count) { m_smudgeCountLastFrame = count;}
83105
Bool getHardwareSupport() { return m_hardwareSupportStatus != SMUDGE_SUPPORT_NO;}
84106

85107
protected:

Core/GameEngine/Source/GameClient/System/ParticleSys.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "GameClient/GameClient.h"
4545
#include "GameClient/InGameUI.h"
4646
#include "GameClient/ParticleSys.h"
47+
#include "GameClient/Smudge.h"
4748

4849
#include "GameLogic/GameLogic.h"
4950
#include "GameLogic/Object.h"
@@ -3003,6 +3004,43 @@ void ParticleSystemManager::update()
30033004
deleteInstance(sys);
30043005
}
30053006
}
3007+
3008+
const Bool drawSmudge = TheSmudgeManager && TheSmudgeManager->getHardwareSupport() && TheGlobalData->m_useHeatEffects;
3009+
3010+
if (drawSmudge)
3011+
{
3012+
// TheSuperHackers @bugfix The smudge time step is now decoupled from the render update.
3013+
// This clears all prior smudges and recreates them for all current smudge particles.
3014+
3015+
TheSmudgeManager->reset();
3016+
SmudgeSet *set = TheSmudgeManager->addSmudgeSet(); //global smudge set through which all smudges are rendered.
3017+
3018+
for (ParticleSystemManager::ParticleSystemListIt it = m_allParticleSystemList.begin(); it != m_allParticleSystemList.end(); ++it)
3019+
{
3020+
ParticleSystem *sys = (*it);
3021+
if (!sys)
3022+
continue;
3023+
3024+
// only look at particle/point style systems
3025+
if (sys->isUsingDrawables())
3026+
continue;
3027+
3028+
// temporary hack that checks if texture name starts with "SMUD" - if so, we can assume it's a smudge type
3029+
if (/*sys->isUsingSmudge()*/ *((DWORD *)sys->getParticleTypeName().str()) == 0x44554D53)
3030+
{
3031+
for (Particle *p = sys->getFirstParticle(); p; p = p->m_systemNext)
3032+
{
3033+
const Coord3D *pos = p->getPosition();
3034+
Smudge *smudge = set->addSmudgeToSet(p);
3035+
smudge->m_pos.Set(pos->x, pos->y, pos->z);
3036+
smudge->m_offset.Set(GameClientRandomValueReal(-0.06f,0.06f), GameClientRandomValueReal(-0.06f,0.06f));
3037+
smudge->m_size = p->getSize();
3038+
smudge->m_opacity = p->getAlpha();
3039+
smudge->m_draw = false;
3040+
}
3041+
}
3042+
}
3043+
}
30063044
}
30073045

30083046
// ------------------------------------------------------------------------------------------------

Core/GameEngine/Source/GameClient/System/Smudge.cpp

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ void SmudgeManager::reset()
7676
}
7777
}
7878

79+
void SmudgeManager::resetDraw()
80+
{
81+
SmudgeSet* smudgeSet = m_usedSmudgeSetList.Head();
82+
for (; smudgeSet; smudgeSet = smudgeSet->Succ()) {
83+
smudgeSet->resetDraw();
84+
}
85+
}
86+
7987
SmudgeSet *SmudgeManager::addSmudgeSet()
8088
{
8189
SmudgeSet* set=m_freeSmudgeSetList.Head();
@@ -89,12 +97,25 @@ SmudgeSet *SmudgeManager::addSmudgeSet()
8997
return set;
9098
}
9199

92-
void SmudgeManager::removeSmudgeSet(SmudgeSet &mySmudge)
100+
void SmudgeManager::removeSmudgeSet(SmudgeSet *&smudgeSet)
93101
{
94-
mySmudge.Remove(); //remove from used list
95-
m_freeSmudgeSetList.Add_Head(&mySmudge); //add to free list.
102+
smudgeSet->Remove(); //remove from used list
103+
m_freeSmudgeSetList.Add_Head(smudgeSet); //add to free list.
104+
smudgeSet = nullptr;
96105
}
97106

107+
Smudge *SmudgeManager::findSmudge(Smudge::Identifier identifier)
108+
{
109+
SmudgeSet *smudgeSet = m_usedSmudgeSetList.Head();
110+
for (; smudgeSet; smudgeSet = smudgeSet->Succ()) {
111+
if (Smudge *smudge = smudgeSet->findSmudge(identifier)) {
112+
return smudge;
113+
}
114+
}
115+
return nullptr;
116+
}
117+
118+
98119
SmudgeSet::SmudgeSet()
99120
{
100121
m_usedSmudgeCount=0;
@@ -113,26 +134,50 @@ void SmudgeSet::reset()
113134
m_usedSmudgeList.Remove_Head ();
114135
m_freeSmudgeList.Add_Head(head); //add to free list
115136
}
137+
138+
m_usedSmudgeMap.clear();
139+
m_usedSmudgeCount = 0;
140+
}
141+
142+
void SmudgeSet::resetDraw()
143+
{
144+
Smudge* smudge = m_usedSmudgeList.Head();
145+
for (; smudge; smudge = smudge->Succ()) {
146+
smudge->m_draw = false;
147+
}
116148
}
117149

118-
Smudge *SmudgeSet::addSmudgeToSet()
150+
Smudge *SmudgeSet::addSmudgeToSet(Smudge::Identifier identifier)
119151
{
120-
Smudge* smudge=m_freeSmudgeList.Head();
152+
DEBUG_ASSERTCRASH(m_usedSmudgeMap.find(identifier) == m_usedSmudgeMap.end(),
153+
("SmudgeSet::addSmudgeToSet: identifier already present"));
154+
155+
Smudge* smudge = m_freeSmudgeList.Head();
121156
if (smudge) {
122157
smudge->Remove(); //remove from free list
123-
m_usedSmudgeList.Add_Tail(smudge); //add to used list.
124-
m_usedSmudgeCount++;
125-
return smudge;
158+
} else {
159+
smudge = W3DNEW Smudge();
126160
}
127-
smudge=W3DNEW Smudge();
161+
smudge->m_identifier = identifier;
128162
m_usedSmudgeList.Add_Tail(smudge); //add to used list.
163+
m_usedSmudgeMap[identifier] = smudge;
129164
m_usedSmudgeCount++;
130165
return smudge;
131166
}
132167

133-
void SmudgeSet::removeSmudgeFromSet(Smudge &mySmudge)
168+
void SmudgeSet::removeSmudgeFromSet(Smudge *&smudge)
134169
{
135-
mySmudge.Remove(); //remove from used list.
136-
m_freeSmudgeList.Add_Head(&mySmudge); //add to free list
170+
m_usedSmudgeMap.erase(smudge->m_identifier);
171+
smudge->Remove(); //remove from used list.
172+
m_freeSmudgeList.Add_Head(smudge); //add to free list
173+
smudge = nullptr;
137174
m_usedSmudgeCount--;
138175
}
176+
177+
Smudge *SmudgeSet::findSmudge(Smudge::Identifier identifier)
178+
{
179+
SmudgeIdToPtrMap::const_iterator it = m_usedSmudgeMap.find(identifier);
180+
if (it != m_usedSmudgeMap.end())
181+
return it->second;
182+
return nullptr;
183+
}

Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class DX8IndexBufferClass;
3232

3333
//#define USE_COPY_RECTS 1 //this was the old method that didn't render to texture. Just copied backbuffer into texture. Slow on Nvidia.
3434

35-
class W3DSmudgeManager : public SmudgeManager
35+
class W3DSmudgeManager final : public SmudgeManager
3636
{
3737
public:
3838
W3DSmudgeManager();

Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,16 +366,20 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
366366
Int count = 0;
367367

368368
if (set)
369-
{ //there are possibly some smudges to render, so make sure background particles have finished drawing.
369+
{
370+
//there are possibly some smudges to render, so make sure background particles have finished drawing.
370371
SortingRendererClass::Flush(); //draw sorted translucent polys like particles.
371372
}
372373

373374
while (set)
374375
{
375376
Smudge *smudge=set->getUsedSmudgeList().Head();
376377

377-
while (smudge)
378+
for (; smudge; smudge = smudge->Succ())
378379
{
380+
if (!smudge->m_draw)
381+
continue;
382+
379383
//Get view-space center
380384
Matrix3D::Transform_Vector(view,smudge->m_pos,&vsVert);
381385

@@ -385,6 +389,8 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
385389
//Do center vertex outside 'for' loop since it's different.
386390
verts[4].pos = vsVert;
387391

392+
Vector2 offset = smudge->m_offset;
393+
388394
for (Int i=0; i<4; i++)
389395
{
390396
verts[i].pos = vsVert + vertex_offsets[i] * smudge->m_size;
@@ -399,26 +405,27 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
399405

400406
// Zero coordinates that fall outside valid texel bounds
401407
if (thisUV.X < 0 || thisUV.X > texClampX)
402-
smudge->m_offset.X = 0;
408+
offset.X = 0;
403409

404410
if (thisUV.Y < 0 || thisUV.Y > texClampY)
405-
smudge->m_offset.Y = 0;
411+
offset.Y = 0;
406412
}
407413

408414
//Finish center vertex
409415
//Ge uv coordinates by interpolating corner uv coordinates and applying desired offset.
410416
uvSpanX=verts[3].uv.X - verts[0].uv.X;
411417
uvSpanY=verts[1].uv.Y - verts[0].uv.Y;
412-
verts[4].uv.X=verts[0].uv.X+uvSpanX*(0.5f+smudge->m_offset.X);
413-
verts[4].uv.Y=verts[0].uv.Y+uvSpanY*(0.5f+smudge->m_offset.Y);
418+
verts[4].uv.X=verts[0].uv.X+uvSpanX*(0.5f+offset.X);
419+
verts[4].uv.Y=verts[0].uv.Y+uvSpanY*(0.5f+offset.Y);
414420

415421
count++; //increment visible smudge count.
416-
smudge=smudge->Succ();
417422
}
418423

419424
set=set->Succ(); //advance to next node.
420425
}
421426

427+
m_smudgeCountLastFrame = count;
428+
422429
if (!count)
423430
{
424431
REF_PTR_RELEASE(background);
@@ -481,8 +488,11 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
481488
{
482489
Smudge *smudge=remainingSmudgeStart;
483490

484-
while (smudge)
491+
for (; smudge; smudge=smudge->Succ())
485492
{
493+
if (!smudge->m_draw)
494+
continue;
495+
486496
Smudge::smudgeVertex *smVerts = smudge->m_verts;
487497

488498
//Check if we exceeded maximum number of smudges allowed per draw call.
@@ -513,7 +523,6 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
513523
}
514524

515525
smudgesInRenderBatch++;
516-
smudge=smudge->Succ();
517526
}
518527

519528
set=set->Succ(); //advance to next node.

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DParticleSys.cpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,6 @@ void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
115115
/// @todo lorenzen sez: this should be debug only:
116116
m_onScreenParticleCount = 0;
117117

118-
Int visibleSmudgeCount = 0;
119-
if (TheSmudgeManager)
120-
TheSmudgeManager->setSmudgeCountLastFrame(0); //keep track of visible smudges
121-
122118
const FrustumClass & frustum = rinfo.Camera.Get_Frustum();
123119
AABoxClass bbox;
124120

@@ -141,9 +137,12 @@ void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
141137

142138
m_fieldParticleCount = 0;
143139

144-
SmudgeSet *set=nullptr;
145-
if (TheSmudgeManager)
146-
set=TheSmudgeManager->addSmudgeSet(); //global smudge set through which all smudges are rendered.
140+
const Bool drawSmudge = TheSmudgeManager && TheSmudgeManager->getHardwareSupport() && TheGlobalData->m_useHeatEffects;
141+
142+
if (drawSmudge)
143+
{
144+
TheSmudgeManager->resetDraw();
145+
}
147146

148147
ParticleSystemManager::ParticleSystemList &particleSysList = TheParticleSystemManager->getAllParticleSystems();
149148
for( ParticleSystemManager::ParticleSystemListIt it = particleSysList.begin(); it != particleSysList.end(); ++it)
@@ -160,9 +159,8 @@ void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
160159
//temporary hack that checks if texture name starts with "SMUD" - if so, we can assume it's a smudge type
161160
if (/*sys->isUsingSmudge()*/ *((DWORD *)sys->getParticleTypeName().str()) == 0x44554D53)
162161
{
163-
if (TheSmudgeManager && ((W3DSmudgeManager*)TheSmudgeManager)->getHardwareSupport() && TheGlobalData->m_useHeatEffects)
162+
if (drawSmudge)
164163
{
165-
//set-up all the per-particle
166164
for (Particle *p = sys->getFirstParticle(); p; p = p->m_systemNext)
167165
{
168166
const Coord3D *pos = p->getPosition();
@@ -178,13 +176,11 @@ void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
178176
if (WWMath::Fabs( pos->z - bcZ ) > ( beZ + psize ) )
179177
continue;
180178

181-
Smudge *smudge = set->addSmudgeToSet();
182-
183-
smudge->m_pos.Set( pos->x, pos->y, pos->z );
184-
smudge->m_offset.Set( GameClientRandomValueReal(-0.06f,0.06f), GameClientRandomValueReal(-0.06f,0.06f) );
185-
smudge->m_size = psize;
186-
smudge->m_opacity = p->getAlpha();
187-
visibleSmudgeCount++;
179+
if (Smudge *smudge = TheSmudgeManager->findSmudge(p))
180+
{
181+
// The particle is in view. Draw the smudge!
182+
smudge->m_draw = true;
183+
}
188184
}
189185
}
190186
continue;
@@ -376,7 +372,5 @@ void W3DParticleSystemManager::doParticles(RenderInfoClass &rinfo)
376372
if(TheSmudgeManager)
377373
{
378374
((W3DSmudgeManager *)TheSmudgeManager)->render(rinfo);
379-
TheSmudgeManager->reset(); //clear all the smudges after rendering since we fill again each frame.
380-
TheSmudgeManager->setSmudgeCountLastFrame(visibleSmudgeCount);
381375
}
382376
}

0 commit comments

Comments
 (0)