1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-12-25 11:36:26 -05:00

Lots of optimizations.

This commit is contained in:
Tim Sarbin 2018-12-09 14:55:01 -05:00
parent 0ead3f15c8
commit 0b3124750d
21 changed files with 137 additions and 71 deletions

View File

@ -15,8 +15,8 @@ namespace OpenDiablo2.Common.Interfaces
void Sync();
void Quit();
uint GetTicks();
ISprite LoadSprite(string resourcePath, string palette, Point location);
ISprite LoadSprite(string resourcePath, string palette);
ISprite LoadSprite(string resourcePath, string palette, Point location, bool cacheFrames = false);
ISprite LoadSprite(string resourcePath, string palette, bool cacheFrames = false);
IFont LoadFont(string resourcePath, string palette);
ILabel CreateLabel(IFont font);
ILabel CreateLabel(IFont font, string text);

View File

@ -35,5 +35,8 @@ namespace OpenDiablo2.Common.Interfaces
/// <param name="cacheItemPolicy">Pass in a new policy to control how this item is handled. Typically you can leave this null.</param>
/// <returns>The item requested</returns>
T AddOrGetExisting<T>(string key, Func<T> valueFactory, CacheItemPolicy cacheItemPolicy = null);
bool Exists(string key);
T GetExisting<T>(string key) where T : class, new();
void Add<T>(string key, T value, CacheItemPolicy cacheItemPolicy = null);
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace OpenDiablo2.Common.Models
{
@ -33,6 +34,7 @@ namespace OpenDiablo2.Common.Models
return _current & 0xff;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EnsureBits(int bitCount)
{
if (bitCount <= _bitCount) return true;

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
namespace OpenDiablo2.Common.Models
{
@ -22,17 +23,11 @@ namespace OpenDiablo2.Common.Models
ImageData = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UInt32 GetColor(int x, int y, Palette palette)
{
var i = x + (y * Width);
if (i >= ImageData.Length)
return 0;
var index = ImageData[i];
if (index == -1)
return 0;
return palette.Colors[index];
var index = ImageData[x + (y * Width)];
return index == -1 ? 0 : palette.Colors[index];
}
}

View File

@ -40,5 +40,12 @@ namespace OpenDiablo2.Core
throw;
}
}
public bool Exists(string key) => _cache.Contains(key);
public T GetExisting<T>(string key) where T : class, new() => (_cache.Get(key) as Lazy<T>)?.Value;
public void Add<T>(string key, T value, CacheItemPolicy cacheItemPolicy = null) => _cache.Add(key, value, cacheItemPolicy ?? new CacheItemPolicy());
}
}

View File

@ -22,9 +22,7 @@ namespace OpenDiablo2.Core
private IScene currentScene;
private IScene nextScene = null;
private readonly MPQ[] MPQs;
private readonly Dictionary<string, SoundEntry> soundTable = new Dictionary<string, SoundEntry>();
public Dictionary<string, Palette> PaletteTable { get; private set; } = new Dictionary<string, Palette>();
@ -92,7 +90,9 @@ namespace OpenDiablo2.Core
if (ms < 33)
{
Thread.Sleep(33 - (int)ms);
continue;
} else
{
log.Info($"Full frame time used - {ms} milliseconds to frame");
}
// Prevent falco-punch updates

View File

@ -82,7 +82,7 @@ namespace OpenDiablo2.Core.UI
font = renderWindow.LoadFont(ResourcePaths.FontExocet10, Palettes.Units);
label = renderWindow.CreateLabel(font);
sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName);
sprite = renderWindow.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName, true);
// TODO: Less stupid way of doing this would be nice
buttonWidth = 0;

View File

@ -38,7 +38,7 @@ namespace OpenDiablo2.Core.UI
{
this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Act1, FrameType.GetOffset());
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Act1, FrameType.GetOffset(), true);
closeButton = createButton(eButtonType.Close);
closeButton.Location = sprite.Location + new Size(128, 388);

View File

@ -62,9 +62,9 @@ namespace OpenDiablo2.Core.UI
menuButton.OnToggle = minipanel.OnMenuToggle;
menuButton.Toggle();
panelSprite = renderWindow.LoadSprite(ResourcePaths.GamePanels, Palettes.Act1);
healthManaSprite = renderWindow.LoadSprite(ResourcePaths.HealthMana, Palettes.Act1);
gameGlobeOverlapSprite = renderWindow.LoadSprite(ResourcePaths.GameGlobeOverlap, Palettes.Act1);
panelSprite = renderWindow.LoadSprite(ResourcePaths.GamePanels, Palettes.Act1, true);
healthManaSprite = renderWindow.LoadSprite(ResourcePaths.HealthMana, Palettes.Act1, true);
gameGlobeOverlapSprite = renderWindow.LoadSprite(ResourcePaths.GameGlobeOverlap, Palettes.Act1, true);
}
public IPanel LeftPanel { get; private set; }

