From ef362473aee11dc4c49b944b9874471998d16449 Mon Sep 17 00:00:00 2001 From: wixoa Date: Fri, 7 Jun 2024 00:46:26 -0400 Subject: [PATCH] Fix color/filter rendering on keep-together icons (#1830) --- OpenDreamClient/Rendering/DreamIcon.cs | 42 ++++++++++++------- OpenDreamClient/Rendering/DreamViewOverlay.cs | 9 ++-- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/OpenDreamClient/Rendering/DreamIcon.cs b/OpenDreamClient/Rendering/DreamIcon.cs index 0f1306d708..5901628216 100644 --- a/OpenDreamClient/Rendering/DreamIcon.cs +++ b/OpenDreamClient/Rendering/DreamIcon.cs @@ -65,27 +65,36 @@ public void Dispose() { } public Texture? GetTexture(DreamViewOverlay viewOverlay, DrawingHandleWorld handle, RendererMetaData iconMetaData, Texture? textureOverride = null) { - if (Appearance == null || DMI == null) - return textureOverride; + Texture? frame; - var animationFrame = AnimationFrame; - if (textureOverride == null && CachedTexture != null && !_textureDirty) - return CachedTexture; + if (textureOverride == null) { + if (Appearance == null || DMI == null) + return null; + + var animationFrame = AnimationFrame; + if (CachedTexture != null && !_textureDirty) + return CachedTexture; + + _textureDirty = false; + frame = DMI.GetState(Appearance.IconState)?.GetFrames(Appearance.Direction)[animationFrame]; + } else { + frame = textureOverride; + } + + var canSkipFullRender = Appearance?.Filters.Count is 0 or null && + iconMetaData.ColorToApply == Color.White && + iconMetaData.ColorMatrixToApply.Equals(ColorMatrix.Identity) && + iconMetaData.AlphaToApply.Equals(1.0f); - var frame = textureOverride ?? DMI.GetState(Appearance.IconState)?.GetFrames(Appearance.Direction)[animationFrame]; if (frame == null) { CachedTexture = null; - } else if ((Appearance.Filters.Count == 0 && iconMetaData.ColorToApply == Color.White && - iconMetaData.ColorMatrixToApply.Equals(ColorMatrix.Identity)) && iconMetaData.AlphaToApply.Equals(1.0f)) { + } else if (canSkipFullRender) { TextureRenderOffset = Vector2.Zero; CachedTexture = frame; } else { CachedTexture = FullRenderTexture(viewOverlay, handle, iconMetaData, frame); } - if (textureOverride == null) - _textureDirty = false; - return CachedTexture; } @@ -181,7 +190,7 @@ private void UpdateAnimation() { elapsedTime -= frames[_animationFrame].Delay; _animationFrameTime += frames[_animationFrame].Delay; _animationFrame++; - _textureDirty = true; + DirtyTexture(); if (_animationFrame >= frames.Length) _animationFrame -= frames.Length; } @@ -387,7 +396,7 @@ private void UpdateAnimation() { } private void UpdateIcon() { - _textureDirty = true; + DirtyTexture(); if (Appearance == null) { DMI = null; @@ -426,7 +435,7 @@ private void UpdateIcon() { /// /// Perform a full (slower) render of this icon's texture, including filters and color /// - /// In a separate method to avoid allocations when not executed + /// In a separate method to avoid closure allocations when not executed /// The final texture private Texture FullRenderTexture(DreamViewOverlay viewOverlay, DrawingHandleWorld handle, RendererMetaData iconMetaData, Texture frame) { if (_ping?.Size != frame.Size * 2 || _pong == null) { @@ -483,6 +492,11 @@ private void CheckSizeChange() { } } + private void DirtyTexture() { + _textureDirty = true; + CachedTexture = null; + } + private struct AppearanceAnimation(DateTime start, TimeSpan duration, IconAppearance endAppearance, AnimationEasing easing, int loops, AnimationFlags flags, int delay) { public readonly DateTime Start = start; public readonly TimeSpan Duration = duration; diff --git a/OpenDreamClient/Rendering/DreamViewOverlay.cs b/OpenDreamClient/Rendering/DreamViewOverlay.cs index eefd79dea7..9f260f2144 100644 --- a/OpenDreamClient/Rendering/DreamViewOverlay.cs +++ b/OpenDreamClient/Rendering/DreamViewOverlay.cs @@ -413,17 +413,15 @@ public void DrawIcon(DrawingHandleWorld handle, Vector2i renderTargetSize, Rende if (icon == null) return; - var frame = iconMetaData.GetTexture(this, handle); - //KEEP_TOGETHER groups if (iconMetaData.KeepTogetherGroup?.Count > 0) { // TODO: Use something better than a hardcoded 64x64 fallback - Vector2i ktSize = frame?.Size ?? (64,64); + Vector2i ktSize = iconMetaData.MainIcon?.DMI?.IconSize ?? (64,64); iconMetaData.TextureOverride = ProcessKeepTogether(handle, iconMetaData, ktSize); - frame = iconMetaData.TextureOverride; positionOffset -= ((ktSize/EyeManager.PixelsPerMeter) - Vector2.One) * new Vector2(0.5f); //correct for KT group texture offset } + var frame = iconMetaData.GetTexture(this, handle); var pixelPosition = (iconMetaData.Position + positionOffset) * EyeManager.PixelsPerMeter; //if frame is null, this doesn't require a draw, so return NOP @@ -768,13 +766,12 @@ private Texture ProcessKeepTogether(DrawingHandleWorld handle, RendererMetaData ktItems.Sort(); //draw it onto an additional render target that we can return immediately for correction of transform IRenderTexture tempTexture = RentRenderTarget(size); - ClearRenderTarget(tempTexture, handle, Color.Transparent); handle.RenderInRenderTarget(tempTexture, () => { foreach (RendererMetaData ktItem in ktItems) { DrawIcon(handle, tempTexture.Size, ktItem, -ktItem.Position+((tempTexture.Size/EyeManager.PixelsPerMeter) - Vector2.One) * new Vector2(0.5f)); //draw the icon in the centre of the KT render target } - }, null); + }, Color.Transparent); //but keep the handle to the final KT group's render target so we don't override it later in the render cycle IRenderTexture ktTexture = RentRenderTarget(tempTexture.Size);