Don't update relights array while relighting (#1371)

Removing solidmasks temporarily as part of the relighting procedure caused
a landscape update which modified the list of to-be-relighted regions that
is currently being iterated over. This could cause relighting of a region in
which solidmasks have not been removed, leading to vehicle pixels in the
landscape surface used by the landscape shader, which show up pink on the
screen.

Fixed this by introducing C4Landscape::_SetPix2Tmp, which changes a pixel
without causing relighting (or material count updates), and use that when
temporarily removing or putting solidmasks. This should also avoid unnecessary
computations (relighting, material count updates) when updating the landscape
or moving objects with solidmasks.
shapetextures
Armin Burgmeier 2015-11-08 13:33:59 -08:00
parent 9a9486d0fe
commit 236759b1db
3 changed files with 25 additions and 17 deletions

View File

@ -329,7 +329,6 @@ bool C4Landscape::DoRelights()
if (!Relights[i].Wdt)
break;
// Remove all solid masks in the (twice!) extended region around the change
// TODO: Isn't Relights[i] already an "affected" rect? Might save a bit here...
C4Rect SolidMaskRect = pLandscapeRender->GetAffectedRect(Relights[i]);
C4SolidMask * pSolid;
for (pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
@ -704,20 +703,6 @@ bool C4Landscape::SetPix2(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix)
// no change?
if ((fgPix == Transparent || fgPix == _GetPix(x, y)) && (bgPix == Transparent || bgPix == Surface8Bkg->_GetPix(x, y)))
return true;
// note for relight (TODO: Why is this not in _SetPix2?)
if(pLandscapeRender)
{
C4Rect CheckRect = pLandscapeRender->GetAffectedRect(C4Rect(x, y, 1, 1));
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
if (!Relights[i].Wdt || Relights[i].Overlap(CheckRect) || i + 1 >= C4LS_MaxRelights)
{
Relights[i].Add(CheckRect);
break;
}
// Invalidate FoW
if (pFoW)
pFoW->Invalidate(CheckRect);
}
// set pixel
return _SetPix2(x, y, fgPix, bgPix);
}
@ -788,10 +773,32 @@ bool C4Landscape::_SetPix2(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix)
// set 8bpp-surface only!
Surface8->SetPix(x, y, fgPix);
Surface8Bkg->SetPix(x, y, bgPix);
// note for relight
if(pLandscapeRender)
{
C4Rect CheckRect = pLandscapeRender->GetAffectedRect(C4Rect(x, y, 1, 1));
for (int32_t i = 0; i < C4LS_MaxRelights; i++)
if (!Relights[i].Wdt || Relights[i].Overlap(CheckRect) || i + 1 >= C4LS_MaxRelights)
{
Relights[i].Add(CheckRect);
break;
}
// Invalidate FoW
if (pFoW)
pFoW->Invalidate(CheckRect);
}
// success
return true;
}
void C4Landscape::_SetPix2Tmp(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix)
{
// set 8bpp-surface only!
assert(x >= 0 && y >= 0 && x < Width && y < Height);
if (fgPix != Transparent) Surface8->SetPix(x, y, fgPix);
if (bgPix != Transparent) Surface8Bkg->SetPix(x, y, bgPix);
}
bool C4Landscape::CheckInstability(int32_t tx, int32_t ty, int32_t recursion_count)
{
int32_t mat=GetMat(tx,ty);

View File

@ -111,6 +111,7 @@ public:
bool SetMode(int32_t iMode);
bool SetPix2(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix); // set landscape pixel (bounds checked)
bool _SetPix2(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix); // set landsape pixel (bounds not checked)
void _SetPix2Tmp(int32_t x, int32_t y, BYTE fgPix, BYTE bgPix); // set landsape pixel (bounds not checked, no material count updates, no landscape relighting). Material must be reset to original value with this function before modifying landscape in any other way. Only used for temporary pixel changes by SolidMask (C4SolidMask::RemoveTemporary, C4SolidMask::PutTemporary).
bool InsertMaterial(int32_t mat, int32_t *tx, int32_t *ty, int32_t vx = 0, int32_t vy = 0, bool query_only=false); // modifies tx/ty to actual insertion position
bool InsertDeadMaterial(int32_t mat, int32_t tx, int32_t ty);
bool FindMatPath(int32_t &fx, int32_t &fy, int32_t ydir, int32_t mdens, int32_t mslide) const;

View File

@ -354,7 +354,7 @@ void C4SolidMask::RemoveTemporary(C4Rect where)
{
// restore
assert(IsSomeVehicle(GBackPix(x,y)));
::Landscape.SetPix2(x, y, *pPix, ::Landscape.Transparent);
::Landscape._SetPix2Tmp(x, y, *pPix, ::Landscape.Transparent);
}
}
}
@ -375,7 +375,7 @@ void C4SolidMask::PutTemporary(C4Rect where)
{
// put
assert(GBackPix(x,y)==*pPix);
::Landscape.SetPix2(x, y, MaskMaterial, ::Landscape.Transparent);
::Landscape._SetPix2Tmp(x, y, MaskMaterial, ::Landscape.Transparent);
}
}
}