View File

@ -51,7 +51,7 @@ namespace OpenDiablo2.Core.UI
{
this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Units, FrameType.GetOffset());
sprite = renderWindow.LoadSprite(ResourcePaths.InventoryCharacterPanel, Palettes.Units, FrameType.GetOffset(), true);
closeButton = createButton(eButtonType.Close);
closeButton.Location = sprite.Location + new Size(18, 384);

View File

@ -47,7 +47,7 @@ namespace OpenDiablo2.Core.UI
this.itemContainerLayout = itemContainerLayout;
this.mouseInfoProvider = mouseInfoProvider;
placeholderSprite = renderWindow.LoadSprite(itemContainerLayout.ResourceName, itemContainerLayout.PaletteName);
placeholderSprite = renderWindow.LoadSprite(itemContainerLayout.ResourceName, itemContainerLayout.PaletteName, true);
placeholderSprite.Location = new Point(location.X, location.Y + placeholderSprite.LocalFrameSize.Height);
this.Size = placeholderSprite.FrameSize; // For all but generic size is equal to the placeholder size. Source: me.
}
@ -58,7 +58,7 @@ namespace OpenDiablo2.Core.UI
if (ContainedItem != null)
{
sprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(this.ContainedItem.InvFile), Palettes.Units);
sprite = renderWindow.LoadSprite(ResourcePaths.GeneratePathForItem(this.ContainedItem.InvFile), Palettes.Units, true);
sprite.Location = new Point(location.X, location.Y + sprite.LocalFrameSize.Height);
}
}

View File

@ -35,7 +35,7 @@ namespace OpenDiablo2.Core.UI
this.gameState = gameState;
this.panels = panels;
sprite = renderWindow.LoadSprite(ResourcePaths.MinipanelSmall, Palettes.Units);
sprite = renderWindow.LoadSprite(ResourcePaths.MinipanelSmall, Palettes.Units, true);
buttons = panelButtons.Select((x, i) =>
{

View File

@ -19,7 +19,7 @@ namespace OpenDiablo2.Core.UI
this.renderWindow = renderWindow;
this.panelFrameType = panelFrameType;
sprite = renderWindow.LoadSprite(ResourcePaths.Frame, Palettes.Units, new Point(0, 0));
sprite = renderWindow.LoadSprite(ResourcePaths.Frame, Palettes.Units, new Point(0, 0), true);
Location = new Point(0, 0);

View File

@ -75,7 +75,7 @@ namespace OpenDiablo2.Core.UI
{
this.renderWindow = renderWindow;
sprite = renderWindow.LoadSprite(ResourcePaths.TextBox2, Palettes.Units);
sprite = renderWindow.LoadSprite(ResourcePaths.TextBox2, Palettes.Units, true);
font = renderWindow.LoadFont(ResourcePaths.FontFormal11, Palettes.Units);
label = renderWindow.CreateLabel(font);
linebar = renderWindow.CreateLabel(font);

View File

@ -36,7 +36,7 @@ namespace OpenDiablo2.SDL2_
{
this.font = font;
sprite = new SDL2Sprite(font.FontImageSet, renderer);
sprite = new SDL2Sprite(font.FontImageSet, renderer, true);
}
public void Dispose()

View File

@ -210,8 +210,8 @@ namespace OpenDiablo2.SDL2_
};
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);
SDL.SDL_SetTextureColorMod(font.sprite.Texture, TextColor.R, TextColor.G, TextColor.B);
SDL.SDL_RenderCopy(renderer, font.sprite.Texture, IntPtr.Zero, ref rect);
}

View File

@ -75,6 +75,9 @@ namespace OpenDiablo2.SDL2_
public int PlaySfx(byte[] data)
{
if (data == null || data.Length == 0)
return -1;
var sound = SDL_mixer.Mix_QuickLoad_WAV(data);
return SDL_mixer.Mix_PlayChannel(-1, sound, 0);
}

View File

