From e348d7b1e1e7ba2b76d9d1196e2507c298d38e68 Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Fri, 23 Nov 2018 15:22:35 -0500 Subject: [PATCH] Tons of performance gained. --- OpenDiablo2.Common/Models/ImageSet.cs | 8 +- OpenDiablo2.Core/MPQProvider.cs | 13 +++- OpenDiablo2.SDL2/SDL2Label.cs | 5 +- OpenDiablo2.SDL2/SDL2RenderWindow.cs | 10 +-- OpenDiablo2.SDL2/SDL2Sprite.cs | 107 +++++++++++++------------- 5 files changed, 78 insertions(+), 65 deletions(-) diff --git a/OpenDiablo2.Common/Models/ImageSet.cs b/OpenDiablo2.Common/Models/ImageSet.cs index 605b29ac..686924a1 100644 --- a/OpenDiablo2.Common/Models/ImageSet.cs +++ b/OpenDiablo2.Common/Models/ImageSet.cs @@ -26,15 +26,15 @@ namespace OpenDiablo2.Common.Models ImageData = new Int16[0]; } - public Color GetColor(int x, int y, Palette palette) + public UInt32 GetColor(int x, int y, Palette palette) { var index = ImageData[x + (y * Width)]; if (index == -1) - return Color.Transparent; + return 0; - var color = palette.Colors[(int)index]; + var color = palette.Colors[index]; - return Color.FromArgb(255, color.R, color.G, color.B); + return ((UInt32)255 << 24) + ((UInt32)color.R << 16) + ((UInt32)color.G << 8) + (UInt32)color.B; } } diff --git a/OpenDiablo2.Core/MPQProvider.cs b/OpenDiablo2.Core/MPQProvider.cs index 7d4f22aa..f4397ab9 100644 --- a/OpenDiablo2.Core/MPQProvider.cs +++ b/OpenDiablo2.Core/MPQProvider.cs @@ -13,6 +13,7 @@ namespace OpenDiablo2.Core { private readonly GlobalConfiguration globalConfiguration; private readonly MPQ[] mpqs; + private Dictionary mpqLookup = new Dictionary(); public MPQProvider(GlobalConfiguration globalConfiguration) { @@ -22,12 +23,22 @@ namespace OpenDiablo2.Core .Where(x => !Path.GetFileName(x).StartsWith("patch")) .Select(file => new MPQ(file)) .ToArray(); + + for(var i = 0; i < mpqs.Count(); i++) + { + foreach(var file in mpqs[i].Files) + { + mpqLookup[file.ToLower()] = i; + } + } } public IEnumerable GetMPQs() => mpqs; public Stream GetStream(string fileName) - => mpqs.First(x => x.Files.Any(z =>z.ToLower() == fileName.ToLower())).OpenFile(fileName); + { + return mpqs[mpqLookup[fileName.ToLower()]].OpenFile(fileName); + } public IEnumerable> GetTextFile(string fileName) { diff --git a/OpenDiablo2.SDL2/SDL2Label.cs b/OpenDiablo2.SDL2/SDL2Label.cs index 55d450a4..46027e0f 100644 --- a/OpenDiablo2.SDL2/SDL2Label.cs +++ b/OpenDiablo2.SDL2/SDL2Label.cs @@ -111,8 +111,9 @@ namespace OpenDiablo2.SDL2_ h = font.sprite.FrameSize.Height }; - SDL.SDL_SetTextureColorMod(font.sprite.textures[character], TextColor.R, TextColor.G, TextColor.B); - SDL.SDL_RenderCopy(renderer, font.sprite.textures[character], IntPtr.Zero, ref rect); + font.sprite.Frame = character; + SDL.SDL_SetTextureColorMod(font.sprite.texture, TextColor.R, TextColor.G, TextColor.B); + SDL.SDL_RenderCopy(renderer, font.sprite.texture, IntPtr.Zero, ref rect); } diff --git a/OpenDiablo2.SDL2/SDL2RenderWindow.cs b/OpenDiablo2.SDL2/SDL2RenderWindow.cs index 6f1a1831..4f85c00a 100644 --- a/OpenDiablo2.SDL2/SDL2RenderWindow.cs +++ b/OpenDiablo2.SDL2/SDL2RenderWindow.cs @@ -70,6 +70,8 @@ namespace OpenDiablo2.SDL2_ public void Clear() { + SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero); + SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL.SDL_RenderClear(renderer); } @@ -148,7 +150,7 @@ namespace OpenDiablo2.SDL2_ w = spr.FrameSize.Width, h = spr.FrameSize.Height }; - SDL.SDL_RenderCopy(renderer, spr.textures[spr.Frame], IntPtr.Zero, ref destRect); + SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect); } @@ -162,9 +164,7 @@ namespace OpenDiablo2.SDL2_ for (var x = 0; x < xSegments; x++) { var textureIndex = x + (y * xSegments) + (offset * xSegments * ySegments); - textureIndex = Math.Min(spr.textures.Count() - 1, Math.Max(0, textureIndex)); - if (textureIndex >= spr.textures.Count()) - continue; + spr.Frame = Math.Min(spr.TotalFrames - 1, Math.Max(0, textureIndex)); var destRect = new SDL.SDL_Rect { @@ -173,7 +173,7 @@ namespace OpenDiablo2.SDL2_ w = spr.FrameSize.Width, h = spr.FrameSize.Height }; - SDL.SDL_RenderCopy(renderer, spr.textures[textureIndex], IntPtr.Zero, ref destRect); + SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect); } } } diff --git a/OpenDiablo2.SDL2/SDL2Sprite.cs b/OpenDiablo2.SDL2/SDL2Sprite.cs index 7de58d32..8573d028 100644 --- a/OpenDiablo2.SDL2/SDL2Sprite.cs +++ b/OpenDiablo2.SDL2/SDL2Sprite.cs @@ -1,14 +1,10 @@ -using OpenDiablo2.Common.Interfaces; -using System; -using System.Collections.Generic; +using System; using System.Drawing; -using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SDL2; using System.Runtime.InteropServices; +using OpenDiablo2.Common.Interfaces; using OpenDiablo2.Common.Models; +using SDL2; namespace OpenDiablo2.SDL2_ { @@ -16,16 +12,24 @@ namespace OpenDiablo2.SDL2_ { static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + internal readonly ImageSet source; + private readonly IntPtr renderer; + internal IntPtr texture = IntPtr.Zero; + public Point Location { get; set; } = new Point(); public Size FrameSize { get; set; } = new Size(); - private int frame; + private int frame = -1; public int Frame { get => frame; set { + if (frame == value && texture != IntPtr.Zero) + return; + frame = Math.Max(0, Math.Min(value, TotalFrames)); + LoadFrame(frame); } } public int TotalFrames { get; internal set; } @@ -37,9 +41,7 @@ namespace OpenDiablo2.SDL2_ set { blend = value; - - foreach (var texture in textures) - SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); + SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); } } @@ -53,9 +55,7 @@ namespace OpenDiablo2.SDL2_ UpdateTextureData(); } } - internal readonly ImageSet source; - private readonly IntPtr renderer; - internal IntPtr[] textures = new IntPtr[0]; + public SDL2Sprite(ImageSet source, IntPtr renderer) { @@ -63,14 +63,8 @@ namespace OpenDiablo2.SDL2_ this.renderer = renderer; - this.TotalFrames = source.Frames.Count(); - this.FrameSize = new Size(Pow2((int)source.Frames.Max(x => x.Width)), Pow2((int)source.Frames.Max(x => x.Height))); - this.textures = new IntPtr[TotalFrames]; - for(var i = 0; i < this.textures.Count(); i++) - { - this.textures[i] = IntPtr.Zero; - } - + TotalFrames = source.Frames.Count(); + FrameSize = new Size(Pow2((int)source.Frames.Max(x => x.Width)), Pow2((int)source.Frames.Max(x => x.Height))); } internal Point GetRenderPoint() @@ -84,8 +78,16 @@ namespace OpenDiablo2.SDL2_ // TODO: This is slow. Make fix. private void UpdateTextureData() { - for (var i = 0; i < source.Frames.Count(); i++) - LoadFrame(i, renderer); + if (texture == IntPtr.Zero) + { + texture = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, Pow2(FrameSize.Width), Pow2(FrameSize.Height)); + + if (texture == IntPtr.Zero) + throw new ApplicationException("Unaple to initialize texture."); + + Frame = 0; + } + } // TODO: Less dumb color correction @@ -97,39 +99,41 @@ namespace OpenDiablo2.SDL2_ (byte)Math.Min((float)source.B * 1.2, 255) ); - object bob = new object(); - private void LoadFrame(int index, IntPtr renderer) + private unsafe void LoadFrame(int index) { var frame = source.Frames[index]; - if (textures[index] == IntPtr.Zero) - textures[index] = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, Pow2(FrameSize.Width), Pow2(FrameSize.Height)); + IntPtr pixels; + int pitch; + var fullRect = new SDL.SDL_Rect { x = 0, y = 0, w = FrameSize.Width, h = FrameSize.Height }; + SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); - if (textures[index] == IntPtr.Zero) - throw new ApplicationException("Unaple to initialize texture."); - - SDL.SDL_SetTextureBlendMode(textures[index], SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND); - SDL.SDL_SetRenderTarget(renderer, textures[index]); - SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); - SDL.SDL_RenderFillRect(renderer, IntPtr.Zero); - SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero); - - var binaryData = new UInt32[frame.Width * frame.Height]; - for (var y = 0; y < frame.Height; y++) + SDL.SDL_LockTexture(texture, IntPtr.Zero, out pixels, out pitch); + try { - for (int x = 0; x < frame.Width; x++) + UInt32* data = (UInt32*)pixels; + var frameOffset = FrameSize.Height - frame.Height; + for (var y = 0; y < FrameSize.Height; y++) { - var palColor = frame.GetColor(x, (int)y, CurrentPalette); - //var col = AdjustColor(palColor); - binaryData[x + y * frame.Width] = (uint)palColor.ToArgb(); + for (int x = 0; x < FrameSize.Width; x++) + { + if ((x >= frame.Width) || (y < frameOffset)) + { + data[x + (y * (pitch / 4))] = 0; + continue; + } + + + var palColor = frame.GetColor(x, (int)(y - frameOffset), CurrentPalette); + //var col = AdjustColor(palColor); + data[x + (y * (pitch / 4))] = palColor; + } } } - - - var rect = new SDL.SDL_Rect { x = 0, y = FrameSize.Height - (int)frame.Height, w = (int)frame.Width, h = (int)frame.Height }; - GCHandle pinnedArray = GCHandle.Alloc(binaryData, GCHandleType.Pinned); - SDL.SDL_UpdateTexture(textures[index], ref rect, pinnedArray.AddrOfPinnedObject(), (int)frame.Width * 4); - pinnedArray.Free(); + finally + { + SDL.SDL_UnlockTexture(texture); + } } @@ -144,10 +148,7 @@ namespace OpenDiablo2.SDL2_ public void Dispose() { - foreach (var texture in textures) - { - SDL.SDL_DestroyTexture(texture); - } + SDL.SDL_DestroyTexture(texture); } } }