Quote from: WillLem on April 07, 2026, 10:39:10 PMAlways happy to accept help wherever offered! It's good to not have to always figure these things out on my ownI am SO happy to hear this.
Besides, I figured that some re-rendering prevention guard is what was needed. You helped pin it down to exactly where the guard needed to be - this is much appreciated!
Quote from: roltemurto on April 07, 2026, 09:18:38 PMI hope I don't overstep my boundaries by doing this but I just want to be helpful.

Quote from: roltemurto on April 07, 2026, 09:18:38 PMFix 1 — Re-entrancy guard on ResetLevelImage
Prevent NLEditForm_Resize from triggering a render if one is already in progress
Quote from: roltemurto on April 07, 2026, 09:18:38 PMFix 2 — Ensure UnlockBits is always called in BmpModify.DrawOn
The existing DrawOn method almost certainly does LockBits without a try/finally guarantee on UnlockBits. If any exception occurs mid-render, the bitmap stays locked forever for the lifetime of the object. Fix the locking pattern:
Quote from: roltemurto on April 07, 2026, 09:18:38 PMFix 3 (optional hardening) — Debounce resize events
Resize events can fire dozens of times per second during a resolution change. Even with the re-entrancy guard, it is worth debouncing to avoid hammering the renderer immediately after wake:
Quote from: WillLem on April 07, 2026, 03:45:11 PMNot sure exactly why the exception occurred though. Maybe more resolution-specific guards need to be in place.
NLEditForm_Resize → ResetLevelImage → CombineLayers → CreateLevelImageFromLayers → BmpModify.DrawOn → Bitmap.LockBits// In SLXEditForm:
private bool _isRendering = false;
private void ResetLevelImage()
{
if (_isRendering) return; // Guard against re-entrant calls
_isRendering = true;
try
{
// ... existing ResetLevelImage body ...
}
finally
{
_isRendering = false;
}
}// In BmpModify.DrawOn — wrap the LockBits/UnlockBits pair in try/finally:
BitmapData bmpData = null;
try
{
bmpData = origBmp.LockBits(rect, ImageLockMode.ReadOnly, origBmp.PixelFormat);
// ... pixel operations ...
}
finally
{
if (bmpData != null)
origBmp.UnlockBits(bmpData);
}private System.Windows.Forms.Timer _resizeDebounce;
private void NLEditForm_Resize(object sender, EventArgs e)
{
if (_resizeDebounce == null)
{
_resizeDebounce = new System.Windows.Forms.Timer { Interval = 150 };
_resizeDebounce.Tick += (s, _) =>
{
_resizeDebounce.Stop();
ResetLevelImage();
};
}
_resizeDebounce.Stop();
_resizeDebounce.Start();
}| Fix | What it addresses |
| Re-entrancy guard (_isRendering) | Stops a second render from starting while one is in progress |
| try/finally around LockBits | Guarantees unlock even if a render throws mid-way |
| Resize debounce | Reduces needless render thrash during resolution changes |