@ -242,7 +242,7 @@ namespace OpenDiablo2.SDL2_
public void Draw(ISprite sprite)
{
var spr = sprite as SDL2Sprite;
if (spr.texture == IntPtr.Zero)
if (spr.Texture == IntPtr.Zero)
return;
var loc = spr.GetRenderPoint();
@ -254,7 +254,7 @@ namespace OpenDiablo2.SDL2_
w = spr.FrameSize.Width,
h = spr.FrameSize.Height
};
SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect);
SDL.SDL_RenderCopy(renderer, spr.Texture, IntPtr.Zero, ref destRect);
}
@ -276,15 +276,15 @@ namespace OpenDiablo2.SDL2_
w = spr.FrameSize.Width,
h = spr.FrameSize.Height
};
SDL.SDL_RenderCopy(renderer, spr.texture, IntPtr.Zero, ref destRect);
SDL.SDL_RenderCopy(renderer, spr.Texture, IntPtr.Zero, ref destRect);
}
}
}
public ISprite LoadSprite(string resourcePath, string palette) => LoadSprite(resourcePath, palette, Point.Empty);
public ISprite LoadSprite(string resourcePath, string palette, Point location)
public ISprite LoadSprite(string resourcePath, string palette, bool cacheFrames = false) => LoadSprite(resourcePath, palette, Point.Empty, cacheFrames);
public ISprite LoadSprite(string resourcePath, string palette, Point location, bool cacheFrames = false)
{
var result = new SDL2Sprite(resourceManager.GetImageSet(resourcePath), renderer)
var result = new SDL2Sprite(resourceManager.GetImageSet(resourcePath), renderer, cacheFrames)
{
CurrentPalette = paletteProvider.PaletteTable[palette],
Location = location
@ -437,7 +437,7 @@ namespace OpenDiablo2.SDL2_
SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL.SDL_SetRenderTarget(renderer, texId);
SDL.SDL_RenderCopy(renderer, (sprite as SDL2Sprite).texture, IntPtr.Zero, IntPtr.Zero);
SDL.SDL_RenderCopy(renderer, (sprite as SDL2Sprite).Texture, IntPtr.Zero, IntPtr.Zero);
SDL.SDL_SetRenderTarget(renderer, IntPtr.Zero);
return new SDL2MouseCursor

View File

@ -28,7 +28,23 @@ namespace OpenDiablo2.SDL2_
{
internal readonly ImageSet source;
private readonly IntPtr renderer;
internal IntPtr texture = IntPtr.Zero;
private readonly bool cacheFrames;
private bool disposed = false;
private IntPtr[] texture;
private bool[] frameLoaded;
public IntPtr Texture
{
get
{
if (!frameLoaded[TextureIndex])
LoadFrame();
return texture[TextureIndex];
}
}
public Point Location { get; set; }
public Size FrameSize { get; set; }
@ -43,21 +59,25 @@ namespace OpenDiablo2.SDL2_
if (darken == value)
return;
darken = value;
LoadFrame(frame);
ClearAllFrames();
}
}
private int frame = -1;
private int frame;
public int Frame
{
get => frame;
set
{
if (frame == value && texture != IntPtr.Zero)
if (frame == value)
return;
frame = Math.Max(0, Math.Min(value, TotalFrames));
LoadFrame(frame);
if (cacheFrames)
return;
frameLoaded[TextureIndex] = false;
}
}
public int TotalFrames { get; internal set; }
@ -69,7 +89,16 @@ namespace OpenDiablo2.SDL2_
set
{
blend = value;
SDL.SDL_SetTextureBlendMode(texture, blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
if (cacheFrames)
{
for (var i = 0; i < TotalFrames; i++)
if (texture[i] != IntPtr.Zero)
SDL.SDL_SetTextureBlendMode(texture[i], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
}
else
if (texture[TextureIndex] != IntPtr.Zero)
SDL.SDL_SetTextureBlendMode(texture[TextureIndex], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
}
}
@ -80,23 +109,31 @@ namespace OpenDiablo2.SDL2_
set
{
palette = value;
UpdateTextureData();
ClearAllFrames();
}
}
private int TextureIndex => cacheFrames ? frame : 0;
public SDL2Sprite(ImageSet source, IntPtr renderer)
public SDL2Sprite(ImageSet source, IntPtr renderer, bool cacheFrames = false)
{
this.source = source;
this.renderer = renderer;
this.cacheFrames = cacheFrames;
texture = new IntPtr[cacheFrames ? source.Frames.Count() : 1];
frameLoaded = new bool[cacheFrames ? source.Frames.Count() : 1];
TotalFrames = source.Frames.Count();
ClearAllFrames();
Location = Point.Empty;
FrameSize = new Size(Pow2((int)source.Frames.Max(x => x.Width)), Pow2((int)source.Frames.Max(x => x.Height)));
Frame = 0;
}
internal Point GetRenderPoint()
{
return source == null
@ -108,31 +145,30 @@ namespace OpenDiablo2.SDL2_
private void UpdateTextureData()
{
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 OpenDiablo2Exception("Unaple to initialize texture.");
Frame = 0;
}
Frame = 0;
}
private unsafe void LoadFrame(int index)
private unsafe void LoadFrame()
{
var sourceFrame = source.Frames[index];
//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 (texture[TextureIndex] == IntPtr.Zero)
{
texture[TextureIndex] = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, Pow2(FrameSize.Width), Pow2(FrameSize.Height));
SDL.SDL_LockTexture(texture, IntPtr.Zero, out IntPtr pixels, out int pitch);
if (texture[TextureIndex] == IntPtr.Zero)
throw new OpenDiablo2Exception("Unaple to initialize texture.");
SDL.SDL_SetTextureBlendMode(texture[TextureIndex], blend ? SDL.SDL_BlendMode.SDL_BLENDMODE_ADD : SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);
}
var sourceFrame = source.Frames[frame];
SDL.SDL_LockTexture(texture[TextureIndex], IntPtr.Zero, out IntPtr pixels, out int pitch);
try
{
UInt32* data = (UInt32*)pixels;
var frameOffset = FrameSize.Height - sourceFrame.Height;
var frameWidth = FrameSize.Width;
var frameHeight = FrameSize.Height;
for (var y = 0; y < frameHeight; y++)
for (int y = 0; y < frameHeight; y++)
{
for (int x = 0; x < frameWidth; x++)
{
@ -151,10 +187,10 @@ namespace OpenDiablo2.SDL2_
}
finally
{
SDL.SDL_UnlockTexture(texture);
SDL.SDL_UnlockTexture(texture[TextureIndex]);
}
frameLoaded[TextureIndex] = true;
}
private int Pow2(int val)
@ -165,9 +201,27 @@ namespace OpenDiablo2.SDL2_
return result;
}
private void ClearAllFrames()
{
var framestoClear = cacheFrames ? TotalFrames : 1;
for (int i = 0; i < framestoClear; i++)
frameLoaded[i] = false;
}
public void Dispose()
{
SDL.SDL_DestroyTexture(texture);
if (disposed)
return;
var framestoClear = cacheFrames ? TotalFrames : 1;
for (var i = 0; i < framestoClear; i++)
{
SDL.SDL_DestroyTexture(texture[i]);
texture[i] = IntPtr.Zero;
}
texture = Array.Empty<IntPtr>();
disposed = true;
}
}

View File

@ -20,7 +20,7 @@ namespace OpenDiablo2.Scenes
builder
.RegisterType(type)
.Keyed<IScene>(att.SceneType)
.SingleInstance();
.InstancePerDependency();
}
}
}

View File

@ -228,18 +228,19 @@ namespace OpenDiablo2.Scenes
Parallel.ForEach(new[]
{
ResourcePaths.SFXAmazonSelect,
ResourcePaths.SFXAmazonDeselect,
ResourcePaths.SFXAssassinSelect,
ResourcePaths.SFXAssassinDeselect,
ResourcePaths.SFXBarbarianSelect,
ResourcePaths.SFXBarbarianDeselect,
ResourcePaths.SFXDruidSelect,
ResourcePaths.SFXDruidDeselect,
ResourcePaths.SFXNecromancerSelect,
ResourcePaths.SFXNecromancerDeselect,
ResourcePaths.SFXPaladinSelect,
ResourcePaths.SFXPaladinDeselect,
ResourcePaths.SFXSorceressSelect,
ResourcePaths.SFXAmazonDeselect,
ResourcePaths.SFXAssassinDeselect,
ResourcePaths.SFXBarbarianDeselect,
ResourcePaths.SFXDruidDeselect,
ResourcePaths.SFXNecromancerDeselect,
ResourcePaths.SFXPaladinDeselect,
ResourcePaths.SFXSorceressDeselect
}, (path => sfxDictionary.Add(path, mpqProvider.GetBytes(path))));
}
@ -609,6 +610,7 @@ namespace OpenDiablo2.Scenes
campfireSprite.Dispose();
headingFont.Dispose();
headingLabel.Dispose();
sfxDictionary.Clear();
}
}
}